On Mon, Jun 22, 2026 at 5:33 PM Andi Kleen <[email protected]> wrote:
>
> Add support for reporting GNU discriminators in the libbacktrace full
> callback to make it usable for autofdo style usages. The autofdo
> file format needs these two bits of information.
>
> There are currently no in tree users for this, but I have some external
> software that makes use of it.
>
> For external users this is currently only available through
> a new backtrace_pcinfo_extra function. This works the same
> as backtrace_pcinfo, except that the callback has an
> extra arguments pointing to backtrace_extra with discriminator
> and decl_line.
>
> Internally the new callback type is used always since
> old callbacks will just ignore the extra argument. This makes the
> assumption that no function call ABI changes from an additional argument
Thanks for the patch.
Adding a new function to libbacktrace is possible but awkward because
of code like
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/src/libbacktrace/backtrace-rename.h;h=5417532480e1c8f2a2bdc1bdabbf413efef9de9a;hb=HEAD
and
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libsanitizer/libbacktrace/backtrace-rename.h;h=a31917c9af53a07f3cdabaae4ae202d897600819;hb=HEAD,
which assumes that it knows all the libbacktrace functions. This kind
of code is unfortunately common in libraries that rely on
libbacktrace. It's a pity I didn't try to think of some approach to
handle that in the early days. This means that while we can add new
functions to libbacktrace, we shouldn't do so casually.
I'm also not happy with the assumption that adding more arguments
doesn't change the calling convention. As far as I know it's true but
this kind of code seems likely to cause trouble with LTO or other
whole program approaches.
Fortunately I think we can address both issues by adjusting the
backtrace_create_state argument to be a flags argument. This is
technically not backward compatible, but I was unable to find any
calls to backtrace_create_state in the while that pass any value other
than 0 or 1. Passing a new MOREDATA flag can direct libbacktrace to
change the DATA value passed to callbacks to instead pass a pointer to
a struct with additional information.
So what do you think of an approach like the appended? Would that
provide the functionality you need?
Separately, can you explain what the decl_line value is for (I didn't
include it in this patch but it's easy to add)? I don't understand
what needs that, and in particular I don't understand what needs
decl_line without also needing the corresponding decl_file.
Ian
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.h b/libbacktrace/backtrace.h
index fd0c659decc..d068a8401b9 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 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,18 +132,20 @@ 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,
const char *function);
-
+p
/* Get a full stack backtrace. SKIP is the number of frames to skip;
passing 0 will start the trace with the function calling
backtrace_full. DATA is passed to the callback routine. If any
@@ -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 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;
+};
+
#ifdef __cplusplus
} /* End extern "C". */
#endif