I've committed this libbacktrace patch to add support for returning
the discriminator field in the callback. I've changed the "threaded"
parameter to backtrace_create_state into a "flags" parameter, with the
low bit indicating threaded. This isn't strictly backward compatible,
but will work with the values 0 and 1, which in practice were the only
values that were ever used. The next bit now indicates that more data
should be returned to the callback. The only additional data at
present is the discriminator.

This is based on a patch by Andi Kleen. That patch actually supports
decl_line as well. I've committed this patch to include the basic
framework, and we can then add in decl_line as seems best.

Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu.
Committed to mainline.

Ian

* 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.
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 3a58461cfc0..c7bdd516016 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -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)
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 50fe4be9686..7530c1d4daa 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -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'; \
diff --git a/libbacktrace/backtrace-supported.h.in 
b/libbacktrace/backtrace-supported.h.in
index 456c329f85d..e5ecf87f46a 100644
--- a/libbacktrace/backtrace-supported.h.in
+++ b/libbacktrace/backtrace-supported.h.in
@@ -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
diff --git a/libbacktrace/backtrace.c b/libbacktrace/backtrace.c
index 3935a3ed968..b4261c438c4 100644
--- a/libbacktrace/backtrace.c
+++ b/libbacktrace/backtrace.c
@@ -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;
 
diff --git a/libbacktrace/backtrace.h b/libbacktrace/backtrace.h
index fd0c659decc..9ca12730a7c 100644
--- a/libbacktrace/backtrace.h
+++ b/libbacktrace/backtrace.h
@@ -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
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index ecf32f7688b..0d29443d7aa 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -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
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index e1c34584578..60489327024 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -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.  */
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 82535e3f6cf..18bd87d65b3 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -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);
 }
 
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 09a2147fdef..355d2a353fe 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -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
diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c
index 5eab4a6c7f8..5a951aadf42 100644
--- a/libbacktrace/macho.c
+++ b/libbacktrace/macho.c
@@ -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
index 00000000000..5f6665f1e2b
--- /dev/null
+++ b/libbacktrace/mdtest.c
@@ -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);
+}
diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index f2b1aa5023a..08ec4c2ba13 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -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,
diff --git a/libbacktrace/state.c b/libbacktrace/state.c
index 8c201624006..491a14dc156 100644
--- a/libbacktrace/state.c
+++ b/libbacktrace/state.c
@@ -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));
diff --git a/libbacktrace/unknown.c b/libbacktrace/unknown.c
index 4834ec92c18..80dc19d640d 100644
--- a/libbacktrace/unknown.c
+++ b/libbacktrace/unknown.c
@@ -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
diff --git a/libbacktrace/xcoff.c b/libbacktrace/xcoff.c
index 874642ab354..43f78398762 100644
--- a/libbacktrace/xcoff.c
+++ b/libbacktrace/xcoff.c
@@ -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.  */

Reply via email to