diff options
| author | Mark Wielaard <[email protected]> | 2018-06-13 14:03:24 +0200 |
|---|---|---|
| committer | Mark Wielaard <[email protected]> | 2018-06-15 23:48:26 +0200 |
| commit | 1e3c7b55cfc91ed80b743daad7517ad3e51b99e1 (patch) | |
| tree | 08ec91de1667c60731b8a3b2b61f16ad77a31a9f /src | |
| parent | 7a1fd63a74e456f0ad9ab954bc381050e702eeb6 (diff) | |
readelf: Handle signedness of DW_FORM_implicit_const and DW_AT_const_value.
We only handles DW_FORM_sdata as a signed form, but DW_FORM_implicit_const
is also signed by default. For DW_AT_const_value we can do a little better.
GCC encodes some const_values with signed forms, even though the type
is unsigned. Lookup the (base) type of the DIE and display the const value
as their (signed) type/size (if we can determine that).
Add a new testcase run-readelf-const-values.sh that shows that.
With the new testcase the const values would come out as follows:
name (string) "i"
const_value (implicit_const) 18446744073709551615
name (string) "j"
const_value (implicit_const) 18446744073709551615
name (string) "sc"
const_value (sdata) -2
name (string) "uc"
const_value (sdata) -2
name (string) "ss"
const_value (sdata) -16
name (string) "us"
const_value (sdata) -16
name (string) "si"
const_value (sdata) -3
name (string) "ui"
const_value (sdata) -94967296
name (string) "sl"
const_value (sdata) -1
name (string) "ul"
const_value (sdata) -1
With this patch they show up as:
name (string) "i"
const_value (implicit_const) -1
name (string) "j"
const_value (implicit_const) -1
name (string) "sc"
const_value (sdata) -2
name (string) "uc"
const_value (sdata) 254 (-2)
name (string) "ss"
const_value (sdata) -16
name (string) "us"
const_value (sdata) 65520 (-16)
name (string) "si"
const_value (sdata) -3
name (string) "ui"
const_value (sdata) 4200000000 (-94967296)
name (string) "sl"
const_value (sdata) -1
name (string) "ul"
const_value (sdata) 18446744073709551615 (-1)
(for signed/unsigned int char, short and long)
Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 7 | ||||
| -rw-r--r-- | src/readelf.c | 122 |
2 files changed, 108 insertions, 21 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index fd45405f..5f381cf8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2018-06-13 Mark Wielaard <[email protected]> + + * readelf.c (die_type_sign_bytes): New function. + (attr_callback): Recognized DW_FORM_implicit_cost as signed. Use + die_type_sign_bytes to lookup the signedness and size of const + values. + 2018-06-11 Mark Wielaard <[email protected]> * readelf.c (print_form_data): Don't reuse readp and readendp when diff --git a/src/readelf.c b/src/readelf.c index f1858971..c9efd795 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -6869,6 +6869,33 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } +/* Returns the signedness (or false if it cannot be determined) and + the byte size (or zero if it cannot be gotten) of the given DIE + DW_AT_type attribute. Uses dwarf_peel_type and dwarf_aggregate_size. */ +static void +die_type_sign_bytes (Dwarf_Die *die, bool *is_signed, int *bytes) +{ + Dwarf_Attribute attr; + Dwarf_Die type; + + *bytes = 0; + *is_signed = false; + + if (dwarf_peel_type (dwarf_formref_die (dwarf_attr_integrate (die, + DW_AT_type, + &attr), &type), + &type) == 0) + { + Dwarf_Word val; + *is_signed = (dwarf_formudata (dwarf_attr (&type, DW_AT_encoding, + &attr), &val) == 0 + && (val == DW_ATE_signed || val == DW_ATE_signed_char)); + + if (dwarf_aggregate_size (&type, &val) == 0) + *bytes = val; + } +} + struct attrcb_args { Dwfl_Module *dwflmod; @@ -7300,36 +7327,89 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) } else { - Dwarf_Sword snum = 0; - if (form == DW_FORM_sdata) - if (unlikely (dwarf_formsdata (attrp, &snum) != 0)) - goto attrval_out; - if (as_hex_id) { printf (" %*s%-20s (%s) 0x%.16" PRIx64 "\n", (int) (level * 2), "", dwarf_attr_name (attr), dwarf_form_name (form), num); } - else if (valuestr == NULL) - { - printf (" %*s%-20s (%s)", - (int) (level * 2), "", dwarf_attr_name (attr), - dwarf_form_name (form)); - if (form == DW_FORM_sdata) - printf (" %" PRIdMAX "\n", (intmax_t) snum); - else - printf (" %" PRIuMAX "\n", (uintmax_t) num); - } else { - printf (" %*s%-20s (%s) %s", - (int) (level * 2), "", dwarf_attr_name (attr), - dwarf_form_name (form), valuestr); - if (form == DW_FORM_sdata) - printf (" (%" PRIdMAX ")\n", (intmax_t) snum); + Dwarf_Sword snum = 0; + bool is_signed; + int bytes = 0; + if (attr == DW_AT_const_value) + die_type_sign_bytes (cbargs->die, &is_signed, &bytes); + else + is_signed = (form == DW_FORM_sdata + || form == DW_FORM_implicit_const); + + if (is_signed) + if (unlikely (dwarf_formsdata (attrp, &snum) != 0)) + goto attrval_out; + + if (valuestr == NULL) + { + printf (" %*s%-20s (%s) ", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form)); + } + else + { + printf (" %*s%-20s (%s) %s (", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), valuestr); + } + + switch (bytes) + { + case 1: + if (is_signed) + printf ("%" PRId8, (int8_t) snum); + else + printf ("%" PRIu8, (uint8_t) num); + break; + + case 2: + if (is_signed) + printf ("%" PRId16, (int16_t) snum); + else + printf ("%" PRIu16, (uint16_t) num); + break; + + case 4: + if (is_signed) + printf ("%" PRId32, (int32_t) snum); + else + printf ("%" PRIu32, (uint32_t) num); + break; + + case 8: + if (is_signed) + printf ("%" PRId64, (int64_t) snum); + else + printf ("%" PRIu64, (uint64_t) num); + break; + + default: + if (is_signed) + printf ("%" PRIdMAX, (intmax_t) snum); + else + printf ("%" PRIuMAX, (uintmax_t) num); + break; + } + + /* Make clear if we switched from a signed encoding to + an unsigned value. */ + if (attr == DW_AT_const_value + && (form == DW_FORM_sdata || form == DW_FORM_implicit_const) + && !is_signed) + printf (" (%" PRIdMAX ")", (intmax_t) num); + + if (valuestr == NULL) + printf ("\n"); else - printf (" (%" PRIuMAX ")\n", (uintmax_t) num); + printf (")\n"); } } break; |
