summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2018-06-13 14:03:24 +0200
committerMark Wielaard <[email protected]>2018-06-15 23:48:26 +0200
commit1e3c7b55cfc91ed80b743daad7517ad3e51b99e1 (patch)
tree08ec91de1667c60731b8a3b2b61f16ad77a31a9f /src
parent7a1fd63a74e456f0ad9ab954bc381050e702eeb6 (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/ChangeLog7
-rw-r--r--src/readelf.c122
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;