/* SPDX-License-Identifier: GPL-2.0+ */ /* * Backtrace support * * Copyright 2025 Canonical Ltd * Written by Simon Glass */ #ifndef __BACKTRACE_H #define __BACKTRACE_H /* Maximum number of stack frames that can be collected */ #define BACKTRACE_MAX_FRAMES 100 /* Size of buffer for all symbol strings combined */ #define BACKTRACE_SYM_BUFSZ (4 * 1024) /** * struct backtrace_frame - a single stack frame in a backtrace * * @addr: return address for this frame * @sym: pointer to symbol string in backtrace_ctx->sym_buf, or NULL if not * yet resolved or if sym_buf ran out of space */ struct backtrace_frame { void *addr; char *sym; }; /** * struct backtrace_ctx - context for backtrace operations * * This structure holds all state for collecting and symbolising a backtrace. * It should be declared static to avoid consuming stack space (~5KB). * * Lifecycle: * 1. Call backtrace_init() - fills @frame[].addr with return addresses and * sets @count. The @frame[].sym pointers are initialised to NULL. * 2. Call backtrace_get_syms() - resolves addresses to symbol strings, * writing them into @sym_buf and setting @frame[].sym pointers. * 3. Access @frame[0..count-1] to read addresses and symbol strings. * 4. Call backtrace_uninit() to release resources (currently a no-op). * * @frame: array of stack frames * @count: number of valid entries in @frame * @sym_buf: buffer holding NUL-terminated symbol strings packed consecutively */ struct backtrace_ctx { struct backtrace_frame frame[BACKTRACE_MAX_FRAMES]; unsigned int count; char sym_buf[BACKTRACE_SYM_BUFSZ]; }; /** * 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); /** * backtrace_strf() - get a condensed backtrace string into a buffer * * Return a string containing the last CONFIG_BACKTRACE_SUMMARY_FRAMES function names * and line number, separated by ``<-``. * * For example: ``func_a:12 <-func_b:34 <-func_c:56`` * * @skip: number of stack frames to skip (0 to include backtrace_strf itself) * @buf: buffer to write the string to * @size: size of buffer * Return: pointer to buf, or NULL on error */ char *backtrace_strf(unsigned int skip, char *buf, int size); /** * backtrace_str() - get a condensed backtrace string * * Return a string containing the last CONFIG_BACKTRACE_SUMMARY_FRAMES function names * and line number, separated by ``<-``. The string is statically allocated and * will be overwritten on the next call. * * For example: ``func_a:12 <-func_b:34 <-func_c:56`` * * @skip: number of stack frames to skip (0 to include backtrace_str itself) * Return: pointer to static string, or NULL on error */ #if CONFIG_IS_ENABLED(BACKTRACE) const char *backtrace_str(unsigned int skip); #else static inline const char *backtrace_str(unsigned int skip) { return NULL; } #endif #endif /* __BACKTRACE_H */