diff mbox series

libbacktrace patch committed: Read symbol table of debuginfo file

Message ID CAOyqgcWNyv_NAk+y_5SKd7SV2aVUg4898H94QigpEc5M83ecKQ@mail.gmail.com
State New
Headers show
Series libbacktrace patch committed: Read symbol table of debuginfo file | expand

Commit Message

Ian Lance Taylor March 1, 2024, 3:47 a.m. UTC
This patch to libbacktrace reads symbol tables from debuginfo files.
These become another symbol table to search.  This is needed if people
use --strip-all rather than --strip-debug when adding a debuglink
section.  This fixes
https://github.com/ianlancetaylor/libbacktrace/issues/113.
Bootstrapped and ran libbacktrace and libgo tests on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian

* elf.c (elf_add): Add the symbol table from a debuginfo file.
* Makefile.am (MAKETESTS): Add buildidfull and gnudebuglinkfull
variants of buildid and gnudebuglink tests.
(%_gnudebuglinkfull, %_buildidfull): New patterns.
* Makefile.in: Regenerate.
24810fbf7b0ce274dfa46cc362305ac77ee5a72c

Comments

Ian Lance Taylor March 2, 2024, 2:53 a.m. UTC | #1
On Thu, Feb 29, 2024 at 7:47 PM Ian Lance Taylor <iant@golang.org> wrote:
>
> This patch to libbacktrace reads symbol tables from debuginfo files.
> These become another symbol table to search.  This is needed if people
> use --strip-all rather than --strip-debug when adding a debuglink
> section.  This fixes
> https://github.com/ianlancetaylor/libbacktrace/issues/113.
> Bootstrapped and ran libbacktrace and libgo tests on
> x86_64-pc-linux-gnu.  Committed to mainline.

This introduced a bug on the PPC v1 ABI, where libbacktrace uses the
.opd section to convert from a function descriptor address to a code
address.  The .opd section is missing from a debuginfo file.  This
patch changes the code to use the original .opd section if it is
missing.  Checked on powerpc64-linux-gnu and x86_64-pc-linux-gnu.
Committed to mainline.

Ian

PR libbacktrace/114201
* elf.c (elf_add): Add caller_opd parameter.  Change all callers.
Release opd data after all recursive calls.
f692b338cd27a4e0d38fcb5af3d416cd66fbf814
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 664937e1438..f4527e2477d 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -6501,8 +6501,9 @@ backtrace_uncompress_lzma (struct backtrace_state *state,
 static int
 elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	 const unsigned char *memory, size_t memory_size,
-	 uintptr_t base_address, backtrace_error_callback error_callback,
-	 void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf,
+	 uintptr_t base_address, struct elf_ppc64_opd_data *caller_opd,
+	 backtrace_error_callback error_callback, void *data,
+	 fileline *fileline_fn, int *found_sym, int *found_dwarf,
 	 struct dwarf_data **fileline_entry, int exe, int debuginfo,
 	 const char *with_buildid_data, uint32_t with_buildid_size)
 {
@@ -6557,6 +6558,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   struct elf_view split_debug_view[DEBUG_MAX];
   unsigned char split_debug_view_valid[DEBUG_MAX];
   struct elf_ppc64_opd_data opd_data, *opd;
+  int opd_view_valid;
   struct dwarf_sections dwarf_sections;
 
   if (!debuginfo)
@@ -6584,6 +6586,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   debug_view_valid = 0;
   memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid);
   opd = NULL;
+  opd_view_valid = 0;
 
   if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr,
 		     error_callback, data, &ehdr_view))
@@ -6867,9 +6870,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	  opd->addr = shdr->sh_addr;
 	  opd->data = (const char *) opd_data.view.view.data;
 	  opd->size = shdr->sh_size;
+	  opd_view_valid = 1;
 	}
     }
 
+  // A debuginfo file may not have a useful .opd section, but we can use the
+  // one from the original executable.
+  if (opd == NULL)
+    opd = caller_opd;
+
   if (symtab_shndx == 0)
     symtab_shndx = dynsym_shndx;
   if (symtab_shndx != 0)
@@ -6948,9 +6957,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	    elf_release_view (state, &debuglink_view, error_callback, data);
 	  if (debugaltlink_view_valid)
 	    elf_release_view (state, &debugaltlink_view, error_callback, data);
-	  ret = elf_add (state, "", d, NULL, 0, base_address, error_callback,
-			 data, fileline_fn, found_sym, found_dwarf, NULL, 0,
-			 1, NULL, 0);
+	  ret = elf_add (state, "", d, NULL, 0, base_address, opd,
+			 error_callback, data, fileline_fn, found_sym,
+			 found_dwarf, NULL, 0, 1, NULL, 0);
 	  if (ret < 0)
 	    backtrace_close (d, error_callback, data);
 	  else if (descriptor >= 0)
@@ -6965,12 +6974,6 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       buildid_view_valid = 0;
     }
 
-  if (opd)
-    {
-      elf_release_view (state, &opd->view, error_callback, data);
-      opd = NULL;
-    }
-
   if (debuglink_name != NULL)
     {
       int d;
@@ -6985,9 +6988,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	  elf_release_view (state, &debuglink_view, error_callback, data);
 	  if (debugaltlink_view_valid)
 	    elf_release_view (state, &debugaltlink_view, error_callback, data);
-	  ret = elf_add (state, "", d, NULL, 0, base_address, error_callback,
-			 data, fileline_fn, found_sym, found_dwarf, NULL, 0,
-			 1, NULL, 0);
+	  ret = elf_add (state, "", d, NULL, 0, base_address, opd,
+			 error_callback, data, fileline_fn, found_sym,
+			 found_dwarf, NULL, 0, 1, NULL, 0);
 	  if (ret < 0)
 	    backtrace_close (d, error_callback, data);
 	  else if (descriptor >= 0)
@@ -7013,7 +7016,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	{
 	  int ret;
 
-	  ret = elf_add (state, filename, d, NULL, 0, base_address,
+	  ret = elf_add (state, filename, d, NULL, 0, base_address, opd,
 			 error_callback, data, fileline_fn, found_sym,
 			 found_dwarf, &fileline_altlink, 0, 1,
 			 debugaltlink_buildid_data, debugaltlink_buildid_size);
@@ -7050,7 +7053,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       if (ret)
 	{
 	  ret = elf_add (state, filename, -1, gnu_debugdata_uncompressed,
-			 gnu_debugdata_uncompressed_size, base_address,
+			 gnu_debugdata_uncompressed_size, base_address, opd,
 			 error_callback, data, fileline_fn, found_sym,
 			 found_dwarf, NULL, 0, 0, NULL, 0);
 	  if (ret >= 0 && descriptor >= 0)
@@ -7059,6 +7062,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	}
     }
 
+  if (opd_view_valid)
+    {
+      elf_release_view (state, &opd->view, error_callback, data);
+      opd_view_valid = 0;
+      opd = NULL;
+    }
+
   /* Read all the debug sections in a single view, since they are
      probably adjacent in the file.  If any of sections are
      uncompressed, we never release this view.  */
@@ -7305,7 +7315,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       if (split_debug_view_valid[i])
 	elf_release_view (state, &split_debug_view[i], error_callback, data);
     }
-  if (opd)
+  if (opd_view_valid)
     elf_release_view (state, &opd->view, error_callback, data);
   if (descriptor >= 0)
     backtrace_close (descriptor, error_callback, data);
@@ -7369,7 +7379,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
 	return 0;
     }
 
-  if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr,
+  if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr, NULL,
 	       pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
 	       &found_dwarf, NULL, 0, 0, NULL, 0))
     {
@@ -7398,9 +7408,9 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
   fileline elf_fileline_fn = elf_nodebug;
   struct phdr_data pd;
 
-  ret = elf_add (state, filename, descriptor, NULL, 0, 0, error_callback, data,
-		 &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL,
-		 0);
+  ret = elf_add (state, filename, descriptor, NULL, 0, 0, NULL, error_callback,
+		 data, &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0,
+		 NULL, 0);
   if (!ret)
     return 0;
diff mbox series

Patch

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 16a72d2abf7..750ed80ed05 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -257,7 +257,7 @@  b2test_LDFLAGS = -Wl,--build-id
 b2test_LDADD = libbacktrace_elf_for_test.la
 
 check_PROGRAMS += b2test
-MAKETESTS += b2test_buildid
+MAKETESTS += b2test_buildid b2test_buildidfull
 
 if HAVE_DWZ
 
@@ -267,7 +267,7 @@  b3test_LDFLAGS = -Wl,--build-id
 b3test_LDADD = libbacktrace_elf_for_test.la
 
 check_PROGRAMS += b3test
-MAKETESTS += b3test_dwz_buildid
+MAKETESTS += b3test_dwz_buildid b3test_dwz_buildidfull
 
 endif HAVE_DWZ
 
@@ -443,12 +443,16 @@  endif HAVE_PTHREAD
 
 if HAVE_OBJCOPY_DEBUGLINK
 
-MAKETESTS += btest_gnudebuglink
+MAKETESTS += btest_gnudebuglink btest_gnudebuglinkfull
 
 %_gnudebuglink: %
 	$(OBJCOPY) --only-keep-debug $< $@.debug
 	$(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@
 
+%_gnudebuglinkfull: %
+	$(OBJCOPY) --only-keep-debug $< $@.debug
+	$(OBJCOPY) --strip-all --add-gnu-debuglink=$@.debug $< $@
+
 endif HAVE_OBJCOPY_DEBUGLINK
 
 %_buildid: %
@@ -457,6 +461,12 @@  endif HAVE_OBJCOPY_DEBUGLINK
 	  $<
 	$(OBJCOPY) --strip-debug $< $@
 
+%_buildidfull: %
+	./install-debuginfo-for-buildid.sh \
+	  "$(TEST_BUILD_ID_DIR)" \
+	  $<
+	$(OBJCOPY) --strip-all $< $@
+
 if HAVE_COMPRESSED_DEBUG
 
 ctestg_SOURCES = btest.c testlib.c
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index c506cc29fe1..664937e1438 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -6872,7 +6872,7 @@  elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   if (symtab_shndx == 0)
     symtab_shndx = dynsym_shndx;
-  if (symtab_shndx != 0 && !debuginfo)
+  if (symtab_shndx != 0)
     {
       const b_elf_shdr *symtab_shdr;
       unsigned int strtab_shndx;