diff options
| -rw-r--r-- | libdw/ChangeLog | 6 | ||||
| -rw-r--r-- | libdw/libdwP.h | 36 | ||||
| -rw-r--r-- | libdw/libdw_form.c | 32 |
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; |
