From: Aaron Merey Date: Tue, 31 Oct 2023 20:00:27 +0000 (-0400) Subject: readelf: Support .gdb_index version 9 X-Git-Tag: elfutils-0.190~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e0572989b33b7e4319d42628fad782fa97825646;p=thirdparty%2Felfutils.git readelf: Support .gdb_index version 9 Version 9 adds a "shortcut table" to the index. The shortcut table contains the name and language of the main function, if it exists. A testcase added in this patch uses an executable written with Fortran. This is because gdb does not currently populate the shortcut table of C/C++ programs (see sourceware PR30996). Signed-off-by: Aaron Merey --- diff --git a/src/readelf.c b/src/readelf.c index db31ad09d..decfaf155 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -11539,8 +11539,9 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, // hash used for generating the table. Version 6 contains symbols // for inlined functions, older versions didn't. Version 7 adds // symbol kinds. Version 8 just indicates that it correctly includes - // TUs for symbols. - if (vers < 4 || vers > 8) + // TUs for symbols. Version 9 adds shortcut table for information + // regarding the main function. + if (vers < 4 || vers > 9) { printf (_(" unknown version, cannot parse section\n")); return; @@ -11578,6 +11579,17 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, if (unlikely (readp + 4 > dataend)) goto invalid_data; + uint32_t shortcut_off = 0; + if (vers >= 9) + { + shortcut_off = read_4ubyte_unaligned (dbg, readp); + printf (_(" shortcut offset: %#" PRIx32 "\n"), shortcut_off); + + readp += 4; + if (unlikely (readp + 4 > dataend)) + goto invalid_data; + } + uint32_t const_off = read_4ubyte_unaligned (dbg, readp); printf (_(" constant offset: %#" PRIx32 "\n"), const_off); @@ -11675,8 +11687,19 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, if (const_off >= data->d_size) goto invalid_data; + const unsigned char *shortcut_start = NULL; + if (vers >= 9) + { + if (shortcut_off >= data->d_size) + goto invalid_data; + + shortcut_start = data->d_buf + shortcut_off; + nextp = shortcut_start; + } + else + nextp = const_start; + readp = data->d_buf + sym_off; - nextp = const_start; size_t sym_nr = (nextp - readp) / 8; printf (_("\n Symbol table at offset %#" PRIx32 @@ -11750,6 +11773,49 @@ print_gdb_index_section (Dwfl_Module *dwflmod, Ebl *ebl, } n++; } + + if (vers < 9) + return; + + if (unlikely (shortcut_start == NULL)) + goto invalid_data; + + readp = shortcut_start; + nextp = const_start; + size_t shortcut_nr = (nextp - readp) / 4; + + if (unlikely (shortcut_nr != 2)) + goto invalid_data; + + printf (_("\nShortcut table at offset %#" PRIx32 " contains %zu slots:\n"), + shortcut_off, shortcut_nr); + + uint32_t lang = read_4ubyte_unaligned (dbg, readp); + readp += 4; + + /* Include the hex number of LANG in the output if the language + is unknown. */ + const char *lang_str = dwarf_lang_string (lang); + lang_str = string_or_unknown (lang_str, lang, DW_LANG_lo_user, + DW_LANG_hi_user, true); + + printf (_("Language of main: %s\n"), lang_str); + printf (_("Name of main: ")); + + if (lang != 0) + { + uint32_t name = read_4ubyte_unaligned (dbg, readp); + readp += 4; + const unsigned char *sym = const_start + name; + + if (unlikely ((size_t) (dataend - const_start) < name + || memchr (sym, '\0', dataend - sym) == NULL)) + goto invalid_data; + + printf ("%s\n", sym); + } + else + printf ("\n"); } /* Returns true and sets split DWARF CU id if there is a split compile diff --git a/tests/Makefile.am b/tests/Makefile.am index d0ae7c6d3..7fb8efb13 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -419,7 +419,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-readelf-Dd.sh \ testfile-s390x-hash-both.bz2 \ run-readelf-gdb_index.sh testfilegdbindex5.bz2 \ - testfilegdbindex7.bz2 \ + testfilegdbindex7.bz2 testfilegdbindex9.bz2 \ + testfilegdbindex9-no-maininfo.bz2 \ run-readelf-s.sh testfilebazdbg.bz2 testfilebazdyn.bz2 \ testfilebazmin.bz2 testfilebazdbg.debug.bz2 testfilebazmdb.bz2 \ testfilebaztab.bz2 testfilebasmin.bz2 testfilebaxmin.bz2 \ diff --git a/tests/run-readelf-gdb_index.sh b/tests/run-readelf-gdb_index.sh index fcbc3c571..cd437f523 100755 --- a/tests/run-readelf-gdb_index.sh +++ b/tests/run-readelf-gdb_index.sh @@ -63,7 +63,7 @@ # (gdb) save gdb-index . # objcopy --add-section .gdb_index=testfilegdbindex7.gdb-index --set-section-flags .gdb_index=readonly testfilegdbindex7 testfilegdbindex7 -testfiles testfilegdbindex5 testfilegdbindex7 +testfiles testfilegdbindex5 testfilegdbindex7 testfilegdbindex9 testfilegdbindex9-no-maininfo testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=gdb_index testfilegdbindex5 <<\EOF @@ -127,4 +127,97 @@ GDB section [33] '.gdb_index' at offset 0xe76 contains 8399 bytes : [ 754] symbol: int, CUs: 0 (type:S) EOF +# testfilegdbindex9-no-maininfo is built the same way as testfilegdbindex7. +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=gdb_index testfilegdbindex9-no-maininfo <<\EOF + +GDB section [33] '.gdb_index' at offset 0x38e1 contains 8415 bytes : + Version: 9 + CU offset: 0x1c + TU offset: 0x3c + address offset: 0x54 + symbol offset: 0x7c + shortcut offset: 0x207c + constant offset: 0x2084 + + CU list at offset 0x1c contains 2 entries: + [ 0] start: 0x00004c, length: 220 + [ 1] start: 0x000128, length: 214 + + TU list at offset 0x3c contains 1 entries: + [ 0] CU offset: 0, type offset: 30, signature: 0x87e03f92cc37cdf0 + + Address list at offset 0x54 contains 2 entries: + [ 0] 0x0000000000401106
..0x000000000040113b , CU index: 1 + [ 1] 0x000000000040113c ..0x0000000000401173 , CU index: 2 + + Symbol table at offset 0x54 contains 1024 slots: + [ 123] symbol: global, CUs: 1 (var:G), 0T (var:G) + [ 489] symbol: main, CUs: 1 (func:G) + [ 518] symbol: char, CUs: 0 (type:S) + [ 661] symbol: foo, CUs: 0 (type:S) + [ 741] symbol: hello, CUs: 1 (var:S), 0T (func:S) + [ 746] symbol: say, CUs: 0T (func:G) + [ 754] symbol: int, CUs: 1 (type:S) + +Shortcut table at offset 0x207c contains 2 slots: +Language of main: ??? (0) +Name of main: +EOF + +# testfilegdbindex9.f90 +# +# program repro +# type small_stride +# character*40 long_string +# integer small_pad +# end type small_stride +# type(small_stride), dimension (20), target :: unpleasant +# character*40, pointer, dimension(:):: c40pt +# integer i +# do i = 0,19 +# unpleasant(i+1)%small_pad = i+1 +# unpleasant(i+1)%long_string = char (ichar('0') + i) +# end do +# c40pt => unpleasant%long_string +# print *, c40pt +#end program repro + +# gfortran -g -o testfilegdbindex9 testfilegdbindex9.f90 +# gdb-add-index testfilegdbindex9 + +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=gdb_index testfilegdbindex9 <<\EOF + +GDB section [35] '.gdb_index' at offset 0x37d9 contains 8395 bytes : + Version: 9 + CU offset: 0x1c + TU offset: 0x2c + address offset: 0x2c + symbol offset: 0x40 + shortcut offset: 0x2040 + constant offset: 0x2048 + + CU list at offset 0x1c contains 1 entries: + [ 0] start: 00000000, length: 307 + + TU list at offset 0x2c contains 0 entries: + + Address list at offset 0x2c contains 1 entries: + [ 0] 0x0000000000401166 ..0x00000000004013f0 , CU index: 0 + + Symbol table at offset 0x2c contains 1024 slots: + [ 61] symbol: small_stride, CUs: 0 (type:S) + [ 71] symbol: integer(kind=8), CUs: 0 (type:S) + [ 161] symbol: character(kind=1), CUs: 0 (type:S) + [ 397] symbol: unpleasant, CUs: 0 (var:S) + [ 489] symbol: main, CUs: 0 (func:G) + [ 827] symbol: integer(kind=4), CUs: 0 (type:S) + [ 858] symbol: c40pt, CUs: 0 (var:S) + [ 965] symbol: repro, CUs: 0 (func:S) + [1016] symbol: i, CUs: 0 (var:S) + +Shortcut table at offset 0x2040 contains 2 slots: +Language of main: Fortran08 +Name of main: repro +EOF + exit 0 diff --git a/tests/testfilegdbindex9-no-maininfo.bz2 b/tests/testfilegdbindex9-no-maininfo.bz2 new file mode 100755 index 000000000..043b8d38d Binary files /dev/null and b/tests/testfilegdbindex9-no-maininfo.bz2 differ diff --git a/tests/testfilegdbindex9.bz2 b/tests/testfilegdbindex9.bz2 new file mode 100755 index 000000000..9a2c18931 Binary files /dev/null and b/tests/testfilegdbindex9.bz2 differ