23RCSID(
"$Id: 7c24e08f3d6f68a6cbca35268f3e3c8e20ce7102 $")
27#include <freeradius-devel/util/backtrace.h>
28#include <freeradius-devel/util/debug.h>
29#include <freeradius-devel/util/file.h>
32# include <freeradius-devel/backtrace/backtrace.h>
34static struct backtrace_state *backtrace_state = NULL;
50#elif defined(HAVE_EXECINFO)
55# define MAX_BT_FRAMES 128
58# define MAX_BT_CBUFF 1048576
83static void _backtrace_error(
UNUSED void *
data,
const char *
msg,
int errnum)
88static void backtrace_info_sanitise(fr_bt_info_frame_t *info)
92 if (dladdr((
void *)info->pc, &dl_info) != 0) {
93 info->library = dl_info.dli_fname;
94 if (!info->function) {
95 info->function = dl_info.dli_sname;
96 info->function_guess =
true;
101static void backtrace_info_print(fr_bt_info_frame_t *frame,
int fd,
bool trim_path)
103 if (!frame->library && !frame->filename) {
104 dprintf(fd,
"#%u: 0x%lx\n",
106 (
unsigned long)frame->pc);
109 else if (!frame->filename) {
110 dprintf(fd,
"#%u: 0x%lx %s in %s()\n",
112 (
unsigned long)frame->pc,
113 trim_path ?
fr_filename(frame->library) : frame->library,
114 frame->function ? frame->function :
"??");
117 dprintf(fd,
"#%u: 0x%lx %s in %s() at %s:%d\n",
119 (
unsigned long)frame->pc,
120 trim_path ?
fr_filename(frame->library) : frame->library,
121 frame->function ? frame->function :
"??",
127static int _backtrace_info_record(
void *
data, uintptr_t pc,
128 const char *filename,
int lineno,
129 const char *function)
132 fr_bt_info_frame_t *frame;
136 frame = talloc_zero(info, fr_bt_info_frame_t);
137 if (!frame)
return -1;
141 frame->lineno = lineno;
142 frame->frameno = info->
count;
145 backtrace_info_sanitise(frame);
154 backtrace_full(backtrace_state, 0, _backtrace_info_record, _backtrace_error, info);
157static int _backtrace_print(
void *
data, uintptr_t pc,
158 const char *filename,
int lineno,
159 const char *function)
161 unsigned int *frame_no = ((
unsigned int *)
data);
162 fr_bt_info_frame_t frame = {
163 .filename = filename,
165 .function = function,
166 .frameno = *frame_no,
170 backtrace_info_sanitise(&frame);
179 unsigned int frame = 0;
183 backtrace_full(backtrace_state, 0, _backtrace_print, _backtrace_error, &frame);
186#elif defined(HAVE_EXECINFO)
197#if (!defined(NDEBUG) || !defined(__GNUC__))
204 FR_FAULT_LOG(
"Backtrace of last %zu frames:", frame_count);
218#if defined(HAVE_BACKTRACE) || defined(HAVE_EXECINFO)
230 if ((p->
obj == obj) || !obj) {
233 fprintf(stderr,
"Stacktrace for: %p\n", p->
obj);
238 for (i = 0; i < p->
count; i++) {
249 fprintf(stderr,
"No backtrace available for %p", obj);
268 backtrace_record(bt);
313 if (*fring == NULL) {
324 marker->
obj = (
void *) obj;
325 marker->
fring = *fring;
327 fprintf(stderr,
"Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
331 _backtrace_do(marker);
332 talloc_set_destructor(marker, _backtrace_do);
339 fprintf(stderr,
"Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo, or libbacktrace\n");
345#ifndef HAVE_BACKTRACE
356 backtrace_state = backtrace_create_state(
program, 1, _backtrace_error, NULL);
357#elif defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
370 backtrace(
stack, 10);
void * obj
Memory address of the block of allocated memory.
fr_fring_t * fring
Where we temporarily store the backtraces.
void * frames[MAX_BT_FRAMES]
Backtrace frame data.
void * obj
Pointer to the parent object, this is our needle when we iterate over the contents of the circular bu...
#define MAX_BT_CBUFF
Should be a power of 2.
fr_bt_marker_t * fr_backtrace_attach(UNUSED fr_fring_t **fring, UNUSED TALLOC_CTX *obj)
void fr_backtrace_init(UNUSED char const *program)
int count
Number of frames stored.
static pthread_mutex_t fr_backtrace_lock
void fr_backtrace_print(fr_fring_t *fring, void *obj)
int fr_fault_log_fd
Where to write debug output.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define FR_FAULT_LOG(_fmt,...)
int fr_fring_overwrite(fr_fring_t *fring, void *in)
Insert a new item into the circular buffer, freeing the tail if we hit it.
void * fr_fring_next(fr_fring_t *fring)
Remove an item from the buffer.
fr_fring_t * fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
Initialise a ring buffer with fixed element size.
Standard thread safe circular buffer.
char const * fr_filename_common_trim(char const *path, char const *common)
Trim a common prefix from a filename.
char const * fr_filename(char const *path)
Get the filename from a path.
static char * stack[MAX_STACK]
static char const * program
#define talloc_strdup(_ctx, _str)