From 1e3c7b55cfc91ed80b743daad7517ad3e51b99e1 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 13 Jun 2018 14:03:24 +0200 Subject: [PATCH] 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 --- src/ChangeLog | 7 ++ src/readelf.c | 122 ++++++++++++++---- tests/ChangeLog | 9 ++ tests/Makefile.am | 2 + tests/run-readelf-const-values.sh | 230 ++++++++++++++++++++++++++++++++++ tests/run-readelf-zdebug-rel.sh | 2 +- tests/testfile-const-values.debug.bz2 | Bin 0 -> 1540 bytes 7 files changed, 350 insertions(+), 22 deletions(-) create mode 100755 tests/run-readelf-const-values.sh create mode 100755 tests/testfile-const-values.debug.bz2 diff --git a/src/ChangeLog b/src/ChangeLog index fd45405..5f381cf 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2018-06-13 Mark Wielaard + + * 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 * readelf.c (print_form_data): Don't reuse readp and readendp when diff --git a/src/readelf.c b/src/readelf.c index f185897..c9efd79 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; diff --git a/tests/ChangeLog b/tests/ChangeLog index e5df211..4abbd12 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2018-06-13 Mark Wielaard + + * run-readelf-const-values.sh: New test. + * testfile-const-values.debug.bz2: New test file. + * run-readelf-zdebug-rel.sh: Adjust expected const_value. + * Makefile.am (TESTS): Add run-readelf-const-values.sh. + (EXTRA_DIST): Add run-readelf-const-values.sh and + testfile-const-values.debug.bz2. + 2018-06-08 Mark Wielaard * varlocs.c (print_expr): Error on bad DW_OP_GNU_parameter_ref diff --git a/tests/Makefile.am b/tests/Makefile.am index b45ecdc..2d63da6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -94,6 +94,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \ run-find-prologues.sh run-allregs.sh run-addrcfi.sh \ run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \ + run-readelf-const-values.sh \ run-varlocs-self.sh run-exprlocs-self.sh \ run-readelf-test1.sh run-readelf-test2.sh run-readelf-test3.sh \ run-readelf-test4.sh run-readelf-twofiles.sh \ @@ -199,6 +200,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-ranlib-test3.sh run-ranlib-test4.sh \ run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \ run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \ + run-readelf-const-values.sh testfile-const-values.debug.bz2 \ run-addrcfi.sh \ run-varlocs-self.sh run-exprlocs-self.sh \ run-find-prologues.sh run-allregs.sh run-native-test.sh \ diff --git a/tests/run-readelf-const-values.sh b/tests/run-readelf-const-values.sh new file mode 100755 index 0000000..0a6356f --- /dev/null +++ b/tests/run-readelf-const-values.sh @@ -0,0 +1,230 @@ +#! /bin/sh +# Test for displaying DW_AT_const_types with the "correct" sign. +# Copyright (C) 2018 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +# = s.c +# +# int s() +# { +# int i = -1; +# int j = -1; +# +# return i - j; +# } +# +# = m.c +# +# extern int s(); +# +# int +# main () +# { +# const signed char sc = -2; +# const unsigned char uc = 254; +# +# const signed short ss = -16; +# const unsigned short us = 65520; +# +# const signed int si = -3; +# const unsigned int ui = 4200000000; +# +# signed long sl = -1; +# unsigned long ul = 0xffffffffffffffffUL; +# +# return s (); +# } +# +# gcc -gdwarf-5 -O2 -c s.c +# gcc -gdwarf-4 -O2 -c m.c +# gcc -o testfile-const-values s.o m.o +# eu-strip -g -f testfile-const-values.debug testfile-const-values + +testfiles testfile-const-values.debug + +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info testfile-const-values.debug << EOF + +DWARF section [28] '.debug_info' at offset 0x2e0: + [Offset] + Compilation unit at offset 0: + Version: 5, Abbreviation section offset: 0, Address size: 8, Offset size: 4 + Unit type: compile (1) + [ c] compile_unit abbrev: 2 + producer (strp) "GNU C11 7.3.1 20180303 (Red Hat 7.3.1-5) -mtune=generic -march=x86-64 -gdwarf-5 -O2" + language (data1) C11 (29) + name (string) "s.c" + comp_dir (strp) "/home/mark/build/elfutils-obj" + low_pc (addr) 0x00000000004004d0 + high_pc (data8) 3 (0x00000000004004d3) + stmt_list (sec_offset) 0 + [ 2e] subprogram abbrev: 3 + external (flag_present) yes + name (string) "s" + decl_file (data1) s.c (1) + decl_line (data1) 1 + type (ref4) [ 5e] + low_pc (addr) 0x00000000004004d0 + high_pc (data8) 3 (0x00000000004004d3) + frame_base (exprloc) + [ 0] call_frame_cfa + call_all_calls (flag_present) yes + sibling (ref4) [ 5e] + [ 4d] variable abbrev: 1 + name (string) "i" + decl_file (implicit_const) s.c (1) + decl_line (data1) 3 + type (ref4) [ 5e] + const_value (implicit_const) -1 + [ 55] variable abbrev: 1 + name (string) "j" + decl_file (implicit_const) s.c (1) + decl_line (data1) 4 + type (ref4) [ 5e] + const_value (implicit_const) -1 + [ 5e] base_type abbrev: 4 + byte_size (data1) 4 + encoding (data1) signed (5) + name (string) "int" + Compilation unit at offset 102: + Version: 4, Abbreviation section offset: 73, Address size: 8, Offset size: 4 + [ 71] compile_unit abbrev: 1 + producer (strp) "GNU C11 7.3.1 20180303 (Red Hat 7.3.1-5) -mtune=generic -march=x86-64 -gdwarf-4 -O2" + language (data1) C99 (12) + name (string) "m.c" + comp_dir (strp) "/home/mark/build/elfutils-obj" + ranges (sec_offset) range list [ 0] + low_pc (addr) 000000000000000000 + stmt_list (sec_offset) 54 + [ 8f] subprogram abbrev: 2 + external (flag_present) yes + name (strp) "main" + decl_file (data1) m.c (1) + decl_line (data1) 4 + type (ref4) [ 119] + low_pc (addr) 0x00000000004003e0 + high_pc (data8) 7 (0x00000000004003e7) + frame_base (exprloc) + [ 0] call_frame_cfa + GNU_all_call_sites (flag_present) yes + sibling (ref4) [ 119] + [ b0] variable abbrev: 3 + name (string) "sc" + decl_file (data1) m.c (1) + decl_line (data1) 6 + type (ref4) [ 12c] + const_value (sdata) -2 + [ bb] variable abbrev: 3 + name (string) "uc" + decl_file (data1) m.c (1) + decl_line (data1) 7 + type (ref4) [ 138] + const_value (sdata) 254 (-2) + [ c6] variable abbrev: 3 + name (string) "ss" + decl_file (data1) m.c (1) + decl_line (data1) 9 + type (ref4) [ 144] + const_value (sdata) -16 + [ d1] variable abbrev: 3 + name (string) "us" + decl_file (data1) m.c (1) + decl_line (data1) 10 + type (ref4) [ 150] + const_value (sdata) 65520 (-16) + [ dc] variable abbrev: 3 + name (string) "si" + decl_file (data1) m.c (1) + decl_line (data1) 12 + type (ref4) [ 120] + const_value (sdata) -3 + [ e7] variable abbrev: 3 + name (string) "ui" + decl_file (data1) m.c (1) + decl_line (data1) 13 + type (ref4) [ 15c] + const_value (sdata) 4200000000 (-94967296) + [ f5] variable abbrev: 3 + name (string) "sl" + decl_file (data1) m.c (1) + decl_line (data1) 15 + type (ref4) [ 161] + const_value (sdata) -1 + [ 100] variable abbrev: 3 + name (string) "ul" + decl_file (data1) m.c (1) + decl_line (data1) 16 + type (ref4) [ 168] + const_value (sdata) 18446744073709551615 (-1) + [ 10b] GNU_call_site abbrev: 4 + low_pc (addr) 0x00000000004003e7 + GNU_tail_call (flag_present) yes + abstract_origin (ref4) [ 16f] + [ 119] base_type abbrev: 5 + byte_size (data1) 4 + encoding (data1) signed (5) + name (string) "int" + [ 120] const_type abbrev: 6 + type (ref4) [ 119] + [ 125] base_type abbrev: 7 + byte_size (data1) 1 + encoding (data1) signed_char (6) + name (strp) "signed char" + [ 12c] const_type abbrev: 6 + type (ref4) [ 125] + [ 131] base_type abbrev: 7 + byte_size (data1) 1 + encoding (data1) unsigned_char (8) + name (strp) "unsigned char" + [ 138] const_type abbrev: 6 + type (ref4) [ 131] + [ 13d] base_type abbrev: 7 + byte_size (data1) 2 + encoding (data1) signed (5) + name (strp) "short int" + [ 144] const_type abbrev: 6 + type (ref4) [ 13d] + [ 149] base_type abbrev: 7 + byte_size (data1) 2 + encoding (data1) unsigned (7) + name (strp) "short unsigned int" + [ 150] const_type abbrev: 6 + type (ref4) [ 149] + [ 155] base_type abbrev: 7 + byte_size (data1) 4 + encoding (data1) unsigned (7) + name (strp) "unsigned int" + [ 15c] const_type abbrev: 6 + type (ref4) [ 155] + [ 161] base_type abbrev: 7 + byte_size (data1) 8 + encoding (data1) signed (5) + name (strp) "long int" + [ 168] base_type abbrev: 7 + byte_size (data1) 8 + encoding (data1) unsigned (7) + name (strp) "long unsigned int" + [ 16f] subprogram abbrev: 8 + external (flag_present) yes + declaration (flag_present) yes + linkage_name (string) "s" + name (string) "s" + decl_file (data1) m.c (1) + decl_line (data1) 1 +EOF + +exit 0 diff --git a/tests/run-readelf-zdebug-rel.sh b/tests/run-readelf-zdebug-rel.sh index ccccd82..3f20078 100755 --- a/tests/run-readelf-zdebug-rel.sh +++ b/tests/run-readelf-zdebug-rel.sh @@ -90,7 +90,7 @@ DWARF section [ 4] '.debug_info' at offset 0x58: decl_file (data1) testfile-zdebug-rel.c (1) decl_line (data1) 6 type (ref4) [ 9a] - const_value (sdata) -9 + const_value (sdata) 18446744073709551607 (-9) [ 74] variable abbrev: 6 name (string) "b" decl_file (data1) testfile-zdebug-rel.c (1) diff --git a/tests/testfile-const-values.debug.bz2 b/tests/testfile-const-values.debug.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..167da166e9fcf88bb548c4c8d0455ebae7d0f54c GIT binary patch literal 1540 zcmV+f2K)I!T4*^jL0KkKS;f_Upa2F-|NsC0{r`XG|KI=R_u>El-}~03PR58hY*>*f zSBYxyiFr^3S(81NY?Kz6ETf?lNl(&E28Lv0000Q4FCWJfDHfu8UctTMFhn()WM-9o+uh^Ko3!- znrZ3)2AVWz^#A|>Xah!o4^gAk9-s%PdO!pkG-;zIBPN(b6Ch}5gfR^a34ntmKs01B z0Lh>+G|7`A0x(RC7)=0_(uAk!H9e{Z)YDC<8U}+v8e}qPWY7R;42Fh)0BFzv0MIfI zQKzH;3)}ymgF}4u(RuI~#@L27ng-C#OC`B=(wb`6hsYZv2M6m&+=!W-1%`pwoaf~tKjLF*J%kf~gRso~fXtkuX#*$q8s~T)H z`YI_&Bcy3kmX9qd34Dw}hZ`zL2r0Ta=OO^Yfy>vfZ^1c8?#-uzpQp;~ip4YH5sOmI z)?m$E0<3PCs>dHSdeL!7TB%=D-o`^OyYUx${7a5Yk^1o z{Ho8)8fcRt01bMW3bf3?D|Z2iQxDw2A%Tp*A%Gf;NL)q&Drj65jqT&D!!!ZDW6Xj_ z@S3D0Ye@(F|r!(|)Ds&CZj0l7cDpY@R&uQQXr%KQC|e7`3e z+go7Sii>dFB@MXt8LuVRdQqOlQc#3)2OLZgpp6WW6sa}X>^Pzjb!tZ%1i;YYis%4@ zR2VMMXb_QnofoNpPRhjCy(ZDD%;)mgxu)(jcPlC)cJ{uRWIFwFC9x2m-VbNFx3@M z@~+g)w!O|iSvFkLXSw54GFd{sF}5#tb{GPZsU|dzC$H^25Iv^?T_GM!nGD2DB|RvZ zc#hG1!E0mIVuHw=RfVyoDaGQVm`0iTn(Ct{x-i8m&`KVsb|fA!up}Th_LEMAV0!}M zObKTUfD4q(5^9AhFz~q5suRJ5#K&hSpKxIfi3X=|Q;48%NoDy^JOn_ADc8FgCby7s zSWcfZF)JnFoC7%Avmh&Z8E24PLZpqtxi^RoV{peK8i<7A6w|2^_Yp(UD9n31Kb8`* z@pdl%Vw*ym$SMuq!`y`OGxumbYHY{z4?V~%Vv3*d6xgedc6S3F97}#!brp`Ld6K@!J`n2psE5~ zArVb)gr2zN6oExx4}6ZC@Lm%$4uj2cT_+f9Qmm4uiomM`mF(6l z0}K-d$cd=f&qZrGy5Z!JMWwAaX3bP~z~0)V`RfI$!{VoWGHl_v`tpwQrC0oV)yA$J7o+(S@6 z$bb+AM4)#%gqEfWS|b9XPN1|R=%8&`1O6=Y5J78xu>vv|%ys-GWs)%yrARsHPf_c( q-CRcdoYN*-f3K-6tt;1DzMX2;a$qtigpXi<#oUoj6eKZqU#I|#!>+Ud literal 0 HcmV?d00001 -- 2.7.4