3#include <freeradius-devel/util/backtrace.h>
4#include <freeradius-devel/util/debug.h>
5#include <freeradius-devel/util/fring.h>
6#include <freeradius-devel/util/misc.h>
9# include <freeradius-devel/backtrace/backtrace.h>
11struct backtrace_state *backtrace_state = NULL;
27#elif defined(HAVE_EXECINFO)
32# define MAX_BT_FRAMES 128
35# define MAX_BT_CBUFF 1048576
60static void _backtrace_error(
UNUSED void *
data,
const char *
msg,
int errnum)
65static void backtrace_info_sanitise(fr_bt_info_frame_t *info)
69 if (dladdr((
void *)info->pc, &dl_info) != 0) {
70 info->library = dl_info.dli_fname;
71 if (!info->function) {
72 info->function = dl_info.dli_sname;
73 info->function_guess =
true;
78static void backtrace_info_print(fr_bt_info_frame_t *frame,
int fd,
bool trim_path)
80 if (!frame->library && !frame->filename) {
81 dprintf(fd,
"%u: @ 0x%lx\n",
83 (
unsigned long)frame->pc);
86 else if (!frame->filename) {
87 dprintf(fd,
"%u: %s %s() @ 0x%lx\n",
89 trim_path ?
fr_filename(frame->library) : frame->library,
91 (unsigned long)frame->pc);
94 dprintf(fd,
"%u: %s:%d %s()%s @ 0x%lx\n",
99 frame->function_guess ?
"?" :
"",
100 (unsigned long)frame->pc);
103static int _backtrace_info_record(
void *
data, uintptr_t pc,
104 const char *filename,
int lineno,
105 const char *function)
108 fr_bt_info_frame_t *frame;
112 frame = talloc_zero(info, fr_bt_info_frame_t);
113 if (!frame)
return -1;
115 frame->filename = talloc_strdup(frame, filename);
116 frame->function = talloc_strdup(frame, function);
117 frame->lineno = lineno;
118 frame->frameno = info->
count;
121 backtrace_info_sanitise(frame);
130 backtrace_full(backtrace_state, 0, _backtrace_info_record, _backtrace_error, info);
133static int _backtrace_print(
void *
data, uintptr_t pc,
134 const char *filename,
int lineno,
135 const char *function)
137 unsigned int *frame_no = ((
unsigned int *)
data);
138 fr_bt_info_frame_t frame = {
139 .filename = filename,
141 .function = function,
142 .frameno = *frame_no,
146 backtrace_info_sanitise(&frame);
155 unsigned int frame = 0;
159 backtrace_full(backtrace_state, 0, _backtrace_print, _backtrace_error, &frame);
162#elif defined(HAVE_EXECINFO)
173#if (!defined(NDEBUG) || !defined(__GNUC__))
180 FR_FAULT_LOG(
"Backtrace of last %zu frames:", frame_count);
194#if defined(HAVE_BACKTRACE) || defined(HAVE_EXECINFO)
206 if ((p->
obj == obj) || !obj) {
209 fprintf(stderr,
"Stacktrace for: %p\n", p->
obj);
214 for (i = 0; i < p->
count; i++) {
225 fprintf(stderr,
"No backtrace available for %p", obj);
289 if (*fring == NULL) {
300 marker->
obj = (
void *) obj;
301 marker->
fring = *fring;
303 fprintf(stderr,
"Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
307 _backtrace_do(marker);
308 talloc_set_destructor(marker, _backtrace_do);
315 fprintf(stderr,
"Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo, or libbacktrace\n");
321#ifndef HAVE_BACKTRACE
332 backtrace_state = backtrace_create_state(
program, 1, _backtrace_error, NULL);
333#elif defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
346 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.
static char * stack[MAX_STACK]
char const * fr_filename_common_trim(char const *path, char const *common)
Get the filename from a path.
char const * fr_filename(char const *path)
Get the filename from a path.