]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libbacktrace: support returning discriminator field
authorIan Lance Taylor <iant@golang.org>
Mon, 6 Jul 2026 17:55:52 +0000 (10:55 -0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 6 Jul 2026 18:01:18 +0000 (11:01 -0700)
Based on patch from Andi Kleen.

* backtrace.h (backtrace_create_state): Rewrite comment to change
threaded parameter to flags.
(backtrace_full_callback, backtrace_syminfo_callback): Document
behavior change if moredata flag is set.
(struct backtrace_moredata): Define.
* backtrace-supported.h.in (BACKTRACE_SUPPORTS_MOREDATA): Define.
* internal.h (struct backtrace_state): Add moredata field.
(BACKTRACE_MOREDATA_VERSION): Define.
* state.c (backtrace_create_state): Change threaded parameter to
flags.  Set state moredata field based on flags.
* dwarf.c (struct line): Add disc field.
(struct function): Add caller_disc field.
(call_callback): New static function.
(add_line): Add disc parameter.  Change all callers.  Store disc
in new line value.
(read_line_program): Track discriminator value.
(read_line_info): Initialize disc field in final line entry.
(read_function_entry): Handle DW_AT_GNU_discriminator.
(report_inlined_functions): Add disc parameter. Change all
callers. Call call_callback rather than calling callback
directly.
(dwarf_lookup_pc): Handle inlined discriminators. Call
call_callback rather than calling callback directly.
(dwarf_fileline): Call call_callback rather than calling callback
directly.
* elf.c (elf_syminfo): Pass moredata if requested.
* macho.c (macho_syminfo): Likewise.
* pecoff.c (coff_syminfo): Likewise.
* xcoff.c (xcoff_syminfo): Likewise.
(xcoff_lookup_pc): Likewise.
* backtrace.c: #include <string.h>.
(unwind): Pass moredata if requested.
* unknown.c: #include <string.h>.
(unknown_fileline): Pass moredata if requested.
* fileline.c (backtrace_syminfo_to_full_callback): Add comment
about moredata.
* mdtest.c: New test file.
* Makefile.am (mdtest_SOURCES): Define.
(mdtest_CFLAGS, mdtest_LDFLAGS, mdtest_LDADD): Define.
(BUILDTESTS): Add mdtest.
* Makefile.in: Regenerate.

15 files changed:
libbacktrace/Makefile.am
libbacktrace/Makefile.in
libbacktrace/backtrace-supported.h.in
libbacktrace/backtrace.c
libbacktrace/backtrace.h
libbacktrace/dwarf.c
libbacktrace/elf.c
libbacktrace/fileline.c
libbacktrace/internal.h
libbacktrace/macho.c
libbacktrace/mdtest.c [new file with mode: 0644]
libbacktrace/pecoff.c
libbacktrace/state.c
libbacktrace/unknown.c
libbacktrace/xcoff.c

index 3a58461cfc05a284e33c93410fcac5e0d022b621..c7bdd516016b4094e55c2973eb0243a3832edb97 100644 (file)
@@ -345,6 +345,13 @@ endif HAVE_OBJCOPY_DEBUGLINK
 
 endif HAVE_DWZ
 
+mdtest_SOURCES = mdtest.c testlib.c
+mdtest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O
+mdtest_LDFLAGS = $(libbacktrace_testing_ldflags)
+mdtest_LDADD = libbacktrace.la
+
+BUILDTESTS += mdtest
+
 stest_SOURCES = stest.c
 stest_CFLAGS = $(libbacktrace_TEST_CFLAGS)
 stest_LDFLAGS = $(libbacktrace_testing_ldflags)
index 50fe4be9686a88d4d946e7cb6d350191605e4d32..7530c1d4daa63bf8f683fccda7b83803d7b45f74 100644 (file)
@@ -138,7 +138,7 @@ TESTS = $(am__append_4) $(MAKETESTS) $(am__EXEEXT_17)
 @HAVE_BUILDID_TRUE@@HAVE_DWZ_TRUE@@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = b3test
 @HAVE_BUILDID_TRUE@@HAVE_DWZ_TRUE@@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_9 = b3test_dwz_buildid b3test_dwz_buildidfull
 @HAVE_ELF_TRUE@@NATIVE_TRUE@am__append_10 = btest_lto
-@NATIVE_TRUE@am__append_11 = btest_alloc stest stest_alloc
+@NATIVE_TRUE@am__append_11 = btest_alloc mdtest stest stest_alloc
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_12 = btest_dwz
 @HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_13 = btest_dwz_gnudebuglink
 @HAVE_ELF_TRUE@@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_14 = -lz
@@ -235,8 +235,8 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@  test_unknown$(EXEEXT) unittest$(EXEEXT) \
 @NATIVE_TRUE@  unittest_alloc$(EXEEXT) btest$(EXEEXT)
 @HAVE_ELF_TRUE@@NATIVE_TRUE@am__EXEEXT_6 = btest_lto$(EXEEXT)
-@NATIVE_TRUE@am__EXEEXT_7 = btest_alloc$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@  stest_alloc$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_7 = btest_alloc$(EXEEXT) mdtest$(EXEEXT) \
+@NATIVE_TRUE@  stest$(EXEEXT) stest_alloc$(EXEEXT)
 @HAVE_ELF_TRUE@@NATIVE_TRUE@am__EXEEXT_8 = ztest$(EXEEXT) \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   ztest_alloc$(EXEEXT) \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   zstdtest$(EXEEXT) \
@@ -396,6 +396,13 @@ m2test_OBJECTS = $(am_m2test_OBJECTS)
 m2test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(m2test_CFLAGS) $(CFLAGS) \
        $(m2test_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_TRUE@am_mdtest_OBJECTS = mdtest-mdtest.$(OBJEXT) \
+@NATIVE_TRUE@  mdtest-testlib.$(OBJEXT)
+mdtest_OBJECTS = $(am_mdtest_OBJECTS)
+@NATIVE_TRUE@mdtest_DEPENDENCIES = libbacktrace.la
+mdtest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mdtest_CFLAGS) $(CFLAGS) \
+       $(mdtest_LDFLAGS) $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_mtest_OBJECTS = mtest-mtest.$(OBJEXT) \
 @NATIVE_TRUE@  mtest-testlib.$(OBJEXT)
 mtest_OBJECTS = $(am_mtest_OBJECTS)
@@ -620,12 +627,13 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
        $(ctestg_alloc_SOURCES) $(ctestzstd_SOURCES) \
        $(ctestzstd_alloc_SOURCES) $(dwarf5_SOURCES) \
        $(dwarf5_alloc_SOURCES) $(edtest_SOURCES) \
-       $(edtest_alloc_SOURCES) $(m2test_SOURCES) $(mtest_SOURCES) \
-       $(stest_SOURCES) $(stest_alloc_SOURCES) $(test_elf_32_SOURCES) \
-       $(test_elf_64_SOURCES) $(test_macho_SOURCES) \
-       $(test_pecoff_SOURCES) $(test_unknown_SOURCES) \
-       $(test_xcoff_32_SOURCES) $(test_xcoff_64_SOURCES) \
-       $(ttest_SOURCES) $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
+       $(edtest_alloc_SOURCES) $(m2test_SOURCES) $(mdtest_SOURCES) \
+       $(mtest_SOURCES) $(stest_SOURCES) $(stest_alloc_SOURCES) \
+       $(test_elf_32_SOURCES) $(test_elf_64_SOURCES) \
+       $(test_macho_SOURCES) $(test_pecoff_SOURCES) \
+       $(test_unknown_SOURCES) $(test_xcoff_32_SOURCES) \
+       $(test_xcoff_64_SOURCES) $(ttest_SOURCES) \
+       $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
        $(unittest_alloc_SOURCES) $(xztest_SOURCES) \
        $(xztest_alloc_SOURCES) $(zstdtest_SOURCES) \
        $(zstdtest_alloc_SOURCES) $(ztest_SOURCES) \
@@ -1148,6 +1156,10 @@ libbacktrace_testing_ldflags = -no-install
 @NATIVE_TRUE@btest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS)
 @NATIVE_TRUE@btest_alloc_LDFLAGS = $(libbacktrace_testing_ldflags)
 @NATIVE_TRUE@btest_alloc_LDADD = libbacktrace_alloc.la
+@NATIVE_TRUE@mdtest_SOURCES = mdtest.c testlib.c
+@NATIVE_TRUE@mdtest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O
+@NATIVE_TRUE@mdtest_LDFLAGS = $(libbacktrace_testing_ldflags)
+@NATIVE_TRUE@mdtest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_CFLAGS = $(libbacktrace_TEST_CFLAGS)
 @NATIVE_TRUE@stest_LDFLAGS = $(libbacktrace_testing_ldflags)
@@ -1445,6 +1457,10 @@ m2test$(EXEEXT): $(m2test_OBJECTS) $(m2test_DEPENDENCIES) $(EXTRA_m2test_DEPENDE
        @rm -f m2test$(EXEEXT)
        $(AM_V_CCLD)$(m2test_LINK) $(m2test_OBJECTS) $(m2test_LDADD) $(LIBS)
 
+mdtest$(EXEEXT): $(mdtest_OBJECTS) $(mdtest_DEPENDENCIES) $(EXTRA_mdtest_DEPENDENCIES) 
+       @rm -f mdtest$(EXEEXT)
+       $(AM_V_CCLD)$(mdtest_LINK) $(mdtest_OBJECTS) $(mdtest_LDADD) $(LIBS)
+
 mtest$(EXEEXT): $(mtest_OBJECTS) $(mtest_DEPENDENCIES) $(EXTRA_mtest_DEPENDENCIES) 
        @rm -f mtest$(EXEEXT)
        $(AM_V_CCLD)$(mtest_LINK) $(mtest_OBJECTS) $(mtest_LDADD) $(LIBS)
@@ -1756,6 +1772,18 @@ m2test-testlib.o: testlib.c
 m2test-testlib.obj: testlib.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(m2test_CFLAGS) $(CFLAGS) -c -o m2test-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
 
+mdtest-mdtest.o: mdtest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mdtest_CFLAGS) $(CFLAGS) -c -o mdtest-mdtest.o `test -f 'mdtest.c' || echo '$(srcdir)/'`mdtest.c
+
+mdtest-mdtest.obj: mdtest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mdtest_CFLAGS) $(CFLAGS) -c -o mdtest-mdtest.obj `if test -f 'mdtest.c'; then $(CYGPATH_W) 'mdtest.c'; else $(CYGPATH_W) '$(srcdir)/mdtest.c'; fi`
+
+mdtest-testlib.o: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mdtest_CFLAGS) $(CFLAGS) -c -o mdtest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+mdtest-testlib.obj: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mdtest_CFLAGS) $(CFLAGS) -c -o mdtest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 mtest-mtest.o: mtest.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mtest_CFLAGS) $(CFLAGS) -c -o mtest-mtest.o `test -f 'mtest.c' || echo '$(srcdir)/'`mtest.c
 
@@ -2354,6 +2382,13 @@ btest_alloc.log: btest_alloc$(EXEEXT)
        --log-file $$b.log --trs-file $$b.trs \
        $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
        "$$tst" $(AM_TESTS_FD_REDIRECT)
+mdtest.log: mdtest$(EXEEXT)
+       @p='mdtest$(EXEEXT)'; \
+       b='mdtest'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
 stest.log: stest$(EXEEXT)
        @p='stest$(EXEEXT)'; \
        b='stest'; \
index 456c329f85dc2ed4cdb02e2f38c1b0e6001e4be1..e5ecf87f46a12dbe5a614787a6a21bad18ad97b9 100644 (file)
@@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE.  */
    be #include'd to see whether the backtrace library will be able to
    get a backtrace and produce symbolic information.  */
 
-
 /* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
    should work, 0 if it will not.  Libraries may #include this to make
    other arrangements.  */
@@ -60,7 +59,12 @@ POSSIBILITY OF SUCH DAMAGE.  */
 
 #define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@
 
-/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
+/* BACKTRACE_SUPPORTS_DATA will be #define'd as 1 if the backtrace_syminfo
    will work for variables.  It will always work for functions.  */
 
 #define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@
+
+/* BACKTRACE_SUPPORTS_MOREDATA will be #define'd as 1 if
+   backtrace_create_state supports setting the MOREDATA flag.  */
+
+#define BACKTRACE_SUPPORTS_MOREDATA 1
index 3935a3ed968280aca362605d223c9b5f63dcbf68..b4261c438c4622fd94c02b75cc4969edbee0c5f8 100644 (file)
@@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.  */
 
 #include "config.h"
 
+#include <string.h>
 #include <sys/types.h>
 
 #include "unwind.h"
@@ -85,11 +86,24 @@ unwind (struct _Unwind_Context *context, void *vdata)
   if (!ip_before_insn)
     --pc;
 
-  if (!bdata->can_alloc)
-    bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
-  else
+  if (bdata->can_alloc)
     bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
                                   bdata->error_callback, bdata->data);
+  else
+    {
+      if (!bdata->state->moredata)
+       bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
+      else
+       {
+         struct backtrace_moredata md;
+
+         memset (&md, 0, sizeof md);
+         md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
+         md.backtrace_data = bdata->data;
+         bdata->ret = bdata->callback (&md, pc, NULL, 0, NULL);
+       }
+    }
+
   if (bdata->ret != 0)
     return _URC_END_OF_STACK;
 
index fd0c659decc68b4df9bffae91a0b59e3149122b1..9ca12730a7c3b718b8ade4fcb93dde965eeda347 100644 (file)
@@ -85,15 +85,41 @@ typedef void (*backtrace_error_callback) (void *data, const char *msg,
 
 /* Create state information for the backtrace routines.  This must be
    called before any of the other routines, and its return value must
-   be passed to all of the other routines.  FILENAME is the path name
-   of the executable file; if it is NULL the library will try
-   system-specific path names.  If not NULL, FILENAME must point to a
-   permanent buffer.  If THREADED is non-zero the state may be
-   accessed by multiple threads simultaneously, and the library will
-   use appropriate atomic operations.  If THREADED is zero the state
-   may only be accessed by one thread at a time.  This returns a state
-   pointer on success, NULL on error.  If an error occurs, this will
-   call the ERROR_CALLBACK routine.
+   be passed to all of the other routines.
+
+   FILENAME is the path name of the executable file; if it is NULL the
+   library will try system-specific path names.  If not NULL, FILENAME
+   must point to a permanent buffer.
+
+   FLAGS passes flags as bits in an int value:
+   1: THREADED
+   2: MOREDATA
+
+   If (FLAGS & 1) != 0 the THREADED flag is set.  If this flag is set,
+   the state may be accessed by multiple threads simultaneously, and the
+   library will use appropriate atomic operations.  If THREADED is not
+   set the state may only be accessed by one thread at a time.
+
+   If (FLAGS & 2) != 0 the MOREDATA flag is set.  If this flag is set,
+   then backtrace_full_callback and backtrace_symbol_callback will not
+   pass the DATA argument as the user-specified DATA value, but will
+   instead pass it as a pointer to a backtrace_moredata struct.  This is
+   a backward compatible approach to getting more data from the various
+   backtrace functions.
+
+   Historical note: in previous versions (before July, 2026) the FLAGS
+   argument was named THREADED, and passing non-zero for THREADED was
+   documented as doing what setting the THREADED flag does today.  In
+   practice all callers passed either 0 or 1, so the new semantics of
+   the flag do not affect users of old versions of the library.
+   However, code that passes the MOREDATA flag must ensure that it is
+   using a new version of the library.  The backtrace-supported.h file
+   will #define BACKTRACE_SUPPORTS_MOREDATA as 1 for versions of
+   libbacktrace that support the MOREDATA flag.
+
+   The backtrace_create_state function returns a state pointer on
+   success, NULL on error.  If an error occurs, it will call the
+   ERROR_CALLBACK routine before returning.
 
    Calling this function allocates resources that cannot be freed.
    There is no backtrace_free_state function.  The state is used to
@@ -106,13 +132,15 @@ extern struct backtrace_state *backtrace_create_state (
     backtrace_error_callback error_callback, void *data);
 
 /* The type of the callback argument to the backtrace_full function.
-   DATA is the argument passed to backtrace_full.  PC is the program
-   counter.  FILENAME is the name of the file containing PC, or NULL
-   if not available.  LINENO is the line number in FILENAME containing
-   PC, or 0 if not available.  FUNCTION is the name of the function
-   containing PC, or NULL if not available.  This should return 0 to
-   continuing tracing.  The FILENAME and FUNCTION buffers may become
-   invalid after this function returns.  */
+   DATA is either the argument passed to backtrace_full (if the MOREDATA
+   flag was not set when calling backtrace_create_state) or a pointer to
+   a backtrace_moredata struct.  PC is the program counter.  FILENAME is
+   the name of the file containing PC, or NULL if not available.  LINENO
+   is the line number in FILENAME containing PC, or 0 if not available.
+   FUNCTION is the name of the function containing PC, or NULL if not
+   available.  This should return 0 to continuing tracing.  The FILENAME
+   and FUNCTION buffers may become invalid after this function
+   returns.  */
 
 typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
                                        const char *filename, int lineno,
@@ -173,11 +201,14 @@ extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
                             backtrace_error_callback error_callback,
                             void *data);
 
-/* The type of the callback argument to backtrace_syminfo.  DATA and
-   PC are the arguments passed to backtrace_syminfo.  SYMNAME is the
-   name of the symbol for the corresponding code.  SYMVAL is the
-   value and SYMSIZE is the size of the symbol.  SYMNAME will be NULL
-   if no error occurred but the symbol could not be found.  */
+/* The type of the callback argument to backtrace_syminfo.  DATA is
+   either the argument passed to backtrace_full (if the MOREDATA flag
+   was not set when calling backtrace_create_state) or a pointer to a
+   backtrace_moredata struct.  PC is the the argument passed to
+   backtrace_syminfo.  SYMNAME is the name of the symbol for the
+   corresponding code.  SYMVAL is the value and SYMSIZE is the size of
+   the symbol.  SYMNAME will be NULL if no error occurred but the symbol
+   could not be found.  */
 
 typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
                                            const char *symname,
@@ -199,6 +230,31 @@ extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,
                              backtrace_error_callback error_callback,
                              void *data);
 
+/* The type of the value that the DATA argument passed to
+   backtrace_full_callback or backtrace_syminfo_callback points to if
+   the MOREDATA flag is set in the call to backtrace_create_state.
+
+   The backtrace_moredata value will only be valid for the lifetime of
+   the callback; the callback may copy the data out but must not save
+   the pointer it receives.  */
+
+struct backtrace_moredata
+{
+  /* The version of this struct. The current expectation is that the
+     version number will be the number of fields in the struct. It's
+     possible that future versions of libbacktrace will add new fields
+     and increment the version number accordingly. There is no plan to
+     remove fields from this struct.  Thus the current value of the
+     version field will be 3.  */
+  int backtrace_version;
+  /* The DATA value passed to whatever function is calling the callback
+     (backtrace_full, backtrace_pcinfo, or backtrace_syminfo).  */
+  void *backtrace_data;
+  /* The DWARF discriminator.  This is zero if there is none. See
+     https://wiki.dwarfstd.org/Path_Discriminators.md.  */
+  unsigned int backtrace_discriminator;
+};
+
 #ifdef __cplusplus
 } /* End extern "C".  */
 #endif
index ecf32f7688b284315bcf2e0e3754bb5c61245eeb..0d29443d7aa43b6a875a83fa330283850daffd0f 100644 (file)
@@ -234,6 +234,8 @@ struct line
   const char *filename;
   /* Line number.  */
   int lineno;
+  /* Discriminator.  */
+  int disc;
   /* Index of the object in the original array read from the DWARF
      section, before it has been sorted.  The index makes it possible
      to use Quicksort and maintain stability.  */
@@ -263,6 +265,9 @@ struct function
   /* If this is an inlined function, the line number of the call
      site.  */
   int caller_lineno;
+  /* If this is an inlined function, the discriminator of the call
+     site.  */
+  unsigned int caller_disc;
   /* Map PC ranges to inlined functions.  */
   struct function_addrs *function_addrs;
   size_t function_addrs_count;
@@ -726,6 +731,28 @@ read_initial_length (struct dwarf_buf *buf, int *is_dwarf64)
   return len;
 }
 
+/* Call the callback function, which differs based on the moredata state
+   flag.  */
+
+static int
+call_callback (struct backtrace_state *state, backtrace_full_callback callback,
+              void *data, uintptr_t pc, const char *filename, int lineno,
+              const char *function, unsigned int disc)
+{
+  if (!state->moredata)
+    return callback (data, pc, filename, lineno, function);
+  else
+    {
+      struct backtrace_moredata md;
+
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
+      md.backtrace_data = data;
+      md.backtrace_discriminator = disc;
+      return callback ((void *) &md, pc, filename, lineno, function);
+    }
+}
+
 /* Free an abbreviations structure.  */
 
 static void
@@ -2484,7 +2511,7 @@ build_address_map (struct backtrace_state *state,
 
 static int
 add_line (struct backtrace_state *state, struct dwarf_data *ddata,
-         uintptr_t pc, const char *filename, int lineno,
+         uintptr_t pc, const char *filename, int lineno, int disc,
          backtrace_error_callback error_callback, void *data,
          struct line_vector *vec)
 {
@@ -2496,7 +2523,13 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata,
     {
       ln = (struct line *) vec->vec.base + (vec->count - 1);
       if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
-       return 1;
+       {
+         /* We only care about the discriminator if moredata is true.  */
+         if (!state->moredata)
+           return 1;
+         if (disc == ln->disc)
+           return 1;
+       }
     }
 
   ln = ((struct line *)
@@ -2511,6 +2544,7 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata,
 
   ln->filename = filename;
   ln->lineno = lineno;
+  ln->disc = disc;
   ln->idx = vec->count;
 
   ++vec->count;
@@ -2929,6 +2963,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
   const char *reset_filename;
   const char *filename;
   int lineno;
+  unsigned int disc;
 
   address = 0;
   op_index = 0;
@@ -2938,6 +2973,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
     reset_filename = "";
   filename = reset_filename;
   lineno = 1;
+  disc = 0;
   while (line_buf->left > 0)
     {
       unsigned int op;
@@ -2954,8 +2990,9 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
                      / hdr->max_ops_per_insn);
          op_index = (op_index + advance) % hdr->max_ops_per_insn;
          lineno += hdr->line_base + (int) (op % hdr->line_range);
-         add_line (state, ddata, address, filename, lineno,
+         add_line (state, ddata, address, filename, lineno, disc,
                    line_buf->error_callback, line_buf->data, vec);
+         disc = 0;
        }
       else if (op == DW_LNS_extended_op)
        {
@@ -2973,6 +3010,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
              op_index = 0;
              filename = reset_filename;
              lineno = 1;
+             disc = 0;
              break;
            case DW_LNE_set_address:
              address = read_address (line_buf, hdr->addrsize);
@@ -3028,8 +3066,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
              }
              break;
            case DW_LNE_set_discriminator:
-             /* We don't care about discriminators.  */
-             read_uleb128 (line_buf);
+             disc = read_uleb128 (line_buf);
              break;
            default:
              if (!advance (line_buf, len - 1))
@@ -3042,8 +3079,9 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
          switch (op)
            {
            case DW_LNS_copy:
-             add_line (state, ddata, address, filename, lineno,
+             add_line (state, ddata, address, filename, lineno, disc,
                        line_buf->error_callback, line_buf->data, vec);
+             disc = 0;
              break;
            case DW_LNS_advance_pc:
              {
@@ -3183,6 +3221,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
   ln->pc = (uintptr_t) -1;
   ln->filename = NULL;
   ln->lineno = 0;
+  ln->disc = 0;
   ln->idx = 0;
 
   if (!backtrace_vector_release (state, &vec.vec, error_callback, data))
@@ -3512,6 +3551,11 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
                    }
                  break;
 
+               case DW_AT_GNU_discriminator:
+                 if (val.encoding == ATTR_VAL_UINT)
+                   function->caller_disc = val.u.uint;
+                 break;
+
                case DW_AT_call_line:
                  if (val.encoding == ATTR_VAL_UINT)
                    function->caller_lineno = val.u.uint;
@@ -3752,13 +3796,15 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata,
 }
 
 /* See if PC is inlined in FUNCTION.  If it is, print out the inlined
-   information, and update FILENAME and LINENO for the caller.
+   information, and update FILENAME, LINENO, and DISC for the caller.
    Returns whatever CALLBACK returns, or 0 to keep going.  */
 
 static int
-report_inlined_functions (uintptr_t pc, struct function *function,
+report_inlined_functions (struct backtrace_state *state, uintptr_t pc,
+                         struct function *function,
                          backtrace_full_callback callback, void *data,
-                         const char **filename, int *lineno)
+                         const char **filename, int *lineno,
+                         unsigned int *disc)
 {
   struct function_addrs *p;
   struct function_addrs *match;
@@ -3810,20 +3856,22 @@ report_inlined_functions (uintptr_t pc, struct function *function,
   inlined = match->function;
 
   /* Report any calls inlined into this one.  */
-  ret = report_inlined_functions (pc, inlined, callback, data,
-                                 filename, lineno);
+  ret = report_inlined_functions (state, pc, inlined, callback, data,
+                                 filename, lineno, disc);
   if (ret != 0)
     return ret;
 
   /* Report this inlined call.  */
-  ret = callback (data, pc, *filename, *lineno, inlined->name);
+  ret = call_callback (state, callback, data, pc, *filename, *lineno,
+                      inlined->name, *disc);
   if (ret != 0)
     return ret;
 
   /* Our caller will report the caller of the inlined function; tell
-     it the appropriate filename and line number.  */
+     it the appropriate filename, line number, and discriminator.  */
   *filename = inlined->caller_filename;
   *lineno = inlined->caller_lineno;
+  *disc = inlined->caller_disc;
 
   return 0;
 }
@@ -3850,6 +3898,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
   struct function *function;
   const char *filename;
   int lineno;
+  unsigned int disc;
   int ret;
 
   *found = 1;
@@ -3991,7 +4040,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
       if (new_data)
        return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
                                data, found);
-      return callback (data, pc, NULL, 0, NULL);
+      return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
     }
 
   /* Search for PC within this unit.  */
@@ -4038,13 +4087,15 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
          entry->u->abs_filename = filename;
        }
 
-      return callback (data, pc, entry->u->abs_filename, 0, NULL);
+      return call_callback (state, callback, data, pc, entry->u->abs_filename,
+                           0, NULL, 0);
     }
 
   /* Search for function name within this unit.  */
 
   if (entry->u->function_addrs_count == 0)
-    return callback (data, pc, ln->filename, ln->lineno, NULL);
+    return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
+                         NULL, ln->disc);
 
   p = ((struct function_addrs *)
        bsearch (&pc, entry->u->function_addrs,
@@ -4052,7 +4103,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
                sizeof (struct function_addrs),
                function_addrs_search));
   if (p == NULL)
-    return callback (data, pc, ln->filename, ln->lineno, NULL);
+    return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
+                         NULL, ln->disc);
 
   /* Here pc >= p->low && pc < (p + 1)->low.  The function_addrs are
      sorted by low, so if pc > p->low we are at the end of a range of
@@ -4076,19 +4128,22 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
       --p;
     }
   if (fmatch == NULL)
-    return callback (data, pc, ln->filename, ln->lineno, NULL);
+    return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
+                         NULL, ln->disc);
 
   function = fmatch->function;
 
   filename = ln->filename;
   lineno = ln->lineno;
+  disc = ln->disc;
 
-  ret = report_inlined_functions (pc, function, callback, data,
-                                 &filename, &lineno);
+  ret = report_inlined_functions (state, pc, function, callback, data,
+                                 &filename, &lineno, &disc);
   if (ret != 0)
     return ret;
 
-  return callback (data, pc, filename, lineno, function->name);
+  return call_callback (state, callback, data, pc, filename, lineno,
+                       function->name, disc);
 }
 
 
@@ -4138,7 +4193,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
 
   /* FIXME: See if any libraries have been dlopen'ed.  */
 
-  return callback (data, pc, NULL, 0, NULL);
+  return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
 }
 
 /* Initialize our data structures from the DWARF debug info for a
index e1c34584578d553c925c13598c5799f225b4537c..60489327024d2c9655f17681067d8b9981c09dfb 100644 (file)
@@ -767,6 +767,8 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
 {
   struct elf_syminfo_data *edata;
   struct elf_symbol *sym = NULL;
+  void *mdata;
+  struct backtrace_moredata md;
 
   if (!state->threaded)
     {
@@ -802,10 +804,20 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
        }
     }
 
+  if (!state->moredata)
+    mdata = data;
+  else
+    {
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
+      md.backtrace_data = data;
+      mdata = (void *) &md;
+    }
+
   if (sym == NULL)
-    callback (data, addr, NULL, 0, 0);
+    callback (mdata, addr, NULL, 0, 0);
   else
-    callback (data, addr, sym->name, sym->address, sym->size);
+    callback (mdata, addr, sym->name, sym->address, sym->size);
 }
 
 /* Return whether FILENAME is a symlink.  */
index 82535e3f6cfb38adac853509ef5bf296b49cb145..18bd87d65b36a0cd626dd2271882908cdd82018d 100644 (file)
@@ -425,6 +425,9 @@ 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);
 }
 
index 09a2147fdef1db10f424528fb06e8b33b1e0e23d..355d2a353feea3737c236ecf55016376efbcb5ad 100644 (file)
@@ -143,6 +143,8 @@ struct backtrace_state
   const char *filename;
   /* Non-zero if threaded.  */
   int threaded;
+  /* Non-zero if passing additional data.  */
+  int moredata;
   /* The master lock for fileline_fn, fileline_data, syminfo_fn,
      syminfo_data, fileline_initialization_failed and everything the
      data pointers point to.  */
@@ -425,4 +427,7 @@ extern int backtrace_uncompress_lzma (struct backtrace_state *,
                                      unsigned char **uncompressed,
                                      size_t *uncompressed_size);
 
+/* Current expected backtrace_moredata version.  */
+#define BACKTRACE_MOREDATA_VERSION (3)
+
 #endif
index 5eab4a6c7f85a74ff70c344199b16374c518c210..5a951aadf42292384acbbc88aab6c61fcd44e728 100644 (file)
@@ -711,6 +711,8 @@ macho_syminfo (struct backtrace_state *state, uintptr_t addr,
 {
   struct macho_syminfo_data *sdata;
   struct macho_symbol *sym;
+  void *mdata;
+  struct backtrace_moredata md;
 
   sym = NULL;
   if (!state->threaded)
@@ -747,10 +749,20 @@ macho_syminfo (struct backtrace_state *state, uintptr_t addr,
        }
     }
 
+  if (!state->moredata)
+    mdata = data;
+  else
+    {
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
+      md.backtrace_data = data;
+      mdata = (void *) &md;
+    }
+
   if (sym == NULL)
-    callback (data, addr, NULL, 0, 0);
+    callback (mdata, addr, NULL, 0, 0);
   else
-    callback (data, addr, sym->name, sym->address, 0);
+    callback (mdata, addr, sym->name, sym->address, 0);
 }
 
 /* Look through a fat file to find the relevant executable.  Returns 1
diff --git a/libbacktrace/mdtest.c b/libbacktrace/mdtest.c
new file mode 100644 (file)
index 0000000..5f6665f
--- /dev/null
@@ -0,0 +1,290 @@
+/* mdtest.c -- Test for libbacktrace library with moredata flag
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* This program tests the externally visible interfaces of the
+   libbacktrace library.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+#include "internal.h"
+
+#include "testlib.h"
+
+/* backtrace_full_callback with moredata flag.  */
+
+static int
+md_callback_one (void *vdata, uintptr_t pc, const char *filename, int lineno,
+                const char *function)
+{
+  struct backtrace_moredata *md = (struct backtrace_moredata *) vdata;
+  struct bdata *data = (struct bdata *) md->backtrace_data;
+
+  if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
+    {
+      fprintf (stderr, "md_callback_one: wrong moredata version: got %u, want %u\n", md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
+      data->failed = 1;
+      return 1;
+    }
+
+  return callback_one ((void *) data, pc, filename, lineno, function);
+}
+
+/* backtrace_syminfo_callback with moredata flag.  */
+
+static void
+md_callback_three (void *vdata, uintptr_t pc, const char *symname,
+                 uintptr_t symval, uintptr_t symsize)
+{
+  struct backtrace_moredata *md = (struct backtrace_moredata *) vdata;
+  struct symdata *data = (struct symdata *) md->backtrace_data;
+
+  if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
+    {
+      fprintf (stderr, "md_callback_one: wrong moredata version: got %u, want %u\n", md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
+      return;
+    }
+
+  callback_three ((void *) data, pc, symname, symval, symsize);
+}
+
+/* Test the backtrace function with non-inlined functions.  */
+
+static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused));
+static int f2 (int) __attribute__ ((noinline, noclone));
+static int f3 (int, int) __attribute__ ((noinline, noclone));
+
+static int
+test1 (void)
+{
+  /* Returning a value here and elsewhere avoids a tailcall which
+     would mess up the backtrace.  */
+  return f2 (__LINE__) + 1;
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line, int f2line)
+{
+  struct info all[20];
+  struct bdata data;
+  int f3line;
+  int i;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (data.index < 3)
+    {
+      fprintf (stderr,
+              "test1: not enough frames; got %zu, expected at least 3\n",
+              data.index);
+      data.failed = 1;
+    }
+
+  check ("test1", 0, all, f3line, "f3", "mdtest.c", &data.failed);
+  check ("test1", 1, all, f2line, "f2", "mdtest.c", &data.failed);
+  check ("test1", 2, all, f1line, "test1", "mdtest.c", &data.failed);
+
+  printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Test the backtrace function with inlined functions.  */
+
+static inline int test2 (void) __attribute__ ((always_inline, unused));
+static inline int f12 (int) __attribute__ ((always_inline));
+static inline int f13 (int, int) __attribute__ ((always_inline));
+
+static inline int
+test2 (void)
+{
+  return f12 (__LINE__) + 1;
+}
+
+static inline int
+f12 (int f1line)
+{
+  return f13 (f1line, __LINE__) + 2;
+}
+
+static inline int
+f13 (int f1line, int f2line)
+{
+  struct info all[20];
+  struct bdata data;
+  int f3line;
+  int i;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  f3line = __LINE__ + 1;
+  i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test2: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  check ("test2", 0, all, f3line, "f13", "mdtest.c", &data.failed);
+  check ("test2", 1, all, f2line, "f12", "mdtest.c", &data.failed);
+  check ("test2", 2, all, f1line, "test2", "mdtest.c", &data.failed);
+
+  printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+static int test5 (void) __attribute__ ((unused));
+
+int global = 1;
+
+static int
+test5 (void)
+{
+  struct symdata symdata;
+  int i;
+  uintptr_t addr = (uintptr_t) &global;
+
+  if (sizeof (global) > 1)
+    addr += 1;
+
+  symdata.name = NULL;
+  symdata.val = 0;
+  symdata.size = 0;
+  symdata.failed = 0;
+
+  i = backtrace_syminfo (state, addr, md_callback_three,
+                        error_callback_three, &symdata);
+  if (i == 0)
+    {
+      fprintf (stderr,
+              "test5: unexpected return value from backtrace_syminfo %d\n",
+              i);
+      symdata.failed = 1;
+    }
+
+  if (!symdata.failed)
+    {
+      if (symdata.name == NULL)
+       {
+         fprintf (stderr, "test5: NULL syminfo name\n");
+         symdata.failed = 1;
+       }
+      else if (!(strncmp (symdata.name, "global", 6) == 0
+                && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo name got %s expected %s\n",
+                  symdata.name, "global");
+         symdata.failed = 1;
+       }
+      else if (symdata.val != (uintptr_t) &global)
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo value got %lx expected %lx\n",
+                  (unsigned long) symdata.val,
+                  (unsigned long) (uintptr_t) &global);
+         symdata.failed = 1;
+       }
+      else if (symdata.size != sizeof (global) && symdata.size != 0)
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo size got %lx expected %lx\n",
+                  (unsigned long) symdata.size,
+                  (unsigned long) sizeof (global));
+         symdata.failed = 1;
+       }
+    }
+
+  printf ("%s: backtrace_syminfo variable\n",
+         symdata.failed ? "FAIL" : "PASS");
+
+  if (symdata.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Run all the tests.  */
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS | 2,
+                                 error_callback_create, NULL);
+
+#if BACKTRACE_SUPPORTED
+  test1 ();
+  test2 ();
+#if BACKTRACE_SUPPORTS_DATA
+  test5 ();
+#endif
+#endif
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
index f2b1aa5023ab455a8e78e444ae5b104c51b137bf..08ec4c2ba138024ef7efae81e06df3c151526ba5 100644 (file)
@@ -587,6 +587,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr,
 {
   struct coff_syminfo_data *sdata;
   struct coff_symbol *sym = NULL;
+  void *mdata;
+  struct backtrace_moredata md;
 
   if (!state->threaded)
     {
@@ -622,10 +624,20 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr,
        }
     }
 
+  if (!state->moredata)
+    mdata = data;
+  else
+    {
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = 3;
+      md.backtrace_data = data;
+      mdata = (void *) &md;
+    }
+
   if (sym == NULL)
-    callback (data, addr, NULL, 0, 0);
+    callback (mdata, addr, NULL, 0, 0);
   else
-    callback (data, addr, sym->name, sym->address, 0);
+    callback (mdata, addr, sym->name, sym->address, 0);
 }
 
 /* Add the backtrace data for one PE/COFF file.  Returns 1 on success,
index 8c20162400620362aee6445720f2939bc58ed60f..491a14dc15603f0b9e4bd666724834532314038b 100644 (file)
@@ -43,13 +43,23 @@ POSSIBILITY OF SUCH DAMAGE.  */
    other routines.  */
 
 struct backtrace_state *
-backtrace_create_state (const char *filename, int threaded,
+backtrace_create_state (const char *filename, int flags,
                        backtrace_error_callback error_callback,
                        void *data)
 {
+  int threaded;
+  int moredata;
   struct backtrace_state init_state;
   struct backtrace_state *state;
 
+  threaded = (flags & 1) != 0;
+  moredata = (flags & 2) != 0;
+  if ((flags & ~3) != 0)
+    {
+      error_callback (data, "backtrace_create_state: unsupported flag", 0);
+      return NULL;
+    }
+
 #ifndef HAVE_SYNC_FUNCTIONS
   if (threaded)
     {
@@ -61,6 +71,7 @@ backtrace_create_state (const char *filename, int threaded,
   memset (&init_state, 0, sizeof init_state);
   init_state.filename = filename;
   init_state.threaded = threaded;
+  init_state.moredata = moredata;
 
   state = ((struct backtrace_state *)
           backtrace_alloc (&init_state, sizeof *state, error_callback, data));
index 4834ec92c182a7d7cfd90efe0d8229cf143e27ff..80dc19d640d7c55ea4c457a30697071b5b022b72 100644 (file)
@@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.  */
 
 #include "config.h"
 
+#include <string.h>
 #include <sys/types.h>
 
 #include "backtrace.h"
@@ -40,13 +41,23 @@ POSSIBILITY OF SUCH DAMAGE.  */
 /* A trivial routine that always fails to find fileline data.  */
 
 static int
-unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED,
-                 uintptr_t pc, backtrace_full_callback callback,
+unknown_fileline (struct backtrace_state *state, uintptr_t pc,
+                 backtrace_full_callback callback,
                  backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
                  void *data)
 
 {
-  return callback (data, pc, NULL, 0, NULL);
+  if (!state->moredata)
+    return callback (data, pc, NULL, 0, NULL);
+  else
+    {
+      struct backtrace_moredata md;
+
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = 3;
+      md.backtrace_data = data;
+      return callback ((void *) &md, pc, NULL, 0, NULL);
+    }
 }
 
 /* Initialize the backtrace data when we don't know how to read the
index 874642ab35482862320366282ca39224066e5086..43f7839876253ca2b844f2c2984c2bf6434d3967 100644 (file)
@@ -512,6 +512,8 @@ xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
   struct xcoff_syminfo_data *edata;
   struct xcoff_symbol *sym = NULL;
   const char *name;
+  void *mdata;
+  struct backtrace_moredata md;
 
   if (!state->threaded)
     {
@@ -547,15 +549,25 @@ xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
        }
     }
 
+  if (!state->moredata)
+    mdata = data;
+  else
+    {
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = 3;
+      md.backtrace_data = data;
+      mdata = (void *) &md;
+    }
+
   if (sym == NULL)
-    callback (data, addr, NULL, 0, 0);
+    callback (mdata, addr, NULL, 0, 0);
   else
     {
       name = sym->name;
       /* AIX prepends a '.' to function entry points, remove it.  */
       if (name && *name == '.')
        ++name;
-      callback (data, addr, name, sym->address, sym->size);
+      callback (mdata, addr, name, sym->address, sym->size);
     }
 }
 
@@ -723,7 +735,7 @@ xcoff_incl_search (const void *vkey, const void *ventry)
    0 if not.  */
 
 static int
-xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
+xcoff_lookup_pc (struct backtrace_state *state,
                 struct xcoff_fileline_data *fdata, uintptr_t pc,
                 backtrace_full_callback callback,
                 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
@@ -805,7 +817,18 @@ xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
   /* AIX prepends a '.' to function entry points, remove it.  */
   if (function != NULL && *function == '.')
     ++function;
-  return callback (data, pc, filename, lnno, function);
+
+  if (!state->moredata)
+    return callback (data, pc, filename, lnno, function);
+  else
+    {
+      struct backtrace_moredata md;
+
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = 3;
+      md.backtrace_data = data;
+      return callback ((void *) &md, pc, filename, lnno, function);
+    }
 }
 
 /* Return the file/line information for a PC using the XCOFF lineno
@@ -855,7 +878,17 @@ xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
 
   /* FIXME: See if any libraries have been dlopen'ed.  */
 
-  return callback (data, pc, NULL, 0, NULL);
+  if (!state->moredata)
+    return callback (data, pc, NULL, 0, NULL);
+  else
+    {
+      struct backtrace_moredata md;
+
+      memset (&md, 0, sizeof md);
+      md.backtrace_version = 3;
+      md.backtrace_data = data;
+      return callback ((void *) data, pc, NULL, 0, NULL);
+    }
 }
 
 /* Initialize the function vector info for xcoff_fileline.  */