>From 84a1e0b7396b29752f27486ec166b782a56852cb Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 29 Jun 2012 23:38:09 +0200 Subject: [PATCH] readelf: Add .gdb_index version 7 support. Add version 7 support. Keep track of cu_nr. Print kind and static/global flag for each symbol. When a symbol is in the TU list add 'T'. Add testfilegdbindex test files. Signed-off-by: Mark Wielaard --- src/ChangeLog | 6 ++ src/readelf.c | 64 +++++++++++++++----- tests/ChangeLog | 9 +++ tests/Makefile.am | 6 +- tests/run-readelf-gdb_index.sh | 130 ++++++++++++++++++++++++++++++++++++++++ tests/testfilegdbindex5.bz2 | Bin 0 -> 3481 bytes tests/testfilegdbindex7.bz2 | Bin 0 -> 3497 bytes 7 files changed, 197 insertions(+), 18 deletions(-) create mode 100755 tests/run-readelf-gdb_index.sh create mode 100755 tests/testfilegdbindex5.bz2 create mode 100755 tests/testfilegdbindex7.bz2 diff --git a/src/ChangeLog b/src/ChangeLog index 2928ab1..a474bb9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2012-07-10 Mark Wielaard + + * readelf.c (print_gdb_index_section): Add version 7 support. + Keep track of cu_nr. Print kind and static/global flag for each + symbol. When a symbol is in the TU list add 'T'. + 2012-06-26 Mark Wielaard * readelf.c (dwarf_attr_string): Add DW_AT_GNU_macros. diff --git a/src/readelf.c b/src/readelf.c index eb1d469..62b2100 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -7123,7 +7123,7 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, // The only difference between version 4 and version 5 is the // hash used for generating the table. Version 6 contains symbols // for inlined functions, older versions didn't. - if (vers < 4 || vers > 6) + if (vers < 4 || vers > 7) { printf (gettext (" unknown version, cannot parse section\n")); return; @@ -7167,14 +7167,14 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, readp = data->d_buf + cu_off; const unsigned char *nextp = data->d_buf + tu_off; - size_t nr = (nextp - readp) / 16; + size_t cu_nr = (nextp - readp) / 16; printf (gettext ("\n CU list at offset %#" PRIx32 " contains %zu entries:\n"), - cu_off, nr); + cu_off, cu_nr); size_t n = 0; - while (readp + 16 <= dataend && n < nr) + while (readp + 16 <= dataend && n < cu_nr) { uint64_t off = read_8ubyte_unaligned (dbg, readp); readp += 8; @@ -7189,14 +7189,14 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, readp = data->d_buf + tu_off; nextp = data->d_buf + addr_off; - nr = (nextp - readp) / 24; + size_t tu_nr = (nextp - readp) / 24; printf (gettext ("\n TU list at offset %#" PRIx32 " contains %zu entries:\n"), - tu_off, nr); + tu_off, tu_nr); n = 0; - while (readp + 24 <= dataend && n < nr) + while (readp + 24 <= dataend && n < tu_nr) { uint64_t off = read_8ubyte_unaligned (dbg, readp); readp += 8; @@ -7215,14 +7215,14 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, readp = data->d_buf + addr_off; nextp = data->d_buf + sym_off; - nr = (nextp - readp) / 20; + size_t addr_nr = (nextp - readp) / 20; printf (gettext ("\n Address list at offset %#" PRIx32 " contains %zu entries:\n"), - addr_off, nr); + addr_off, addr_nr); n = 0; - while (readp + 20 <= dataend && n < nr) + while (readp + 20 <= dataend && n < addr_nr) { uint64_t low = read_8ubyte_unaligned (dbg, readp); readp += 8; @@ -7242,14 +7242,14 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, readp = data->d_buf + sym_off; nextp = data->d_buf + const_off; - nr = (nextp - readp) / 8; + size_t sym_nr = (nextp - readp) / 8; printf (gettext ("\n Symbol table at offset %#" PRIx32 " contains %zu slots:\n"), - addr_off, nr); + addr_off, sym_nr); n = 0; - while (readp + 8 <= dataend && n < nr) + while (readp + 8 <= dataend && n < sym_nr) { uint32_t name = read_4ubyte_unaligned (dbg, readp); readp += 4; @@ -7272,10 +7272,42 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, uint32_t cus = read_4ubyte_unaligned (dbg, readcus); while (cus--) { - uint32_t cu; + uint32_t cu_kind, cu, kind; + bool is_static; readcus += 4; - cu = read_4ubyte_unaligned (dbg, readcus); - printf ("%" PRId32 "%s", cu, ((cus > 0) ? ", " : "")); + cu_kind = read_4ubyte_unaligned (dbg, readcus); + cu = cu_kind & ((1 << 24) - 1); + kind = (cu_kind >> 28) & 7; + is_static = cu_kind & (1 << 31); + if (cu > cu_nr - 1) + printf ("%" PRId32 "T", cu - (uint32_t) cu_nr); + else + printf ("%" PRId32, cu); + if (kind != 0) + { + printf (" ("); + switch (kind) + { + case 1: + printf ("type"); + break; + case 2: + printf ("var"); + break; + case 3: + printf ("func"); + break; + case 4: + printf ("other"); + break; + default: + printf ("unknown-0x%" PRIx32, kind); + break; + } + printf (":%c)", (is_static ? 'S' : 'G')); + } + if (cus > 0) + printf (", "); } printf ("\n"); } diff --git a/tests/ChangeLog b/tests/ChangeLog index 9b64917..9cc13c5 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2012-06-27 Mark Wielaard + + * run-readelf-gdb-index.sh: New test. + * testfilegdbindex5.bz2: New testfile. + * testfilegdbindex7.bz2: Likewise. + * Makefile.am (TESTS): Add run-readelf-gdb-index.sh. + (EXTRA_DIST): run-readelf-gdb_index.sh, testfilegdbindex5.bz2 and + testfilegdbindex7.bz2. + 2012-06-26 Mark Wielaard * run-macro-test.sh: New test. diff --git a/tests/Makefile.am b/tests/Makefile.am index 39e58ae..4d7fa22 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -79,8 +79,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-early-offscn.sh run-dwarf-getmacros.sh \ run-test-flag-nobits.sh run-prelink-addr-test.sh \ run-dwarf-getstring.sh run-rerequest_tag.sh run-typeiter.sh \ - run-readelf-d.sh run-unstrip-n.sh run-low_high_pc.sh \ - run-macro-test.sh + run-readelf-d.sh run-readelf-gdb_index.sh run-unstrip-n.sh \ + run-low_high_pc.sh run-macro-test.sh if !STANDALONE noinst_PROGRAMS += msg_tst md5-sha1-test @@ -157,6 +157,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile56.bz2 testfile57.bz2 testfile58.bz2 \ run-typeiter.sh testfile59.bz2 \ run-readelf-d.sh testlib_dynseg.so.bz2 \ + run-readelf-gdb_index.sh testfilegdbindex5.bz2 \ + testfilegdbindex7.bz2 \ run-unstrip-n.sh testcore-rtlib.bz2 \ run-low_high_pc.sh testfile_low_high_pc.bz2 \ run-macro-test.sh testfile-macinfo.bz2 testfile-macros.bz2 diff --git a/tests/run-readelf-gdb_index.sh b/tests/run-readelf-gdb_index.sh new file mode 100755 index 0000000..31c94c1 --- /dev/null +++ b/tests/run-readelf-gdb_index.sh @@ -0,0 +1,130 @@ +#! /bin/sh +# Copyright (C) 2012 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 + +# common.h +# struct foo +# { +# const char *bar; +# }; +# +# extern char *global; +# int say (struct foo *prefix); + +# hello.c +# #include "common.h" +# +# static char *hello = "Hello"; +# +# int +# main (int argc, char **argv) +# { +# struct foo baz; +# global = hello; +# baz.bar = global; +# return say(&baz); +# } + +# world.c +# #include "common.h" +# +# char *global; +# +# static int hello (const char *bar) +# { +# return bar == global; +# } +# +# int +# say (struct foo *prefix) +# { +# return hello (prefix->bar); +# } + +# gcc -g -fdebug-types-section -c hello.c +# gcc -g -fdebug-types-section -c world.c +# gcc -g -fdebug-types-section -o testfilegdbindex7 hello.o world.o +# gdb testfilegdbindex7 +# (gdb) save gdb-index . +# objcopy --add-section .gdb_index=testfilegdbindex7.gdb-index --set-section-flags .gdb_index=readonly testfilegdbindex7 testfilegdbindex7 + +testfiles testfilegdbindex5 testfilegdbindex7 + +testrun_compare ../src/readelf --debug-dump=gdb_index testfilegdbindex5 <<\EOF + +GDB section [33] '.gdb_index' at offset 0xe76 contains 8383 bytes : + Version: 5 + CU offset: 0x18 + TU offset: 0x38 + address offset: 0x50 + symbol offset: 0x78 + constant offset: 0x2078 + + CU list at offset 0x18 contains 2 entries: + [ 0] start: 00000000, length: 184 + [ 1] start: 0x0000b8, length: 204 + + TU list at offset 0x38 contains 1 entries: + [ 0] CU offset: 0, type offset: 29, signature: 0x87e03f92cc37cdf0 + + Address list at offset 0x50 contains 2 entries: + [ 0] 0x000000000040049c
..0x00000000004004d1 , CU index: 0 + [ 1] 0x00000000004004d4 ..0x000000000040050b , CU index: 1 + + Symbol table at offset 0x50 contains 1024 slots: + [ 123] symbol: global, CUs: 1 + [ 489] symbol: main, CUs: 0 + [ 518] symbol: char, CUs: 0 + [ 661] symbol: foo, CUs: 0T + [ 741] symbol: hello, CUs: 0, 1 + [ 746] symbol: say, CUs: 1 + [ 754] symbol: int, CUs: 0 +EOF + +testrun_compare ../src/readelf --debug-dump=gdb_index testfilegdbindex7 <<\EOF + +GDB section [33] '.gdb_index' at offset 0xe76 contains 8399 bytes : + Version: 7 + CU offset: 0x18 + TU offset: 0x38 + address offset: 0x50 + symbol offset: 0x78 + constant offset: 0x2078 + + CU list at offset 0x18 contains 2 entries: + [ 0] start: 00000000, length: 184 + [ 1] start: 0x0000b8, length: 204 + + TU list at offset 0x38 contains 1 entries: + [ 0] CU offset: 0, type offset: 29, signature: 0x87e03f92cc37cdf0 + + Address list at offset 0x50 contains 2 entries: + [ 0] 0x000000000040049c
..0x00000000004004d1 , CU index: 0 + [ 1] 0x00000000004004d4 ..0x000000000040050b , CU index: 1 + + Symbol table at offset 0x50 contains 1024 slots: + [ 123] symbol: global, CUs: 1 (var:G) + [ 489] symbol: main, CUs: 0 (func:G) + [ 518] symbol: char, CUs: 0 (type:S) + [ 661] symbol: foo, CUs: 0T (type:S) + [ 741] symbol: hello, CUs: 0 (var:S), 1 (func:S) + [ 746] symbol: say, CUs: 1 (func:G) + [ 754] symbol: int, CUs: 0 (type:S) +EOF + +exit 0 diff --git a/tests/testfilegdbindex5.bz2 b/tests/testfilegdbindex5.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..45ee945a2af4562f22be666e906c045f658bb0fc GIT binary patch literal 3481 zcmV;K4QBE}T4*^jL0KkKS-0A9v;YjhfB*mg|NsC0|NsC0|L_0*|Nqbb_4a3S)qMZ= zci-24|9jvJ53uXr^t}LgcbxBS?)C1BD%YJI*m}pD4Y5vzJK>>C0txA&XwwkNpP-p1 zf`{r)X%Xo?L9%I-JfQTOQR+QUQ1v{M)Y^@y>UxHZnW^bLKxleR9;S~$sM?JNfIUa3 z0imWr>K;(^jDev9Gy(+L5ilm0)ili$1k=>ofb|VD(?);;Kn9us(VzeWKmZy5&;Zah z000Jn44$SzsisM!PgKdZ9+TAcpQ>mw8UdgH0000Q03M(K02%<$0000Q00Tg100001 zpaiB-1SW+Zf;9Cs^$$q(9*}t>%3=nOPz^K#KmY&+gVfMy4FG5~0B8e1000008UO$U z27mwn0002c00E!?01Sf=001%oGynrkjRPPUO#lD@Xvv@e4FriIX);WkO;c>9Os1Ge zrjtxTqfHGmG&E_D01r{>X`zs5pvVBk05k?eO#lD@0imD(01W`Zn8LD6Qj(5GF*DN~ zFAcuXZN}>X9eyu$uqM!!HLjklrw}2V2!kDV;SsBQIVf#|XezN6j8bYKfu|;@jb<5S zS_`#EJ#rsKn2?O%P32G+Vc$gn(MXrK&5r%hs&dSr5#luj`~LWk=3qTN)0ph5;q^rj zxP)BcTWP@8JSSL!sug36Y&Bw2Re_3?rAxsbimL}nsHQ|}W2jSbt`H;m^`kK5;bzxv zRt>>(L=Z@iUOzb9uKh*4(A*Ga0n}O&fti_+0tCj8K^fN{+RW13uEDX(%F?1TzvwkS z5=uCA$Vw0=77=P`p_nbO4_puep#hI$8Iau~8QC?d0+y@0c5<35c;egcUH#4a&*&2yPi(m|f zzcBzq9?Whc#0%Xr1)ymy<%we&1C-6~GRI^0HuJK}GWD80N1H1+T3t20vMjL#GVUh$ ziUb^%{8@GgF6{QbTVz0h=nN475=7ohy2<~Y`TgkduI(*(WO$uJD=V;vwcT8yqeZ#0qYAQlsJO${q+Hn0<>+HL@^6K(16d32@FY%8NuPx0H9$o!CxjMF{G2Ygd$9a z07z>x!4(0umw+M|+i-;h5HX{`Vgg}+k)UQV&cHOq1ORLr1AAwN(m~m=BBMZ4U|KY& zVh}?BFX|epB_b3g2-PxnBH5sZ3#efY17g^)QGtCb`}7?Nh=8Gj2GP>6)5-+827@3R zDue~QLY<(*(8nf1a!6FzM9`|l7fk_lw?o_6V6hJ1E1~j2EoXqD!b*QEbP8vi< zw?T$wNVr3}-f$qqH0^R^jH%RVnkK84-(xTyZ(85rG}coB6L3}pGNMDaAW3Ppg*GF` zB1$@P#aDN$ElB*=DKqfEmtSekQ(k@46sBxNDHo!qkp42Ti< zk?AQuy3kmM4fdO&m@kH-EpWJALUc<}L!Cl^j2Ytt#TW*g#lvNcu+T{zQirvfjI_zD zNYYsg5i)tf!4XyN0W6ZGoTluyCh$sdj8#;Uv7PgC1!5FXLsX+HreQ^ljDesqVlk4( z<6b)wE#^cj_R8y(S)=%SA6K`5$@D6+zMCA_?t&u+SY&|Eunl|(WfMsl1IeQra4Sqq zETcxB?TQAl%~cw+3N5a!14aS|2n+-e&&|dajxf;TU2hdySZdM(MV26#NHA{vRf8kX zz36y4oOnT?L37~DOicvNFhEe50V%9#%m0(wT%<2VXPDn~|g|^mWq>(Tplt6;a6sN8+9Fk0vEmJA2 zv-IlTuJg}1&2waUhQDfr177B0Z34O?x+F=gCIqk{PBDDCo?o@M!rA@*gfrz$k09a9 z(c>y8xA64;MqJ57F5rcX?uxkSH330!`V}@Jet-V!LYW0cunP zoT0KD+$iAJmLtQkWDpaU(oi%-o3M=a<%+YdpeeyC)~}pX5tMWpS+6hbOZ*6SfeN+juSn}E1BO=SiUkDj-T(&2KV%Gc&@{Hl!n@y4_p5h*82 zQKlaVz77sIgkmh@l*A~dxVq%_G^ntC)-L2Jlq!c% zuEgyQ%7S-C1#XIQ z$?8bEH_I48omjh)LN{?4cyb&$4W!|up1C2DCMSa?pr0j1NtKm>qP^)Ch_H*A!EtvJ z5L2a4a4KRZsiInRPF++O!li|MNWDdR+|4RTWf(Pfl%Y<-@x=D54Ma+)AP*sSW}xJP zvW}=gGg+#^Mox)NbfckYC9V+(s8=!!15(ylh@S|eGOk5ITP8Z9j0i!CF@j)~$Qbzt z2vZO};Ksn0O_m4(vlKZRZL zscc`atzs48go+|6gd-M%hHAKUByhzRA(f*@y(C+SS*m2Ecn%T-?#5QDpqeE#5tAt# zP}yh^jSAiM?cH0+;gzUYq?M8(7?S?TVT$8waH>1fpiVBsuWu&4JAoB&sH^7e2`N=e zrHmbJvH}hPlz~u}ur@=KF8!fra!X>?31I>P5($hsV3G(z?vyWYRv?AoVx9D&Cd@=K zgbvl*4VrMpnO&ZKqMaxPVDwZU1zKXlzo}?i11Cc-tk@BPItuWMix)NSizOhWJ6CHx zt?3Kp#)Fjw>a{(KGP%^))l0#$O$gMh}l`0gFBQ3ZVUjhOG}sz zutdR`CEkro6t}anC1n`K0nA(^J^&3e{80amT(3u2=%X>)Z4_7SlEc~?Nc3R^BAyG~ z=@}5%914Kd)bx)#ztYD907$r1wCod{{zZ7|qx0;)U71*>cg35uo(gB_mI*-P92ZO z;sGsigG`Y7s)=q3R!Kp~s0-`|NQtC-t&PLYtt^;`>-Z1$tt|n(p`~L@AL8yvrwS4l H`%YGX9{)R@ literal 0 HcmV?d00001 diff --git a/tests/testfilegdbindex7.bz2 b/tests/testfilegdbindex7.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..2a7c6c2cee11136f76787cfa6e8e612550f72dcd GIT binary patch literal 3497 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 XP#qVq=L(7{zxcb7DZ+$