backtrace: Add a library to access the backtrace

Provide an API to access the backtrace, in an arch-neutral way.

The backtrace can be retrieved, examined and printed.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
Simon Glass
2025-11-28 05:29:39 -07:00
committed by Simon Glass
parent e0b8e54f52
commit cdde93a9e3
4 changed files with 121 additions and 0 deletions

72
include/backtrace.h Normal file
View File

@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Backtrace support
*
* Copyright 2025 Canonical Ltd
* Written by Simon Glass <simon.glass@canonical.com>
*/
#ifndef __BACKTRACE_H
#define __BACKTRACE_H
#define BACKTRACE_MAX 100
#define BACKTRACE_SYM_SIZE 128
#define BACKTRACE_BUFSZ (BACKTRACE_MAX * BACKTRACE_SYM_SIZE)
/**
* struct backtrace_ctx - context for backtrace operations
*
* @addrs: array of return addresses
* @syms: array of symbol strings (NULL until backtrace_get_syms() called)
* @count: number of entries in addrs/syms arrays
*/
struct backtrace_ctx {
void *addrs[BACKTRACE_MAX];
char *syms[BACKTRACE_MAX];
unsigned int count;
};
/**
* backtrace_init() - collect a backtrace
*
* Collect backtrace addresses into the context. Call backtrace_uninit() when
* done with the context.
*
* @ctx: context to fill
* @skip: number of stack frames to skip (0 to include backtrace_init itself)
* Return: number of addresses collected, or -ve on error (e.g. -ENOSYS)
*/
int backtrace_init(struct backtrace_ctx *ctx, unsigned int skip);
/**
* backtrace_get_syms() - get symbol strings for a backtrace
*
* Convert the addresses in the context to symbol strings. The strings are
* stored in ctx->syms[]. The caller must provide a buffer of sufficient size.
*
* @ctx: context with addresses from backtrace_init()
* @buf: buffer to use for string storage
* @size: size of buffer in bytes
* Return: 0 if OK, -ENOSPC if buffer too small
*/
int backtrace_get_syms(struct backtrace_ctx *ctx, char *buf, int size);
/**
* backtrace_uninit() - free backtrace resources
*
* Free any memory allocated in the context.
*
* @ctx: context to free
*/
void backtrace_uninit(struct backtrace_ctx *ctx);
/**
* backtrace_show() - print a backtrace
*
* Print a backtrace of the current call stack.
*
* Return: 0 if OK, -ve on error
*/
int backtrace_show(void);
#endif /* __BACKTRACE_H */

View File

@@ -28,6 +28,14 @@ config PHYSMEM
Enable this to access this basic support, which only supports clearing
the memory.
config BACKTRACE
bool "Enable backtrace support"
depends on SANDBOX
help
Enables support for printing a backtrace showing the current call
stack. This is currently only available on sandbox. The backtrace
command can be used to print the backtrace.
config BCH
bool "Enable Software based BCH ECC"
help

View File

@@ -147,6 +147,7 @@ obj-$(CONFIG_TRACE) += trace.o
obj-$(CONFIG_LIB_UUID) += uuid.o
obj-$(CONFIG_LIB_RAND) += rand.o
obj-y += panic.o
obj-$(CONFIG_BACKTRACE) += backtrace.o
ifeq ($(CONFIG_XPL_BUILD),y)
# SPL U-Boot may use full-printf, tiny-printf or none at all

40
lib/backtrace.c Normal file
View File

@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Stack-backtrace support
*
* Copyright 2025 Canonical Ltd
* Written by Simon Glass <simon.glass@canonical.com>
*/
#include <backtrace.h>
#include <stdio.h>
int backtrace_show(void)
{
char buf[BACKTRACE_BUFSZ];
struct backtrace_ctx ctx;
uint i;
int ret;
ret = backtrace_init(&ctx, 1);
if (ret < 0)
return ret;
ret = backtrace_get_syms(&ctx, buf, sizeof(buf));
if (ret) {
backtrace_uninit(&ctx);
return ret;
}
printf("backtrace: %d addresses\n", ctx.count);
for (i = 0; i < ctx.count; i++) {
if (ctx.syms[i])
printf(" %s\n", ctx.syms[i]);
else
printf(" %p\n", ctx.addrs[i]);
}
backtrace_uninit(&ctx);
return 0;
}