From 5b21e70216b853065fa2fef34273db5f7dcdc88b Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 8 Nov 2021 09:27:51 +0100 Subject: [PATCH] libdw: dwarf_elf_begin should use either plain, dwo or lto DWARF sections. When opening an ELF file that contained a mix of plain, dwo or lto .debug sections the result could be confusing. Add a check to pick just the plain .debug sections, or the .dwo sections or the .gnu.debuglto_.debug sections (in that order of preference). That way there is always a consistent set. https://sourceware.org/bugzilla/show_bug.cgi?id=27367 Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 9 +++ libdw/dwarf_begin_elf.c | 83 ++++++++++++++++++++++++++-- libdw/libdwP.h | 12 ++++ tests/ChangeLog | 8 +++ tests/Makefile.am | 3 +- tests/run-readelf-fat-lto.sh | 53 ++++++++++++++++++ tests/testfile-dwarf5-fat-lto.o.bz2 | Bin 0 -> 3101 bytes 7 files changed, 162 insertions(+), 6 deletions(-) create mode 100755 tests/run-readelf-fat-lto.sh create mode 100644 tests/testfile-dwarf5-fat-lto.o.bz2 diff --git a/libdw/ChangeLog b/libdw/ChangeLog index b38368338..38e6efb22 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,12 @@ +2021-11-08 Mark Wielaard + + * dwarf_begin_elf.c (scn_dwarf_type): New function. + (check_section): Check result->type. + (global_read): First check type. + (scngrp_read): Likewise. + * libdw/libdwP.h (enum dwarf_type): New enumeration. + (struct Dwarf): New field type. + 2021-02-14 Alexander Miller * dwarf_aggregate_size.c (dwarf_aggregate_size): Move NEW_VERSION diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 53b44cd43..a48dada6f 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -72,6 +72,31 @@ static const char dwarf_scnnames[IDX_last][19] = }; #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) +static enum dwarf_type +scn_dwarf_type (Dwarf *result, size_t shstrndx, Elf_Scn *scn) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr == NULL) + return TYPE_UNKNOWN; + + const char *scnname = elf_strptr (result->elf, shstrndx, + shdr->sh_name); + if (scnname != NULL) + { + if (startswith (scnname, ".gnu.debuglto_.debug")) + return TYPE_GNU_LTO; + else if (startswith (scnname, ".debug_") || startswith (scnname, ".zdebug_")) + { + size_t len = strlen (scnname); + if (strcmp (scnname + len - 4, ".dwo") == 0) + return TYPE_DWO; + else + return TYPE_PLAIN; + } + } + return TYPE_UNKNOWN; +} static Dwarf * check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp) { @@ -116,7 +141,11 @@ check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp) return NULL; } - /* Recognize the various sections. Most names start with .debug_. */ + /* Recognize the various sections. Most names start with .debug_. + They might be compressed (and start with .z). Or end with .dwo + for split dwarf sections. Or start with .gnu.debuglto_ for + LTO debug sections. We should only use one consistent set at + a time. We prefer PLAIN over DWO over LTO. */ size_t cnt; bool gnu_compressed = false; for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) @@ -127,7 +156,15 @@ check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp) && (dbglen == scnlen || (scnlen == dbglen + 4 && strstr (scnname, ".dwo") == scnname + dbglen))) - break; + { + if (dbglen == scnlen) + { + if (result->type == TYPE_PLAIN) + break; + } + else if (result->type == TYPE_DWO) + break; + } else if (scnname[0] == '.' && scnname[1] == 'z' && (strncmp (&scnname[2], &dwarf_scnnames[cnt][1], dbglen - 1) == 0 @@ -136,13 +173,27 @@ check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp) && strstr (scnname, ".dwo") == scnname + dbglen + 1)))) { - gnu_compressed = true; - break; + if (scnlen == dbglen + 1) + { + if (result->type == TYPE_PLAIN) + { + gnu_compressed = true; + break; + } + } + else if (result->type <= TYPE_DWO) + { + gnu_compressed = true; + break; + } } else if (scnlen > 14 /* .gnu.debuglto_ prefix. */ && startswith (scnname, ".gnu.debuglto_") && strcmp (&scnname[14], dwarf_scnnames[cnt]) == 0) - break; + { + if (result->type == TYPE_GNU_LTO) + break; + } } if (cnt >= ndwarf_scnnames) @@ -344,6 +395,16 @@ global_read (Dwarf *result, Elf *elf, size_t shstrndx) { Elf_Scn *scn = NULL; + /* First check the type (PLAIN, DWO, LTO) we are looking for. We + prefer PLAIN if available over DWO, over LTO. */ + while ((scn = elf_nextscn (elf, scn)) != NULL && result->type != TYPE_PLAIN) + { + enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn); + if (type > result->type) + result->type = type; + } + + scn = NULL; while (result != NULL && (scn = elf_nextscn (elf, scn)) != NULL) result = check_section (result, shstrndx, scn, false); @@ -388,6 +449,9 @@ scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, Elf_Scn *scngrp) represent section indices. The first word is a flag word. */ Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; size_t cnt; + + /* First check the type (PLAIN, DWO, LTO) we are looking for. We + prefer PLAIN if available over DWO, over LTO. */ for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) { Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); @@ -401,6 +465,15 @@ scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, Elf_Scn *scngrp) return NULL; } + enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn); + if (type > result->type) + result->type = type; + } + + for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size && result != NULL; ++cnt) + { + Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); + assert (scn != NULL); // checked above result = check_section (result, shstrndx, scn, true); if (result == NULL) break; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 7174ea931..48f3a9435 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -145,6 +145,16 @@ enum #include "dwarf_sig8_hash.h" +/* The type of Dwarf object, sorted by preference + (if there is a higher order type, we pick that one over the others). */ +enum dwarf_type + { + TYPE_UNKNOWN = 0, + TYPE_GNU_LTO = 16, + TYPE_DWO = 32, + TYPE_PLAIN = 64, + }; + /* This is the structure representing the debugging state. */ struct Dwarf { @@ -216,6 +226,8 @@ struct Dwarf /* Similar for addrx/constx, which will come from .debug_addr section. */ struct Dwarf_CU *fake_addr_cu; + enum dwarf_type type; + /* Supporting lock for internal memory handling. Ensures threads that have an entry in the mem_tails array are not disturbed by new threads doing allocations for this Dwarf. */ diff --git a/tests/ChangeLog b/tests/ChangeLog index b791cd7f0..c5d00027b 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,11 @@ +2021-11-08 Mark Wielaard + + * Makefile.am (TESTS): Add run-readelf-fat-lto.sh. + (EXTRA_DIST): Add run-readelf-fat-lto.sh and + testfile-dwarf5-fat-lto.o.bz2. + * run-readelf-fat-lto.sh: New test. + * testfile-dwarf5-fat-lto.o.bz2: New test file. + 2021-11-04 Frank Ch. Eigler PR28514 diff --git a/tests/Makefile.am b/tests/Makefile.am index 54b389549..ccc4c0522 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -139,7 +139,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-low_high_pc.sh run-macro-test.sh run-elf_cntl_gelf_getshdr.sh \ run-test-archive64.sh run-readelf-vmcoreinfo.sh \ run-readelf-mixed-corenote.sh run-dwfllines.sh \ - run-readelf-variant.sh \ + run-readelf-variant.sh run-readelf-fat-lto.sh \ run-dwfl-report-elf-align.sh run-addr2line-test.sh \ run-addr2line-i-test.sh run-addr2line-i-lex-test.sh \ run-addr2line-i-demangle-test.sh run-addr2line-alt-debugpath.sh \ @@ -379,6 +379,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfilebazminppc64.bz2 testfilebazminppc64_pl.bz2 \ testfilebazminppc64_plr.bz2 testfilebaztabppc64.bz2 \ run-readelf-variant.sh testfile-ada-variant.bz2 \ + run-readelf-fat-lto.sh testfile-dwarf5-fat-lto.o.bz2 \ run-dwflsyms.sh \ run-unstrip-n.sh testcore-rtlib.bz2 testcore-rtlib-ppc.bz2 \ run-low_high_pc.sh testfile_low_high_pc.bz2 \ diff --git a/tests/run-readelf-fat-lto.sh b/tests/run-readelf-fat-lto.sh new file mode 100755 index 000000000..e03cec3a9 --- /dev/null +++ b/tests/run-readelf-fat-lto.sh @@ -0,0 +1,53 @@ +. $srcdir/test-subr.sh + +# - s.c +# int main_argc_remaining; +# +# int main_argc() { +# int result = 0; +# if (main_argc_remaining) +# result = 0; +# +# return 0; +# } +# +# gcc -gdwarf-5 -c -o testfile-dwarf5-fat-lto.o -flto -O s.c -g -ffat-lto-objects + +testfiles testfile-dwarf5-fat-lto.o +testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=loc --debug-dump=ranges -N -U testfile-dwarf5-fat-lto.o << EOF + +DWARF section [26] '.debug_loclists' at offset 0x7db: +Table at Offset 0x0: + + Length: 24 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 0 + CU [ c] base: 000000000000000000 + + Offset: c, Index: 0 + view pair 2, 3 + + Offset: e, Index: 2 + start_length 0x0, 0 + [ 0] lit0 + [ 1] stack_value + end_of_list + + +DWARF section [30] '.debug_rnglists' at offset 0x827: +Table at Offset 0x0: + + Length: 19 + DWARF version: 5 + Address size: 8 + Segment size: 0 + Offset entries: 0 + CU [ c] base: 000000000000000000 + + Offset: c, Index: 0 + start_length 0x0, 8 + end_of_list + +EOF diff --git a/tests/testfile-dwarf5-fat-lto.o.bz2 b/tests/testfile-dwarf5-fat-lto.o.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..ce3659f4a41c0a42b6f85827a31d810a1ec996d3 GIT binary patch literal 3101 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 literal 0 Hc-jL100001 -- 2.39.5