/** Inserts a backtrace marker into the provided context * * Allows for maximum laziness and will initialise a circular buffer if one has not already been created. * * Code augmentation should look something like: @verbatim // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it static fr_cbuff *my_obj_bt; my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) { my_obj_t *this; this = talloc(ctx, my_obj_t); // Attach backtrace marker to object backtrace_attach(&my_obj_bt, this); return this; } @endverbatim * * Then, later when a double free occurs: @verbatim (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>) @endverbatim * * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument * values, but should at least show the code path taken. * * @param cbuff this should be a pointer to a static *fr_cbuff. * @param obj we want to generate a backtrace for. */ fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj) { fr_bt_marker_t *marker; if (*cbuff == NULL) { PTHREAD_MUTEX_LOCK(&fr_debug_init); /* Check again now we hold the mutex - eww*/ if (*cbuff == NULL) { TALLOC_CTX *ctx; ctx = fr_autofree_ctx(); *cbuff = fr_cbuff_alloc(ctx, MAX_BT_CBUFF, true); } PTHREAD_MUTEX_UNLOCK(&fr_debug_init); } marker = talloc(obj, fr_bt_marker_t); if (!marker) { return NULL; } marker->obj = (void *) obj; marker->cbuff = *cbuff; talloc_set_destructor(marker, _fr_do_bt); return marker; }
/** Inserts a backtrace marker into the provided context * * Allows for maximum laziness and will initialise a circular buffer if one has not already been created. * * Code augmentation should look something like: @verbatim // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it static fr_cbuff_t *my_obj_bt; my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) { my_obj_t *this; this = talloc(ctx, my_obj_t); // Attach backtrace marker to object backtrace_attach(&my_obj_bt, this); return this; } @endverbatim * * Then, later when a double free occurs: @verbatim (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>) @endverbatim * * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument * values, but should at least show the code path taken. * * @param cbuff this should be a pointer to a static *fr_cbuff. * @param obj we want to generate a backtrace for. */ fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj) { fr_bt_marker_t *marker; if (*cbuff == NULL) { PTHREAD_MUTEX_LOCK(&fr_debug_init); /* Check again now we hold the mutex - eww*/ if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true); PTHREAD_MUTEX_UNLOCK(&fr_debug_init); } marker = talloc(obj, fr_bt_marker_t); if (!marker) { return NULL; } marker->obj = (void *) obj; marker->cbuff = *cbuff; fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj); /* * Generate the backtrace for memory allocation */ fr_backtrace_do(marker); talloc_set_destructor(marker, fr_backtrace_do); return marker; }