diff options
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/readelf.c | 213 | ||||
| -rw-r--r-- | tests/ChangeLog | 6 | ||||
| -rw-r--r-- | tests/Makefile.am | 4 | ||||
| -rwxr-xr-x | tests/run-readelf-str.sh | 211 |
5 files changed, 440 insertions, 3 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 01ecc610..545fb503 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2018-04-29 Mark Wielaard <[email protected]> + + * readelf.c (parse_opt): Request implicit section_info for "str". + (known_stroffbases): New static variable. + (attr_callbackattr_callback): Handle DW_AT_str_offets_base. + (print_debug_str_offsets_section): New function. + (print_debug): Handle .debug_str_offsets as section_str. Reset + known_stroffbases. + 2018-04-27 Mark Wielaard <[email protected]> * readelf.c (options): Add addr. diff --git a/src/readelf.c b/src/readelf.c index ab0223b8..be9fe88c 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -484,7 +484,11 @@ parse_opt (int key, char *arg, else if (strcmp (arg, "pubnames") == 0) print_debug_sections |= section_pubnames; else if (strcmp (arg, "str") == 0) - print_debug_sections |= section_str; + { + print_debug_sections |= section_str; + /* For mapping string offset tables to CUs. */ + implicit_debug_sections |= section_info; + } else if (strcmp (arg, "macinfo") == 0) print_debug_sections |= section_macinfo; else if (strcmp (arg, "macro") == 0) @@ -4824,6 +4828,7 @@ static struct listptr_table known_loclistsptr; static struct listptr_table known_rangelistptr; static struct listptr_table known_rnglistptr; static struct listptr_table known_addrbases; +static struct listptr_table known_stroffbases; static void reset_listptr (struct listptr_table *table) @@ -7192,6 +7197,21 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) } return DWARF_CB_OK; + case DW_AT_str_offsets_base: + { + bool stroffbase = notice_listptr (section_str, &known_stroffbases, + cbargs->addrsize, + cbargs->offset_size, + cbargs->cu, num, attr); + if (!cbargs->silent) + printf (" %*s%-20s (%s) str offsets base [%6" + PRIxMAX "]%s\n", + (int) (level * 2), "", dwarf_attr_name (attr), + dwarf_form_name (form), (uintmax_t) num, + stroffbase ? "" : " <WARNING offset too big>"); + } + return DWARF_CB_OK; + case DW_AT_language: valuestr = dwarf_lang_name (num); break; @@ -9936,6 +9956,193 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)), } } +static void +print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)), + Ebl *ebl, GElf_Ehdr *ehdr, + Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg) +{ + printf (gettext ("\ +\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), + elf_ndxscn (scn), section_name (ebl, ehdr, shdr), + (uint64_t) shdr->sh_offset); + + if (shdr->sh_size == 0) + return; + + /* We like to get the section from libdw to make sure they are relocated. */ + Elf_Data *data = (dbg->sectiondata[IDX_debug_str_offsets] + ?: elf_rawdata (scn, NULL)); + if (unlikely (data == NULL)) + { + error (0, 0, gettext ("cannot get .debug_str_offsets section data: %s"), + elf_errmsg (-1)); + return; + } + + size_t idx = 0; + sort_listptr (&known_stroffbases, "str_offsets"); + + const unsigned char *start = (const unsigned char *) data->d_buf; + const unsigned char *readp = start; + const unsigned char *readendp = ((const unsigned char *) data->d_buf + + data->d_size); + + while (readp < readendp) + { + /* Most string offset tables will have a header. For split + dwarf unit GNU DebugFission didn't add one. But they were + also only defined for split units (main or skeleton units + didn't have indirect strings). So if we don't have a + DW_AT_str_offsets_base at all and this is offset zero, then + just start printing offsets immediately, if this is a .dwo + section. */ + Dwarf_Off off = (Dwarf_Off) (readp + - (const unsigned char *) data->d_buf); + + printf ("Table at offset %" PRIx64 " ", off); + + struct listptr *listptr = get_listptr (&known_stroffbases, idx++); + const unsigned char *next_unitp = readendp; + uint8_t offset_size; + bool has_header; + if (listptr == NULL) + { + /* This can happen for .dwo files. There is only an header + in the case this is a version 5 split DWARF file. */ + Dwarf_CU *cu; + uint8_t unit_type; + if (dwarf_get_units (dbg, NULL, &cu, NULL, &unit_type, + NULL, NULL) != 0) + { + error (0, 0, "Warning: Cannot find any DWARF unit."); + /* Just guess some values. */ + has_header = false; + offset_size = 4; + } + else if (off == 0 + && (unit_type == DW_UT_split_type + || unit_type == DW_UT_split_compile)) + { + has_header = cu->version > 4; + offset_size = cu->offset_size; + } + else + { + error (0, 0, + "Warning: No CU references .debug_str_offsets after %" + PRIx64, off); + has_header = cu->version > 4; + offset_size = cu->offset_size; + } + printf ("\n"); + } + else + { + /* This must be DWARF5, since GNU DebugFission didn't define + DW_AT_str_offsets_base. */ + has_header = true; + + Dwarf_Die cudie; + if (dwarf_cu_die (listptr->cu, &cudie, + NULL, NULL, NULL, NULL, + NULL, NULL) == NULL) + printf ("Unknown CU (%s):\n", dwarf_errmsg (-1)); + else + printf ("for CU [%6" PRIx64 "]:\n", dwarf_dieoffset (&cudie)); + } + + if (has_header) + { + uint64_t unit_length; + uint16_t version; + uint16_t padding; + + unit_length = read_4ubyte_unaligned_inc (dbg, readp); + if (unlikely (unit_length == 0xffffffff)) + { + if (unlikely (readp > readendp - 8)) + { + invalid_data: + error (0, 0, "Invalid data"); + return; + } + unit_length = read_8ubyte_unaligned_inc (dbg, readp); + offset_size = 8; + } + else + offset_size = 4; + + printf ("\n"); + printf (gettext (" Length: %8" PRIu64 "\n"), + unit_length); + printf (gettext (" Offset size: %8" PRIu8 "\n"), + offset_size); + + /* We need at least 2-bytes (version) + 2-bytes (padding) = + 4 bytes to complete the header. And this unit cannot go + beyond the section data. */ + if (readp > readendp - 4 + || unit_length < 4 + || unit_length > (uint64_t) (readendp - readp)) + goto invalid_data; + + next_unitp = readp + unit_length; + + version = read_2ubyte_unaligned_inc (dbg, readp); + printf (gettext (" DWARF version: %8" PRIu16 "\n"), version); + + if (version != 5) + { + error (0, 0, gettext ("Unknown version")); + goto next_unit; + } + + padding = read_2ubyte_unaligned_inc (dbg, readp); + printf (gettext (" Padding: %8" PRIx16 "\n"), padding); + + if (listptr != NULL + && listptr->offset != (Dwarf_Off) (readp - start)) + { + error (0, 0, "String offsets index doesn't start after header"); + goto next_unit; + } + + printf ("\n"); + } + + int digits = 1; + size_t offsets = (next_unitp - readp) / offset_size; + while (offsets >= 10) + { + ++digits; + offsets /= 10; + } + + unsigned int index = 0; + size_t index_offset = readp - (const unsigned char *) data->d_buf; + printf (" Offsets start at 0x%zx:\n", index_offset); + while (readp <= next_unitp - offset_size) + { + Dwarf_Word offset; + if (offset_size == 4) + offset = read_4ubyte_unaligned_inc (dbg, readp); + else + offset = read_8ubyte_unaligned_inc (dbg, readp); + const char *str = dwarf_getstring (dbg, offset, NULL); + printf (" [%*u] [%*" PRIx64 "] \"%s\"\n", + digits, index++, (int) offset_size * 2, offset, str ?: "???"); + } + printf ("\n"); + + if (readp != next_unitp) + error (0, 0, "extra %zd bytes at end of unit", + (size_t) (next_unitp - readp)); + + next_unit: + readp = next_unitp; + } +} + /* Print the content of the call frame search table section '.eh_frame_hdr'. */ @@ -10752,6 +10959,9 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) /* A DWARF5 specialised debug string section. */ { ".debug_line_str", section_str, print_debug_str_section }, + /* DWARF5 string offsets table. */ + { ".debug_str_offsets", section_str, + print_debug_str_offsets_section }, NEW_SECTION (macinfo), NEW_SECTION (macro), NEW_SECTION (ranges), @@ -10807,6 +11017,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) reset_listptr (&known_rangelistptr); reset_listptr (&known_rnglistptr); reset_listptr (&known_addrbases); + reset_listptr (&known_stroffbases); } diff --git a/tests/ChangeLog b/tests/ChangeLog index 69915519..7ac6bd3c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2018-04-29 Mark Wielaard <[email protected]> + + * run-readelf-addr.sh: New test. + * Makefile.am (TESTS): Add run-readelf-addr.sh. + (EXTRA_DIST): Likewise. + 2018-04-27 Mark Wielaard <[email protected]> * run-readelf-ranges.sh: Adjust expected output for address base. diff --git a/tests/Makefile.am b/tests/Makefile.am index e15fe519..4cd06656 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -130,7 +130,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-backtrace-core-aarch64.sh run-backtrace-core-sparc.sh \ run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \ run-stack-demangled-test.sh run-readelf-zx.sh run-readelf-zp.sh \ - run-readelf-addr.sh \ + run-readelf-addr.sh run-readelf-str.sh \ run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \ run-linkmap-cut.sh run-aggregate-size.sh run-peel-type.sh \ vdsosyms run-readelf-A.sh \ @@ -246,7 +246,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-readelf-dwz-multi.sh libtestfile_multi_shared.so.bz2 \ testfile_multi.dwz.bz2 testfile_multi_main.bz2 \ testfile-dwzstr.bz2 testfile-dwzstr.multi.bz2 \ - run-readelf-addr.sh \ + run-readelf-addr.sh run-readelf-str.sh \ run-allfcts-multi.sh \ test-offset-loop.bz2 test-offset-loop.alt.bz2 \ run-prelink-addr-test.sh \ diff --git a/tests/run-readelf-str.sh b/tests/run-readelf-str.sh new file mode 100755 index 00000000..8b894e8d --- /dev/null +++ b/tests/run-readelf-str.sh @@ -0,0 +1,211 @@ +#! /bin/sh +# 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 <http://www.gnu.org/licenses/>. + +. $srcdir/test-subr.sh + +# See tests/testfile-dwarf-45.source +testfiles testfile-splitdwarf-4 testfile-splitdwarf-5 +testfiles testfile-hello4.dwo testfile-hello5.dwo +testfiles testfile-world4.dwo testfile-world5.dwo + +# DWARF4 GNU DebugFission No real table header. +# We don't really need the skeleton, but we don't want any Warnings. +testrun_compare ${abs_top_builddir}/src/readelf --dwarf-skeleton testfile-splitdwarf-4 --debug-dump=str testfile-hello4.dwo testfile-world4.dwo<<\EOF + +testfile-hello4.dwo: + + +DWARF section [ 5] '.debug_str_offsets.dwo' at offset 0x335: +Table at offset 0 + Offsets start at 0x0: + [ 0] [ 0] "long long int" + [ 1] [ e] "frob" + [ 2] [ 13] "long unsigned int" + [ 3] [ 25] "/home/mark/src/elfutils/tests" + [ 4] [ 43] "wchar_t" + [ 5] [ 4b] "main" + [ 6] [ 50] "long int" + [ 7] [ 59] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ 8] [ e9] "long double" + [ 9] [ f5] "hello.c" + + +DWARF section [ 6] '.debug_str.dwo' at offset 0x35d: + Offset String + [ 0] "long long int" + [ e] "frob" + [ 13] "long unsigned int" + [ 25] "/home/mark/src/elfutils/tests" + [ 43] "wchar_t" + [ 4b] "main" + [ 50] "long int" + [ 59] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ e9] "long double" + [ f5] "hello.c" + +testfile-world4.dwo: + + +DWARF section [ 5] '.debug_str_offsets.dwo' at offset 0x2e7: +Table at offset 0 + Offsets start at 0x0: + [ 0] [ 0] "long long unsigned int" + [ 1] [ 17] "/home/mark/src/elfutils/tests" + [ 2] [ 35] "long long int" + [ 3] [ 43] "signed char" + [ 4] [ 4f] "long int" + [ 5] [ 58] "world.c" + [ 6] [ 60] "unsigned int" + [ 7] [ 6d] "long unsigned int" + [ 8] [ 7f] "short unsigned int" + [ 9] [ 92] "frob" + [10] [ 97] "calc" + [11] [ 9c] "unsigned char" + [12] [ aa] "short int" + [13] [ b4] "exit" + [14] [ b9] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [15] [ 149] "char" + [16] [ 14e] "word" + [17] [ 153] "argv" + [18] [ 158] "argc" + [19] [ 15d] "main" + + +DWARF section [ 6] '.debug_str.dwo' at offset 0x337: + Offset String + [ 0] "long long unsigned int" + [ 17] "/home/mark/src/elfutils/tests" + [ 35] "long long int" + [ 43] "signed char" + [ 4f] "long int" + [ 58] "world.c" + [ 60] "unsigned int" + [ 6d] "long unsigned int" + [ 7f] "short unsigned int" + [ 92] "frob" + [ 97] "calc" + [ 9c] "unsigned char" + [ aa] "short int" + [ b4] "exit" + [ b9] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-4 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ 149] "char" + [ 14e] "word" + [ 153] "argv" + [ 158] "argc" + [ 15d] "main" +EOF + +# DWARF5 Real table header. +# We don't really need the skeleton, but we don't want any Warnings. +testrun_compare ${abs_top_builddir}/src/readelf --dwarf-skeleton testfile-splitdwarf-5 --debug-dump=str testfile-hello5.dwo testfile-world5.dwo<<\EOF + +testfile-hello5.dwo: + + +DWARF section [ 5] '.debug_str_offsets.dwo' at offset 0x353: +Table at offset 0 + + Length: 44 + Offset size: 4 + DWARF version: 5 + Padding: 0 + + Offsets start at 0x8: + [ 0] [ 0] "long long int" + [ 1] [ e] "frob" + [ 2] [ 13] "long unsigned int" + [ 3] [ 25] "/home/mark/src/elfutils/tests" + [ 4] [ 43] "wchar_t" + [ 5] [ 4b] "main" + [ 6] [ 50] "long int" + [ 7] [ 59] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ 8] [ e9] "long double" + [ 9] [ f5] "hello.c" + + +DWARF section [ 6] '.debug_str.dwo' at offset 0x383: + Offset String + [ 0] "long long int" + [ e] "frob" + [ 13] "long unsigned int" + [ 25] "/home/mark/src/elfutils/tests" + [ 43] "wchar_t" + [ 4b] "main" + [ 50] "long int" + [ 59] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ e9] "long double" + [ f5] "hello.c" + +testfile-world5.dwo: + + +DWARF section [ 5] '.debug_str_offsets.dwo' at offset 0x313: +Table at offset 0 + + Length: 84 + Offset size: 4 + DWARF version: 5 + Padding: 0 + + Offsets start at 0x8: + [ 0] [ 0] "long long unsigned int" + [ 1] [ 17] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ 2] [ a7] "/home/mark/src/elfutils/tests" + [ 3] [ c5] "long long int" + [ 4] [ d3] "signed char" + [ 5] [ df] "long int" + [ 6] [ e8] "world.c" + [ 7] [ f0] "unsigned int" + [ 8] [ fd] "long unsigned int" + [ 9] [ 10f] "short unsigned int" + [10] [ 122] "frob" + [11] [ 127] "calc" + [12] [ 12c] "unsigned char" + [13] [ 13a] "short int" + [14] [ 144] "exit" + [15] [ 149] "char" + [16] [ 14e] "word" + [17] [ 153] "argv" + [18] [ 158] "argc" + [19] [ 15d] "main" + + +DWARF section [ 6] '.debug_str.dwo' at offset 0x36b: + Offset String + [ 0] "long long unsigned int" + [ 17] "GNU C17 9.0.0 20180515 (experimental) -mtune=generic -march=x86-64 -gdwarf-5 -gsplit-dwarf -gno-as-loc-support -gno-variable-location-views -O2" + [ a7] "/home/mark/src/elfutils/tests" + [ c5] "long long int" + [ d3] "signed char" + [ df] "long int" + [ e8] "world.c" + [ f0] "unsigned int" + [ fd] "long unsigned int" + [ 10f] "short unsigned int" + [ 122] "frob" + [ 127] "calc" + [ 12c] "unsigned char" + [ 13a] "short int" + [ 144] "exit" + [ 149] "char" + [ 14e] "word" + [ 153] "argv" + [ 158] "argc" + [ 15d] "main" +EOF + +exit 0 |
