[3/3] Some bug fixes for MOREDATA

Message ID 20260717203854.627989-3-andi@firstfloor.org
State New
Headers
Series [1/3] Add backtrace_decl_line to libbacktrace |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Andi Kleen July 17, 2026, 8:38 p.m. UTC
  From: Andi Kleen <ak@gcc.gnu.org>

The non symbol fallback handling didn't handle MOREDATA correctly,
resulting in the callback crashing because it tried to interpret
a MOREDATA wrapper as its callback data. Fix this by using
separate callbacks that understand MOREDATA. Also fix a similar
problem in xcoff (untested)

Also there were some open coded uses of the version, which
is a problem when extending the version.

libbacktrace/ChangeLog:

	* elf.c (elf_nodebug): Use moredata callback function if needed.
	* fileline.c (backtrace_syminfo_to_full_callback_moredata):
	Remove incorrect comment.
	(backtrace_syminfo_to_full_error_callback_moredata):
	New function.
	* internal.h (backtrace_syminfo_to_full_callback_moredata):
	New declaration.
	(backtrace_syminfo_to_full_error_callback_moredata):
	Dito.
	* pecoff.c (coff_syminfo): Use symbolic version.
	* unknown.c (unknown_fileline): Dito.
	* xcoff.c (xcoff_syminfo): Dito.
	(xcoff_lookup_pc): Dito.
	(xcoff_fileline): Pass correct moredata.
---
 libbacktrace/elf.c      | 10 ++++++++--
 libbacktrace/fileline.c | 36 ++++++++++++++++++++++++++++++++----
 libbacktrace/internal.h |  6 ++++++
 libbacktrace/pecoff.c   |  2 +-
 libbacktrace/unknown.c  |  2 +-
 libbacktrace/xcoff.c    |  8 ++++----
 6 files changed, 52 insertions(+), 12 deletions(-)
  

Patch

diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 297fb083b4b..46b65c0b82d 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -671,8 +671,14 @@  elf_nodebug (struct backtrace_state *state, uintptr_t pc,
       bdata.full_error_callback = error_callback;
       bdata.full_data = data;
       bdata.ret = 0;
-      state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,
-			 backtrace_syminfo_to_full_error_callback, &bdata);
+      if (state->moredata)
+	state->syminfo_fn (state, pc,
+				   backtrace_syminfo_to_full_callback_moredata,
+				   backtrace_syminfo_to_full_error_callback_moredata,
+				   &bdata);
+      else
+	state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,
+				   backtrace_syminfo_to_full_error_callback, &bdata);
       return bdata.ret;
     }
 
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 18bd87d65b3..89461b7c0b7 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -63,6 +63,7 @@  POSSIBILITY OF SUCH DAMAGE.  */
 #include <windows.h>
 #endif
 
+#include <string.h>
 #include "backtrace.h"
 #include "internal.h"
 
@@ -425,15 +426,31 @@  backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
 {
   struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
 
-  /* If STATE->MOREDATA is set, then data will point to a
-     backtrace_moredata struct, which is what full_callback expects.  */
-
   bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, symname);
 }
 
+/* Variant of backtrace_syminfo_to_full_callback that handles the exta wrapping
+   of moredata.  */
+
+void
+backtrace_syminfo_to_full_callback_moredata (void *data, uintptr_t pc,
+					     const char *symname,
+					     uintptr_t symval ATTRIBUTE_UNUSED,
+					     uintptr_t symsize ATTRIBUTE_UNUSED)
+{
+  struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+  struct backtrace_moredata callback_md;
+  struct backtrace_call_full *bdata;
+
+  bdata = (struct backtrace_call_full *) md->backtrace_data;
+  memset (&callback_md, 0, sizeof callback_md);
+  callback_md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
+  callback_md.backtrace_data = bdata->full_data;
+  bdata->ret = bdata->full_callback (&callback_md, pc, NULL, 0, symname);
+}
+
 /* An error callback that corresponds to
    backtrace_syminfo_to_full_callback.  */
-
 void
 backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
 					  int errnum)
@@ -442,3 +459,14 @@  backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
 
   bdata->full_error_callback (bdata->full_data, msg, errnum);
 }
+
+void
+backtrace_syminfo_to_full_error_callback_moredata (void *data, const char *msg,
+							   int errnum)
+{
+  struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+  struct backtrace_call_full *bdata;
+
+  bdata = (struct backtrace_call_full *) md->backtrace_data;
+  bdata->full_error_callback (bdata->full_data, msg, errnum);
+}
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 7ff01d0bc4f..afa971de600 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -395,12 +395,18 @@  extern void backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
 						const char *symname,
 						uintptr_t symval,
 						uintptr_t symsize);
+extern void backtrace_syminfo_to_full_callback_moredata (void *data, uintptr_t pc,
+							 const char *symname,
+							 uintptr_t symval,
+							 uintptr_t symsize);
 
 /* An error callback that corresponds to
    backtrace_syminfo_to_full_callback.  */
 
 extern void backtrace_syminfo_to_full_error_callback (void *, const char *,
 						      int);
+extern void backtrace_syminfo_to_full_error_callback_moredata (void *, const char *,
+								 int);
 
 /* A test-only hook for elf_uncompress_zdebug.  */
 
diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index 08ec4c2ba13..bad11a516c7 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -629,7 +629,7 @@  coff_syminfo (struct backtrace_state *state, uintptr_t addr,
   else
     {
       memset (&md, 0, sizeof md);
-      md.backtrace_version = 3;
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
       md.backtrace_data = data;
       mdata = (void *) &md;
     }
diff --git a/libbacktrace/unknown.c b/libbacktrace/unknown.c
index 80dc19d640d..1d89c2378b9 100644
--- a/libbacktrace/unknown.c
+++ b/libbacktrace/unknown.c
@@ -54,7 +54,7 @@  unknown_fileline (struct backtrace_state *state, uintptr_t pc,
       struct backtrace_moredata md;
 
       memset (&md, 0, sizeof md);
-      md.backtrace_version = 3;
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
       md.backtrace_data = data;
       return callback ((void *) &md, pc, NULL, 0, NULL);
     }
diff --git a/libbacktrace/xcoff.c b/libbacktrace/xcoff.c
index 43f78398762..2ed243cde2a 100644
--- a/libbacktrace/xcoff.c
+++ b/libbacktrace/xcoff.c
@@ -554,7 +554,7 @@  xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
   else
     {
       memset (&md, 0, sizeof md);
-      md.backtrace_version = 3;
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
       md.backtrace_data = data;
       mdata = (void *) &md;
     }
@@ -825,7 +825,7 @@  xcoff_lookup_pc (struct backtrace_state *state,
       struct backtrace_moredata md;
 
       memset (&md, 0, sizeof md);
-      md.backtrace_version = 3;
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
       md.backtrace_data = data;
       return callback ((void *) &md, pc, filename, lnno, function);
     }
@@ -885,9 +885,9 @@  xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
       struct backtrace_moredata md;
 
       memset (&md, 0, sizeof md);
-      md.backtrace_version = 3;
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
       md.backtrace_data = data;
-      return callback ((void *) data, pc, NULL, 0, NULL);
+      return callback ((void *) &md, pc, NULL, 0, NULL);
     }
 }