From: Andi Kleen <[email protected]>

Reworked patch based on a more compatible interface from Ian Lance
Taylor.

This allows tools to access discriminator and decl_line to resolve
inline stacks for autofdo.

libbacktrace/ChangeLog:

        Andi Kleen <[email protected]>
        Ian Lance Taylor <[email protected]>
        * backtrace-supported.h.in (BACKTRACE_SUPPORTS_MOREDATA): New.
        * backtrace.c (unwind): Handle moredata callback.
        * backtrace.h (backtrace_pcinfo): Dito.
        (struct backtrace_moredata): New interface.
        * dwarf.c (struct line): Add disc field.
        (struct function): Add caller_disc and decl_line.
        (add_line): Handle discriminator.
        (read_line_program): Dito.
        (read_line_info): Dito.
        (read_referenced_name): Handle decl_line.
        (read_referenced_name_from_attr): Handle discriminator and
        decl_line.
        (read_function_entry): Dito.
        (report_inlined_functions): Handle moredata callback.
        (dwarf_lookup_pc): Dito.
        (dwarf_fileline): Dito.
        * fileline.c (backtrace_pcinfo): Add moredata.
        (backtrace_syminfo): Dito.
        * internal.h (struct backtrace_state): Add moredata flag.
        * state.c (backtrace_create_state): Handle threaded flag.
---
 libbacktrace/backtrace-supported.h.in |   8 +-
 libbacktrace/backtrace.c              |  14 ++-
 libbacktrace/backtrace.h              | 104 ++++++++++++++----
 libbacktrace/dwarf.c                  | 151 +++++++++++++++++++++-----
 libbacktrace/fileline.c               |  21 +++-
 libbacktrace/internal.h               |   2 +
 libbacktrace/state.c                  |   5 +-
 7 files changed, 249 insertions(+), 56 deletions(-)

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..74ab932c1ec 100644
--- a/libbacktrace/backtrace.c
+++ b/libbacktrace/backtrace.c
@@ -31,6 +31,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE
 POSSIBILITY OF SUCH DAMAGE.  */
 
 #include "config.h"
+#include <string.h>
 
 #include <sys/types.h>
 
@@ -86,7 +87,18 @@ unwind (struct _Unwind_Context *context, void *vdata)
     --pc;
 
   if (!bdata->can_alloc)
-    bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
+    {
+      if (bdata->state->moredata)
+       {
+         struct backtrace_moredata md;
+         memset (&md, 0, sizeof md);
+         md.version = 4;
+         md.data = bdata->data;
+         bdata->ret = bdata->callback (&md, pc, NULL, 0, NULL);
+       }
+      else
+       bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
+    }
   else
     bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
                                   bdata->error_callback, bdata->data);
diff --git a/libbacktrace/backtrace.h b/libbacktrace/backtrace.h
index fd0c659decc..b94c410fe11 100644
--- a/libbacktrace/backtrace.h
+++ b/libbacktrace/backtrace.h
@@ -85,15 +85,44 @@ 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_syminfo_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.  When the MOREDATA flag is set, the
+  backtrace_error_callback will also receive a pointer to
+  backtrace_moredata as its DATA argument; the callback can extract the
+  original data from the data field of the backtrace_moredata struct.
+
+   Historical note: in previous versions (before June, 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 +135,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 +204,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_syminfo (if the MOREDATA flag
+   was not set when calling backtrace_create_state) or a pointer to a
+   backtrace_moredata struct.  PC is 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 +233,34 @@ 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 4.  */
+  int version;
+  /* The DATA value passed to whatever function is calling the callback
+     (backtrace_full, backtrace_pcinfo, or backtrace_syminfo).  */
+  void *data;
+  /* The DWARF discriminator.  This is zero if there is none. See
+     https://wiki.dwarfstd.org/Path_Discriminators.md.  */
+  unsigned int discriminator;
+  /* The line of the original declaration of the symbol the PC is
+     in.  */
+  unsigned int decl_line;
+};
+
 #ifdef __cplusplus
 } /* End extern "C".  */
 #endif
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index ecf32f7688b..7dfff1293ba 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,10 @@ struct function
   /* If this is an inlined function, the line number of the call
      site.  */
   int caller_lineno;
+  /* Dito for the discriminator.  */
+  int caller_disc;
+  /* Dito for the line of the declaration.  */
+  int decl_line;
   /* Map PC ranges to inlined functions.  */
   struct function_addrs *function_addrs;
   size_t function_addrs_count;
@@ -2484,7 +2490,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)
 {
@@ -2495,7 +2501,8 @@ add_line (struct backtrace_state *state, struct 
dwarf_data *ddata,
   if (vec->count > 0)
     {
       ln = (struct line *) vec->vec.base + (vec->count - 1);
-      if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
+      if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno
+         && ln->disc == disc)
        return 1;
     }
 
@@ -2511,6 +2518,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 +2937,7 @@ read_line_program (struct backtrace_state *state, struct 
dwarf_data *ddata,
   const char *reset_filename;
   const char *filename;
   int lineno;
+  int disc = 0;
 
   address = 0;
   op_index = 0;
@@ -2954,8 +2963,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 +2983,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);
@@ -3025,11 +3036,10 @@ read_line_program (struct backtrace_state *state, 
struct dwarf_data *ddata,
                    memcpy (p + dir_len + 1, f, f_len + 1);
                    filename = p;
                  }
-             }
+           }
              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 +3052,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 +3194,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))
@@ -3206,15 +3218,17 @@ read_line_info (struct backtrace_state *state, struct 
dwarf_data *ddata,
 
 static const char *read_referenced_name (struct dwarf_data *, struct unit *,
                                         uint64_t, backtrace_error_callback,
-                                        void *);
+                                        void *, int *);
 
-/* Read the name of a function from a DIE referenced by ATTR with VAL.  */
+/* Read the name of a function from a DIE referenced by ATTR with VAL.
+   If DECL_LINE is not NULL, and the referenced DIE has a
+   DW_AT_decl_line attribute, store its value in *DECL_LINE.  */
 
 static const char *
 read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
                                struct attr *attr, struct attr_val *val,
                                backtrace_error_callback error_callback,
-                               void *data)
+                               void *data, int *decl_line)
 {
   switch (attr->name)
     {
@@ -3237,12 +3251,14 @@ read_referenced_name_from_attr (struct dwarf_data 
*ddata, struct unit *u,
        return NULL;
 
       uint64_t offset = val->u.uint - unit->low_offset;
-      return read_referenced_name (ddata, unit, offset, error_callback, data);
+      return read_referenced_name (ddata, unit, offset, error_callback, data,
+                                  decl_line);
     }
 
   if (val->encoding == ATTR_VAL_UINT
       || val->encoding == ATTR_VAL_REF_UNIT)
-    return read_referenced_name (ddata, u, val->u.uint, error_callback, data);
+    return read_referenced_name (ddata, u, val->u.uint, error_callback, data,
+                                decl_line);
 
   if (val->encoding == ATTR_VAL_REF_ALT_INFO)
     {
@@ -3254,7 +3270,7 @@ read_referenced_name_from_attr (struct dwarf_data *ddata, 
struct unit *u,
 
       uint64_t offset = val->u.uint - alt_unit->low_offset;
       return read_referenced_name (ddata->altlink, alt_unit, offset,
-                                  error_callback, data);
+                                  error_callback, data, decl_line);
     }
 
   return NULL;
@@ -3262,12 +3278,14 @@ read_referenced_name_from_attr (struct dwarf_data 
*ddata, struct unit *u,
 
 /* Read the name of a function from a DIE referenced by a
    DW_AT_abstract_origin or DW_AT_specification tag.  OFFSET is within
-   the same compilation unit.  */
+   the same compilation unit.  If DECL_LINE is not NULL, and the
+   referenced DIE has a DW_AT_decl_line attribute, store its value in
+   *DECL_LINE.  */
 
 static const char *
 read_referenced_name (struct dwarf_data *ddata, struct unit *u,
                      uint64_t offset, backtrace_error_callback error_callback,
-                     void *data)
+                     void *data, int *decl_line)
 {
   struct dwarf_buf unit_buf;
   uint64_t code;
@@ -3359,12 +3377,18 @@ read_referenced_name (struct dwarf_data *ddata, struct 
unit *u,
            const char *name;
 
            name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
-                                                  &val, error_callback, data);
+                                                  &val, error_callback, data,
+                                                  decl_line);
            if (name != NULL)
              ret = name;
          }
          break;
 
+       case DW_AT_decl_line:
+         if (decl_line != NULL && val.encoding == ATTR_VAL_UINT)
+           *decl_line = val.u.uint;
+         break;
+
        default:
          break;
        }
@@ -3517,6 +3541,16 @@ read_function_entry (struct backtrace_state *state, 
struct dwarf_data *ddata,
                    function->caller_lineno = val.u.uint;
                  break;
 
+               case DW_AT_GNU_discriminator:
+                 if (val.encoding == ATTR_VAL_UINT)
+                   function->caller_disc = val.u.uint;
+                 break;
+
+               case DW_AT_decl_line:
+                 if (val.encoding == ATTR_VAL_UINT)
+                   function->decl_line = val.u.uint;
+                 break;
+
                case DW_AT_abstract_origin:
                case DW_AT_specification:
                  /* Second name preference: override DW_AT_name, don't override
@@ -3529,7 +3563,8 @@ read_function_entry (struct backtrace_state *state, 
struct dwarf_data *ddata,
                    name
                      = read_referenced_name_from_attr (ddata, u,
                                                        &abbrev->attrs[i], &val,
-                                                       error_callback, data);
+                                                       error_callback, data,
+                                                       &function->decl_line);
                    if (name != NULL)
                      function->name = name;
                  }
@@ -3752,13 +3787,16 @@ 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 and LINENO and DISC and DECL_LINE
+   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,
+                         int *disc)
 {
   struct function_addrs *p;
   struct function_addrs *match;
@@ -3810,12 +3848,18 @@ 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.  */
+  if (state->moredata)
+    {
+      struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+      md->discriminator = *disc;
+      md->decl_line = inlined->decl_line;
+    }
   ret = callback (data, pc, *filename, *lineno, inlined->name);
   if (ret != 0)
     return ret;
@@ -3824,6 +3868,7 @@ report_inlined_functions (uintptr_t pc, struct function 
*function,
      it the appropriate filename and line number.  */
   *filename = inlined->caller_filename;
   *lineno = inlined->caller_lineno;
+  *disc = inlined->caller_disc;
 
   return 0;
 }
@@ -3850,6 +3895,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct 
dwarf_data *ddata,
   struct function *function;
   const char *filename;
   int lineno;
+  int disc = 0;
   int ret;
 
   *found = 1;
@@ -3991,6 +4037,12 @@ 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);
+      if (state->moredata)
+       {
+         struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+         md->discriminator = 0;
+         md->decl_line = 0;
+       }
       return callback (data, pc, NULL, 0, NULL);
     }
 
@@ -4038,13 +4090,27 @@ dwarf_lookup_pc (struct backtrace_state *state, struct 
dwarf_data *ddata,
          entry->u->abs_filename = filename;
        }
 
+      if (state->moredata)
+       {
+         struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+         md->discriminator = 0;
+         md->decl_line = 0;
+       }
       return callback (data, pc, entry->u->abs_filename, 0, NULL);
     }
 
   /* Search for function name within this unit.  */
 
   if (entry->u->function_addrs_count == 0)
-    return callback (data, pc, ln->filename, ln->lineno, NULL);
+    {
+      if (state->moredata)
+       {
+         struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+         md->discriminator = ln->disc;
+         md->decl_line = 0;
+       }
+      return callback (data, pc, ln->filename, ln->lineno, NULL);
+    }
 
   p = ((struct function_addrs *)
        bsearch (&pc, entry->u->function_addrs,
@@ -4052,7 +4118,15 @@ 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);
+    {
+      if (state->moredata)
+       {
+         struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+         md->discriminator = ln->disc;
+         md->decl_line = 0;
+       }
+      return callback (data, pc, ln->filename, ln->lineno, NULL);
+    }
 
   /* 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,18 +4150,32 @@ dwarf_lookup_pc (struct backtrace_state *state, struct 
dwarf_data *ddata,
       --p;
     }
   if (fmatch == NULL)
-    return callback (data, pc, ln->filename, ln->lineno, NULL);
+    {
+      if (state->moredata)
+       {
+         struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+         md->discriminator = ln->disc;
+         md->decl_line = 0;
+       }
+      return callback (data, pc, ln->filename, ln->lineno, NULL);
+    }
 
   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;
-
+  if (state->moredata)
+    {
+      struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+      md->discriminator = disc;
+      md->decl_line = function->decl_line;
+    }
   return callback (data, pc, filename, lineno, function->name);
 }
 
@@ -4137,7 +4225,12 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t 
pc,
     }
 
   /* FIXME: See if any libraries have been dlopen'ed.  */
-
+  if (state->moredata)
+    {
+      struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+      md->discriminator = 0;
+      md->decl_line = 0;
+    }
   return callback (data, pc, NULL, 0, NULL);
 }
 
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 82535e3f6cf..617133ee032 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -31,6 +31,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
OF THE
 POSSIBILITY OF SUCH DAMAGE.  */
 
 #include "config.h"
+#include <string.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -393,6 +394,15 @@ backtrace_pcinfo (struct backtrace_state *state, uintptr_t 
pc,
   if (state->fileline_initialization_failed)
     return 0;
 
+  if (state->moredata)
+    {
+      struct backtrace_moredata md;
+      memset (&md, 0, sizeof md);
+      md.version = 4;
+      md.data = data;
+      return state->fileline_fn (state, pc, callback, error_callback, &md);
+    }
+
   return state->fileline_fn (state, pc, callback, error_callback, data);
 }
 
@@ -409,7 +419,16 @@ backtrace_syminfo (struct backtrace_state *state, 
uintptr_t pc,
   if (state->fileline_initialization_failed)
     return 0;
 
-  state->syminfo_fn (state, pc, callback, error_callback, data);
+  if (state->moredata)
+    {
+      struct backtrace_moredata md;
+      memset (&md, 0, sizeof md);
+      md.version = 4;
+      md.data = data;
+      state->syminfo_fn (state, pc, callback, error_callback, &md);
+    }
+  else
+    state->syminfo_fn (state, pc, callback, error_callback, data);
   return 1;
 }
 
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 09a2147fdef..a5521e7ee38 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 MOREDATA flag was set.  */
+  int moredata;
   /* The master lock for fileline_fn, fileline_data, syminfo_fn,
      syminfo_data, fileline_initialization_failed and everything the
      data pointers point to.  */
diff --git a/libbacktrace/state.c b/libbacktrace/state.c
index 8c201624006..602e6d23b7b 100644
--- a/libbacktrace/state.c
+++ b/libbacktrace/state.c
@@ -51,7 +51,7 @@ backtrace_create_state (const char *filename, int threaded,
   struct backtrace_state *state;
 
 #ifndef HAVE_SYNC_FUNCTIONS
-  if (threaded)
+  if (threaded & 1)
     {
       error_callback (data, "backtrace library does not support threads", 0);
       return NULL;
@@ -60,7 +60,8 @@ 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.threaded = threaded & 1;
+  init_state.moredata = (threaded & 2) != 0;
 
   state = ((struct backtrace_state *)
           backtrace_alloc (&init_state, sizeof *state, error_callback, data));
-- 
2.54.0

Reply via email to