mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
libdrgn: use new libdwfl stack trace API
This commit is contained in:
parent
6f43fff627
commit
4fb0e2e110
@ -2265,7 +2265,11 @@ bool drgn_symbol_eq(struct drgn_symbol *a, struct drgn_symbol *b);
|
||||
*/
|
||||
|
||||
struct drgn_stack_trace;
|
||||
struct drgn_stack_frame;
|
||||
|
||||
struct drgn_stack_frame {
|
||||
struct drgn_stack_trace *trace;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
/** Destroy a @ref drgn_stack_trace. */
|
||||
void drgn_stack_trace_destroy(struct drgn_stack_trace *trace);
|
||||
@ -2273,16 +2277,6 @@ void drgn_stack_trace_destroy(struct drgn_stack_trace *trace);
|
||||
/** Get the number of stack frames in a stack trace. */
|
||||
size_t drgn_stack_trace_num_frames(struct drgn_stack_trace *trace);
|
||||
|
||||
/**
|
||||
* Get the stack at index @p i, where 0 is the innermost stack frame, 1 is its
|
||||
* caller, etc.
|
||||
*
|
||||
* @return On success, the stack frame, which is valid until this stack trace is
|
||||
* destroyed. If <tt>i >= drgn_stack_trace_num_frames(trace)</tt>, @c NULL.
|
||||
*/
|
||||
struct drgn_stack_frame *drgn_stack_trace_frame(struct drgn_stack_trace *trace,
|
||||
size_t i);
|
||||
|
||||
/**
|
||||
* Pretty-print a stack trace.
|
||||
*
|
||||
@ -2294,7 +2288,7 @@ struct drgn_error *drgn_pretty_print_stack_trace(struct drgn_stack_trace *trace,
|
||||
char **ret);
|
||||
|
||||
/** Get the return address at a stack frame. */
|
||||
uint64_t drgn_stack_frame_pc(struct drgn_stack_frame *frame);
|
||||
uint64_t drgn_stack_frame_pc(struct drgn_stack_frame frame);
|
||||
|
||||
/**
|
||||
* Get the function symbol at a stack frame.
|
||||
@ -2303,7 +2297,7 @@ uint64_t drgn_stack_frame_pc(struct drgn_stack_frame *frame);
|
||||
* drgn_symbol_destroy(). On error, its contents are undefined.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *drgn_stack_frame_symbol(struct drgn_stack_frame *frame,
|
||||
struct drgn_error *drgn_stack_frame_symbol(struct drgn_stack_frame frame,
|
||||
struct drgn_symbol **ret);
|
||||
|
||||
/**
|
||||
|
@ -816,53 +816,64 @@ drgn_program_find_object(struct drgn_program *prog, const char *name,
|
||||
}
|
||||
|
||||
struct drgn_error *drgn_program_find_symbol_internal(struct drgn_program *prog,
|
||||
Dwfl_Module *module,
|
||||
uint64_t address,
|
||||
struct drgn_symbol *sym)
|
||||
{
|
||||
Dwfl_Module *module;
|
||||
const char *name;
|
||||
GElf_Off offset;
|
||||
GElf_Sym elf_sym;
|
||||
|
||||
if (!prog->_dicache)
|
||||
return &drgn_not_found;
|
||||
|
||||
module = dwfl_addrmodule(prog->_dicache->dindex.dwfl, address);
|
||||
if (!module)
|
||||
return &drgn_not_found;
|
||||
name = dwfl_module_addrinfo(module, address, &offset, &elf_sym, NULL,
|
||||
NULL, NULL);
|
||||
if (!name)
|
||||
return &drgn_not_found;
|
||||
|
||||
sym->name = name;
|
||||
sym->address = address - offset;
|
||||
sym->size = elf_sym.st_size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_find_symbol(struct drgn_program *prog, uint64_t address,
|
||||
struct drgn_symbol **ret)
|
||||
struct drgn_error *
|
||||
drgn_program_find_symbol_in_module(struct drgn_program *prog,
|
||||
Dwfl_Module *module, uint64_t address,
|
||||
struct drgn_symbol **ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_symbol *sym;
|
||||
|
||||
if (!module)
|
||||
goto not_found;
|
||||
sym = malloc(sizeof(*sym));
|
||||
if (!sym)
|
||||
return &drgn_enomem;
|
||||
err = drgn_program_find_symbol_internal(prog, address, sym);
|
||||
err = drgn_program_find_symbol_internal(prog, module, address, sym);
|
||||
if (err) {
|
||||
free(sym);
|
||||
if (err == &drgn_not_found) {
|
||||
err = drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find symbol containing 0x%" PRIx64,
|
||||
address);
|
||||
}
|
||||
if (err == &drgn_not_found)
|
||||
goto not_found;
|
||||
return err;
|
||||
}
|
||||
*ret = sym;
|
||||
return NULL;
|
||||
|
||||
not_found:
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find symbol containing 0x%" PRIx64,
|
||||
address);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_find_symbol(struct drgn_program *prog, uint64_t address,
|
||||
struct drgn_symbol **ret)
|
||||
{
|
||||
Dwfl_Module *module;
|
||||
|
||||
if (prog->_dicache)
|
||||
module = dwfl_addrmodule(prog->_dicache->dindex.dwfl, address);
|
||||
else
|
||||
module = NULL;
|
||||
return drgn_program_find_symbol_in_module(prog, module, address, ret);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
|
@ -130,11 +130,20 @@ static inline bool drgn_program_is_64_bit(struct drgn_program *prog)
|
||||
|
||||
struct drgn_error *drgn_program_get_dwfl(struct drgn_program *prog, Dwfl **ret);
|
||||
|
||||
/* TODO: comment this. */
|
||||
struct drgn_error *drgn_program_find_symbol_in_module(struct drgn_program *prog,
|
||||
Dwfl_Module *module,
|
||||
uint64_t address,
|
||||
struct drgn_symbol **ret);
|
||||
|
||||
/*
|
||||
* Like @ref drgn_program_find_symbol(), but @p ret is already allocated and
|
||||
* returns @ref drgn_not_found instead of a more informative message.
|
||||
* TODO: update this.
|
||||
* Like @ref drgn_program_find_symbol(), but the module is known, @p ret is
|
||||
* already allocated, and returns @ref drgn_not_found instead of a more
|
||||
* informative message.
|
||||
*/
|
||||
struct drgn_error *drgn_program_find_symbol_internal(struct drgn_program *prog,
|
||||
Dwfl_Module *module,
|
||||
uint64_t address,
|
||||
struct drgn_symbol *ret);
|
||||
|
||||
|
@ -92,7 +92,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
StackTrace *trace;
|
||||
struct drgn_stack_frame *frame;
|
||||
struct drgn_stack_frame frame;
|
||||
} StackFrame;
|
||||
|
||||
typedef struct {
|
||||
@ -154,7 +154,8 @@ int Program_type_arg(Program *prog, PyObject *type_obj, bool can_be_none,
|
||||
Program *program_from_core_dump(PyObject *self, PyObject *args, PyObject *kwds);
|
||||
Program *program_from_kernel(PyObject *self);
|
||||
Program *program_from_pid(PyObject *self, PyObject *args, PyObject *kwds);
|
||||
Symbol *Program_find_symbol(Program *self, uint64_t address);
|
||||
|
||||
PyObject *Symbol_wrap(struct drgn_symbol *sym, Program *prog);
|
||||
|
||||
static inline PyObject *DrgnType_parent(DrgnType *type)
|
||||
{
|
||||
|
@ -701,35 +701,27 @@ static StackTrace *Program_stack_trace(Program *self, PyObject *args,
|
||||
return ret;
|
||||
}
|
||||
|
||||
Symbol *Program_find_symbol(Program *self, uint64_t address)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_symbol *sym;
|
||||
Symbol *ret;
|
||||
|
||||
err = drgn_program_find_symbol(&self->prog, address, &sym);
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
ret = (Symbol *)Symbol_type.tp_alloc(&Symbol_type, 0);
|
||||
if (!ret) {
|
||||
drgn_symbol_destroy(sym);
|
||||
return NULL;
|
||||
}
|
||||
ret->sym = sym;
|
||||
ret->prog = self;
|
||||
Py_INCREF(self);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Symbol *Program_symbol(Program *self, PyObject *args, PyObject *kwds)
|
||||
static PyObject *Program_symbol(Program *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *keywords[] = {"address", NULL};
|
||||
struct drgn_error *err;
|
||||
struct index_arg address;
|
||||
struct drgn_symbol *sym;
|
||||
PyObject *ret;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", keywords,
|
||||
index_converter, &address))
|
||||
return NULL;
|
||||
return Program_find_symbol(self, address.value);
|
||||
|
||||
err = drgn_program_find_symbol(&self->prog, address.value, &sym);
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
ret = Symbol_wrap(sym, self);
|
||||
if (!ret) {
|
||||
drgn_symbol_destroy(sym);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DrgnObject *Program_subscript(Program *self, PyObject *key)
|
||||
|
@ -32,10 +32,9 @@ static Py_ssize_t StackTrace_length(StackTrace *self)
|
||||
|
||||
static StackFrame *StackTrace_item(StackTrace *self, Py_ssize_t i)
|
||||
{
|
||||
struct drgn_stack_frame *frame;
|
||||
StackFrame *ret;
|
||||
|
||||
if (i < 0 || !(frame = drgn_stack_trace_frame(self->trace, i))) {
|
||||
if (i < 0 || i >= drgn_stack_trace_num_frames(self->trace)) {
|
||||
PyErr_SetString(PyExc_IndexError,
|
||||
"stack frame index out of range");
|
||||
return NULL;
|
||||
@ -43,7 +42,8 @@ static StackFrame *StackTrace_item(StackTrace *self, Py_ssize_t i)
|
||||
ret = (StackFrame *)StackFrame_type.tp_alloc(&StackFrame_type, 0);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->frame = frame;
|
||||
ret->frame.trace = self->trace;
|
||||
ret->frame.i = i;
|
||||
ret->trace = self;
|
||||
Py_INCREF(self);
|
||||
return ret;
|
||||
@ -86,10 +86,21 @@ static void StackFrame_dealloc(StackFrame *self)
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static Symbol *StackFrame_symbol(StackFrame *self)
|
||||
static PyObject *StackFrame_symbol(StackFrame *self)
|
||||
{
|
||||
return Program_find_symbol(self->trace->prog,
|
||||
drgn_stack_frame_pc(self->frame));
|
||||
struct drgn_error *err;
|
||||
struct drgn_symbol *sym;
|
||||
PyObject *ret;
|
||||
|
||||
err = drgn_stack_frame_symbol(self->frame, &sym);
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
ret = Symbol_wrap(sym, self->trace->prog);
|
||||
if (!ret) {
|
||||
drgn_symbol_destroy(sym);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *StackFrame_get_pc(StackFrame *self, void *arg)
|
||||
|
@ -3,6 +3,19 @@
|
||||
|
||||
#include "drgnpy.h"
|
||||
|
||||
PyObject *Symbol_wrap(struct drgn_symbol *sym, Program *prog)
|
||||
{
|
||||
Symbol *ret;
|
||||
|
||||
ret = (Symbol *)Symbol_type.tp_alloc(&Symbol_type, 0);
|
||||
if (ret) {
|
||||
ret->sym = sym;
|
||||
ret->prog = prog;
|
||||
Py_INCREF(prog);
|
||||
}
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
|
||||
static void Symbol_dealloc(Symbol *self)
|
||||
{
|
||||
drgn_symbol_destroy(self->sym);
|
||||
|
@ -11,18 +11,19 @@
|
||||
#include "string_builder.h"
|
||||
#include "symbol.h"
|
||||
|
||||
struct drgn_stack_frame {
|
||||
struct drgn_program *prog;
|
||||
uint64_t pc;
|
||||
};
|
||||
|
||||
struct drgn_stack_trace {
|
||||
struct drgn_program *prog;
|
||||
union {
|
||||
size_t capacity;
|
||||
Dwfl_Thread *thread;
|
||||
};
|
||||
size_t num_frames;
|
||||
struct drgn_stack_frame frames[];
|
||||
Dwfl_Frame *frames[];
|
||||
};
|
||||
|
||||
LIBDRGN_PUBLIC void drgn_stack_trace_destroy(struct drgn_stack_trace *trace)
|
||||
{
|
||||
dwfl_detach_thread(trace->thread);
|
||||
free(trace);
|
||||
}
|
||||
|
||||
@ -32,31 +33,30 @@ size_t drgn_stack_trace_num_frames(struct drgn_stack_trace *trace)
|
||||
return trace->num_frames;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_stack_frame *
|
||||
drgn_stack_trace_frame(struct drgn_stack_trace *trace, size_t i)
|
||||
{
|
||||
if (i >= trace->num_frames)
|
||||
return NULL;
|
||||
return &trace->frames[i];
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_pretty_print_stack_trace(struct drgn_stack_trace *trace, char **ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct string_builder str = {};
|
||||
size_t i;
|
||||
struct drgn_stack_frame frame = { .trace = trace, };
|
||||
|
||||
for (i = 0; i < trace->num_frames; i++) {
|
||||
struct drgn_stack_frame *frame = &trace->frames[i];
|
||||
for (; frame.i < trace->num_frames; frame.i++) {
|
||||
uint64_t pc;
|
||||
Dwfl_Module *module;
|
||||
struct drgn_symbol sym;
|
||||
|
||||
pc = drgn_stack_frame_pc(frame);
|
||||
err = drgn_program_find_symbol_internal(frame->prog, pc, &sym);
|
||||
module = dwfl_frame_module(trace->frames[frame.i]);
|
||||
if (module) {
|
||||
err = drgn_program_find_symbol_internal(trace->prog,
|
||||
module, pc,
|
||||
&sym);
|
||||
} else {
|
||||
err = &drgn_not_found;
|
||||
}
|
||||
if (err && err != &drgn_not_found)
|
||||
goto err;
|
||||
if (!string_builder_appendf(&str, "#%-2zu ", i)) {
|
||||
if (!string_builder_appendf(&str, "#%-2zu ", frame.i)) {
|
||||
err = &drgn_enomem;
|
||||
goto err;
|
||||
}
|
||||
@ -74,7 +74,7 @@ drgn_pretty_print_stack_trace(struct drgn_stack_trace *trace, char **ret)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (i != trace->num_frames - 1 &&
|
||||
if (frame.i != trace->num_frames - 1 &&
|
||||
!string_builder_appendc(&str, '\n')) {
|
||||
err = &drgn_enomem;
|
||||
goto err;
|
||||
@ -91,16 +91,23 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC uint64_t drgn_stack_frame_pc(struct drgn_stack_frame *frame)
|
||||
LIBDRGN_PUBLIC uint64_t drgn_stack_frame_pc(struct drgn_stack_frame frame)
|
||||
{
|
||||
return frame->pc;
|
||||
Dwarf_Addr pc;
|
||||
|
||||
dwfl_frame_pc(frame.trace->frames[frame.i], &pc, NULL);
|
||||
return pc;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_stack_frame_symbol(struct drgn_stack_frame *frame,
|
||||
struct drgn_symbol **ret)
|
||||
drgn_stack_frame_symbol(struct drgn_stack_frame frame, struct drgn_symbol **ret)
|
||||
{
|
||||
return drgn_program_find_symbol(frame->prog, frame->pc, ret);
|
||||
Dwfl_Module *module;
|
||||
|
||||
module = dwfl_frame_module(frame.trace->frames[frame.i]);
|
||||
return drgn_program_find_symbol_in_module(frame.trace->prog, module,
|
||||
drgn_stack_frame_pc(frame),
|
||||
ret);
|
||||
}
|
||||
|
||||
static bool drgn_thread_memory_read(Dwfl *dwfl, Dwarf_Addr addr,
|
||||
@ -145,9 +152,9 @@ err:
|
||||
|
||||
/*
|
||||
* For drgn_object_stack_trace(), we only care about the thread
|
||||
* prog->stack_trace_obj. We return it with an arbitrary PID.
|
||||
* prog->stack_trace_obj. We return it with an arbitrary TID.
|
||||
*/
|
||||
#define STACK_TRACE_OBJ_PID 1
|
||||
#define STACK_TRACE_OBJ_TID 1
|
||||
static pid_t drgn_object_stack_trace_next_thread(Dwfl *dwfl, void *dwfl_arg,
|
||||
void **thread_argp)
|
||||
{
|
||||
@ -156,7 +163,7 @@ static pid_t drgn_object_stack_trace_next_thread(Dwfl *dwfl, void *dwfl_arg,
|
||||
if (*thread_argp || !prog->stack_trace_obj)
|
||||
return 0;
|
||||
*thread_argp = (void *)prog->stack_trace_obj;
|
||||
return STACK_TRACE_OBJ_PID;
|
||||
return STACK_TRACE_OBJ_TID;
|
||||
}
|
||||
|
||||
static bool drgn_linux_kernel_set_initial_registers(Dwfl_Thread *thread,
|
||||
@ -176,50 +183,30 @@ static bool drgn_linux_kernel_set_initial_registers(Dwfl_Thread *thread,
|
||||
return true;
|
||||
}
|
||||
|
||||
struct drgn_stack_trace_builder {
|
||||
struct drgn_program *prog;
|
||||
struct drgn_stack_trace *trace;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
static int drgn_append_stack_frame(Dwfl_Frame *dwfl_frame, void *arg)
|
||||
static int drgn_append_stack_frame(Dwfl_Frame *state, void *arg)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_stack_trace_builder *builder = arg;
|
||||
struct drgn_program *prog = builder->prog;
|
||||
struct drgn_stack_trace *trace = builder->trace;
|
||||
struct drgn_stack_frame *frame;
|
||||
Dwarf_Addr pc;
|
||||
struct drgn_stack_trace **tracep = arg;
|
||||
struct drgn_stack_trace *trace = *tracep;
|
||||
|
||||
if (!dwfl_frame_pc(dwfl_frame, &pc, NULL)) {
|
||||
err = drgn_error_libdwfl();
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (trace->num_frames >= builder->capacity) {
|
||||
if (trace->num_frames >= trace->capacity) {
|
||||
struct drgn_stack_trace *tmp;
|
||||
size_t new_capacity, bytes;
|
||||
|
||||
if (__builtin_mul_overflow(2U, builder->capacity,
|
||||
if (__builtin_mul_overflow(2U, trace->capacity,
|
||||
&new_capacity) ||
|
||||
__builtin_mul_overflow(new_capacity,
|
||||
sizeof(trace->frames[0]), &bytes) ||
|
||||
__builtin_add_overflow(bytes, sizeof(*trace), &bytes) ||
|
||||
!(trace = realloc(trace, bytes))) {
|
||||
err = &drgn_enomem;
|
||||
goto err;
|
||||
!(tmp = realloc(trace, bytes))) {
|
||||
drgn_error_destroy(trace->prog->stack_trace_err);
|
||||
trace->prog->stack_trace_err = &drgn_enomem;
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
builder->trace = trace;
|
||||
builder->capacity = new_capacity;
|
||||
*tracep = trace = tmp;
|
||||
trace->capacity = new_capacity;
|
||||
}
|
||||
frame = &trace->frames[trace->num_frames++];
|
||||
frame->prog = prog;
|
||||
frame->pc = pc;
|
||||
trace->frames[trace->num_frames++] = state;
|
||||
return DWARF_CB_OK;
|
||||
|
||||
err:
|
||||
drgn_error_destroy(prog->stack_trace_err);
|
||||
prog->stack_trace_err = err;
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
|
||||
static const Dwfl_Thread_Callbacks drgn_linux_kernel_thread_callbacks = {
|
||||
@ -234,7 +221,7 @@ struct drgn_error *drgn_object_stack_trace(const struct drgn_object *obj,
|
||||
struct drgn_error *err;
|
||||
struct drgn_program *prog = obj->prog;
|
||||
Dwfl *dwfl;
|
||||
struct drgn_stack_trace_builder builder;
|
||||
Dwfl_Thread *thread;
|
||||
struct drgn_stack_trace *trace;
|
||||
|
||||
if (!prog->has_platform) {
|
||||
@ -262,41 +249,55 @@ struct drgn_error *drgn_object_stack_trace(const struct drgn_object *obj,
|
||||
prog->attached_dwfl_state = true;
|
||||
}
|
||||
|
||||
builder.prog = prog;
|
||||
builder.trace = malloc(sizeof(*builder.trace) +
|
||||
sizeof(builder.trace->frames[0]));
|
||||
if (!builder.trace)
|
||||
return &drgn_enomem;
|
||||
builder.trace->num_frames = 0;
|
||||
builder.capacity = 1;
|
||||
|
||||
prog->stack_trace_obj = obj;
|
||||
dwfl_getthread_frames(dwfl, STACK_TRACE_OBJ_PID,
|
||||
drgn_append_stack_frame, &builder);
|
||||
thread = dwfl_attach_thread(dwfl, STACK_TRACE_OBJ_TID);
|
||||
prog->stack_trace_obj = NULL;
|
||||
if (prog->stack_trace_err)
|
||||
goto stack_trace_err;
|
||||
if (!thread) {
|
||||
err = drgn_error_libdwfl();
|
||||
goto err;
|
||||
}
|
||||
|
||||
trace = malloc(sizeof(*trace) + sizeof(trace->frames[0]));
|
||||
if (!trace) {
|
||||
err = &drgn_enomem;
|
||||
goto err;
|
||||
}
|
||||
trace->prog = prog;
|
||||
trace->capacity = 1;
|
||||
trace->num_frames = 0;
|
||||
|
||||
dwfl_thread_getframes(thread, drgn_append_stack_frame, &trace);
|
||||
if (prog->stack_trace_err) {
|
||||
free(trace);
|
||||
goto stack_trace_err;
|
||||
}
|
||||
|
||||
/* Shrink the trace to fit if we can, but don't fail if we can't. */
|
||||
if (trace->capacity > trace->num_frames) {
|
||||
struct drgn_stack_trace *tmp;
|
||||
|
||||
tmp = realloc(trace,
|
||||
sizeof(*trace) +
|
||||
trace->num_frames * sizeof(trace->frames[0]));
|
||||
if (tmp)
|
||||
trace = tmp;
|
||||
}
|
||||
trace->thread = thread;
|
||||
*ret = trace;
|
||||
return NULL;
|
||||
|
||||
stack_trace_err:
|
||||
/*
|
||||
* The error reporting for dwfl_getthread_frames() is not great. The
|
||||
* documentation says that some of its unwinder implementations always
|
||||
* return an error. So, we do our own error reporting for fatal errors
|
||||
* through prog->stack_trace_err.
|
||||
*/
|
||||
if (prog->stack_trace_err) {
|
||||
err = prog->stack_trace_err;
|
||||
prog->stack_trace_err = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Shrink the trace to fit if we can, but don't fail if we can't. */
|
||||
trace = realloc(builder.trace,
|
||||
sizeof(*builder.trace) +
|
||||
builder.trace->num_frames *
|
||||
sizeof(builder.trace->frames[0]));
|
||||
if (!trace)
|
||||
trace = builder.trace;
|
||||
*ret = trace;
|
||||
return NULL;
|
||||
|
||||
err = prog->stack_trace_err;
|
||||
prog->stack_trace_err = NULL;
|
||||
err:
|
||||
free(builder.trace);
|
||||
dwfl_detach_thread(thread);
|
||||
return err;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user