summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdw/ChangeLog6
-rw-r--r--libdw/libdwP.h36
-rw-r--r--libdw/libdw_form.c32
3 files changed, 43 insertions, 31 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 79bb4b57..a2e4b142 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-09 Josh Stone <[email protected]>
+
+ * libdw_form.c (__libdw_form_val_compute_len): Renamed function from
+ __libdw_form_val_len, now handling only non-constant form lengths.
+ * libdwP.h (__libdw_form_val_len): New inlined function.
+
2013-12-09 Mark Wielaard <[email protected]>
* dwarf_getlocation.c (__libdw_intern_expression): Handle empty
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 35ab6e79..49392005 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -34,6 +34,7 @@
#include <stdbool.h>
#include <libdw.h>
+#include <dwarf.h>
/* gettext helper macros. */
@@ -403,11 +404,40 @@ extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
__nonnull_attribute__ (1) internal_function;
/* Helper functions for form handling. */
-extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
- unsigned int form,
- const unsigned char *valp)
+extern size_t __libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
+ unsigned int form,
+ const unsigned char *valp)
__nonnull_attribute__ (1, 2, 4) internal_function;
+/* Find the length of a form attribute. */
+static inline size_t
+__nonnull_attribute__ (1, 2, 4)
+__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
+ unsigned int form, const unsigned char *valp)
+{
+ /* Small lookup table of forms with fixed lengths. Absent indexes are
+ initialized 0, so any truly desired 0 is set to 0x80 and masked. */
+ static const uint8_t form_lengths[] =
+ {
+ [DW_FORM_flag_present] = 0x80,
+ [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1, [DW_FORM_flag] = 1,
+ [DW_FORM_data2] = 2, [DW_FORM_ref2] = 2,
+ [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4,
+ [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sig8] = 8,
+ };
+
+ /* Return immediately for forms with fixed lengths. */
+ if (form < sizeof form_lengths / sizeof form_lengths[0])
+ {
+ uint8_t len = form_lengths[form];
+ if (len != 0)
+ return len & 0x7f; /* Mask to allow 0x80 -> 0. */
+ }
+
+ /* Other forms require some computation. */
+ return __libdw_form_val_compute_len (dbg, cu, form, valp);
+}
+
/* Helper function for DW_FORM_ref* handling. */
extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
__nonnull_attribute__ (1, 2) internal_function;
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index c476a6e3..53505564 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -39,13 +39,15 @@
size_t
internal_function
-__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
- const unsigned char *valp)
+__libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
+ unsigned int form, const unsigned char *valp)
{
const unsigned char *saved;
Dwarf_Word u128;
size_t result;
+ /* NB: This doesn't cover constant form lengths, which are
+ already handled by the inlined __libdw_form_val_len. */
switch (form)
{
case DW_FORM_addr:
@@ -82,32 +84,6 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
result = u128 + (valp - saved);
break;
- case DW_FORM_flag_present:
- result = 0;
- break;
-
- case DW_FORM_ref1:
- case DW_FORM_data1:
- case DW_FORM_flag:
- result = 1;
- break;
-
- case DW_FORM_data2:
- case DW_FORM_ref2:
- result = 2;
- break;
-
- case DW_FORM_data4:
- case DW_FORM_ref4:
- result = 4;
- break;
-
- case DW_FORM_data8:
- case DW_FORM_ref8:
- case DW_FORM_ref_sig8:
- result = 8;
- break;
-
case DW_FORM_string:
result = strlen ((char *) valp) + 1;
break;