libdw: dwarf_elf_begin should use either plain, dwo or lto DWARF sections.

Message ID 20211108084211.253156-1-mark@klomp.org
State Committed
Headers
Series libdw: dwarf_elf_begin should use either plain, dwo or lto DWARF sections. |

Commit Message

Mark Wielaard Nov. 8, 2021, 8:42 a.m. UTC
  When opening an ELF file that contained a mix of pain, 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 <mark@klomp.org>
---
 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

GIT binary patch
literal 3101
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

literal 0
HcmV?d00001
  

Patch

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 311f34b5..08e8863d 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,12 @@ 
+2021-11-08  Mark Wielaard  <mark@klomp.org>
+
+	* 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-10-18  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf_aggregate_size.c (get_type): Don't pass NULL to
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 53b44cd4..a48dada6 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 7174ea93..48f3a943 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 b791cd7f..c5d00027 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,11 @@ 
+2021-11-08  Mark Wielaard  <mark@klomp.org>
+
+	* 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  <fche@redhat.com>
 
 	PR28514
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 54b38954..ccc4c052 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 00000000..e03cec3a
--- /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