make visible to user libunwind function's context, SP register and CFA
This commit is contained in:
@@ -16,9 +16,14 @@ typedef struct {
|
||||
char* file; ///< file name where the function is defined. NULL if library failed to get file name
|
||||
int line; ///< line of definition of the function. -1 if library failed to get file line
|
||||
unw_word_t pc; ///< address between LowPC & HighPC (plus base address offset). actually, address of currently executed command in function
|
||||
unw_word_t lowpc; ///< offset to start of the function against base address
|
||||
unw_word_t highpc; ///< offset to the next address after the end of the function against base address
|
||||
unw_word_t sp; ///< SP register in function's frame
|
||||
unw_word_t cfa; ///< CFA (Canonical Frame Address) of the function. !!! Don't use CFA provided by libunwind, it's not valid !!!
|
||||
unw_cursor_t context;///< Function's frame including register's values
|
||||
} pst_function_info;
|
||||
|
||||
/// @brief bitmask of parameter options
|
||||
/// @brief bitmask of parameter's options
|
||||
typedef enum {
|
||||
// scope & access
|
||||
PARAM_CONST = 0x00000001, ///< constant access
|
||||
|
||||
@@ -307,7 +307,7 @@ void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st
|
||||
|
||||
pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_function* callee)
|
||||
{
|
||||
uint64_t start_pc = storage->ctx->base_addr + callee->lowpc;
|
||||
uint64_t start_pc = storage->ctx->base_addr + callee->info.lowpc;
|
||||
pst_call_site* cs = storage_call_site_by_target(storage, start_pc);
|
||||
if(!cs) {
|
||||
cs = storage_call_site_by_origin(storage, callee->info.name);
|
||||
|
||||
+16
-14
@@ -74,11 +74,11 @@ static bool get_frame(pst_function* fn)
|
||||
|
||||
bool nret = true;
|
||||
pst_decl(pst_dwarf_stack, stack, fn->ctx);
|
||||
if(pst_dwarf_stack_calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && pst_dwarf_stack_get_value(&stack, &fn->cfa)) {
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->info.name, fn->ctx->buff, fn->cfa);
|
||||
if(pst_dwarf_stack_calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && pst_dwarf_stack_get_value(&stack, &fn->info.cfa)) {
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->info.name, fn->ctx->buff, fn->info.cfa);
|
||||
|
||||
// setup context to match CFA for frame
|
||||
fn->ctx->cfa = fn->cfa;
|
||||
fn->ctx->cfa = fn->info.cfa;
|
||||
} else {
|
||||
nret = false;
|
||||
pst_log(SEVERITY_ERROR, "Failed to calculate CFA expression");
|
||||
@@ -261,21 +261,21 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
|
||||
|
||||
// get list of offsets from process base address of continuous memory ranges where function's code resides
|
||||
// if(dwarf_haspc(d, pc)) {
|
||||
dwarf_lowpc(d, &fn->lowpc);
|
||||
dwarf_highpc(d, &fn->highpc);
|
||||
dwarf_lowpc(d, &fn->info.lowpc);
|
||||
dwarf_highpc(d, &fn->info.highpc);
|
||||
// } else {
|
||||
// pst_log(SEVERITY_ERROR, "Function's '%s' DIE hasn't definitions of memory offsets of function's code", dwarf_diename(d));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
unw_proc_info_t info;
|
||||
unw_get_proc_info(&fn->cursor, &info);
|
||||
unw_get_proc_info(&fn->info.context, &info);
|
||||
fn->ctx->clean_print(fn->ctx);
|
||||
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): LOW_PC = %#lX, HIGH_PC = %#lX, offset from base address: 0x%lX, START_PC = 0x%lX, offset from start of function: 0x%lX",
|
||||
dwarf_diename(d), fn->lowpc, fn->highpc, fn->info.pc - fn->ctx->base_addr, info.start_ip, info.start_ip - fn->ctx->base_addr);
|
||||
dwarf_diename(d), fn->info.lowpc, fn->info.highpc, fn->info.pc - fn->ctx->base_addr, info.start_ip, info.start_ip - fn->ctx->base_addr);
|
||||
fn->ctx->print_registers(fn->ctx, 0x0, 0x10);
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), fn->parent ? fn->parent->sp : 0, fn->ctx->buff);
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), fn->parent ? fn->parent->info.sp : 0, fn->ctx->buff);
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), fn->ctx->buff);
|
||||
|
||||
// determine function's stack frame base
|
||||
@@ -418,20 +418,22 @@ void pst_function_init(pst_function* fn, pst_context* _ctx, pst_function* _paren
|
||||
{
|
||||
list_node_init(&fn->node);
|
||||
|
||||
// fields
|
||||
fn->lowpc = 0;
|
||||
fn->highpc = 0;
|
||||
// user visible fields
|
||||
fn->info.pc = 0;
|
||||
fn->info.lowpc = 0;
|
||||
fn->info.highpc = 0;
|
||||
bzero(&fn->info.context, sizeof(fn->info.context));
|
||||
fn->info.name = NULL;
|
||||
fn->info.line = -1;
|
||||
fn->info.file = NULL;
|
||||
fn->info.sp = 0;
|
||||
|
||||
// internal fields
|
||||
fn->die = NULL;
|
||||
list_head_init(&fn->params);
|
||||
pst_call_site_storage_init(&fn->call_sites, _ctx);
|
||||
|
||||
fn->sp = 0;
|
||||
fn->cfa = 0;
|
||||
memcpy(&fn->cursor, &_ctx->cursor, sizeof(fn->cursor));
|
||||
memcpy(&fn->info.context, &_ctx->cursor, sizeof(fn->info.context));
|
||||
fn->parent = _parent;
|
||||
fn->frame = NULL;
|
||||
fn->ctx = _ctx;
|
||||
|
||||
@@ -22,18 +22,11 @@
|
||||
// pst_function
|
||||
// -----------------------------------------------------------------------------------
|
||||
typedef struct pst_function {
|
||||
list_node node;
|
||||
|
||||
Dwarf_Addr lowpc; // offset to start of the function against base address
|
||||
Dwarf_Addr highpc; // offset to the next address after the end of the function against base address
|
||||
list_node node; // uplink
|
||||
Dwarf_Die* die; // DWARF DIE containing definition of the function
|
||||
pst_function_info info;
|
||||
list_head params; // function's parameters
|
||||
pst_call_site_storage call_sites;
|
||||
|
||||
unw_word_t sp; // SP register in function's frame
|
||||
unw_word_t cfa; // CFA (Canonical Frame Address) of the function
|
||||
unw_cursor_t cursor; // copy of stack state of the function
|
||||
pst_function_info info; // information about the function itself
|
||||
list_head params; // parameters of the function
|
||||
pst_call_site_storage call_sites; // call-sites of the function
|
||||
pst_function* parent; // parent function in call trace (caller)
|
||||
Dwarf_Frame* frame; // function's stack frame
|
||||
pst_context* ctx; // context of unwinding
|
||||
|
||||
@@ -146,15 +146,15 @@ bool pst_handler_handle_dwarf(pst_handler* h)
|
||||
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) {
|
||||
for(pst_function* fun = last_function(h); fun; fun = prev_function(h, fun)) {
|
||||
dladdr((void*)(fun->info.pc), &info);
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX", fun->info.name, info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->sp : 0);
|
||||
pst_log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX",
|
||||
fun->info.name, info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->info.sp : 0);
|
||||
|
||||
// setup context
|
||||
h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, fun->info.pc);
|
||||
h->ctx.base_addr = (uint64_t)info.dli_fbase;
|
||||
h->ctx.curr_frame = &fun->cursor;
|
||||
h->ctx.sp = fun->sp;
|
||||
h->ctx.cfa = fun->cfa;
|
||||
h->ctx.curr_frame = &fun->cursor;
|
||||
h->ctx.curr_frame = &fun->info.context;
|
||||
h->ctx.sp = fun->info.sp;
|
||||
h->ctx.cfa = fun->info.cfa;
|
||||
|
||||
get_dwarf_function(h, fun);
|
||||
}
|
||||
@@ -282,7 +282,7 @@ bool pst_handler_unwind(pst_handler* h)
|
||||
pst_log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, pc, sp);
|
||||
pst_function* last = last_function(h);
|
||||
pst_function* fn = add_function(h, NULL);
|
||||
fn->info.pc = pc; fn->sp = sp;
|
||||
fn->info.pc = pc; fn->info.sp = sp;
|
||||
if(!pst_function_unwind(fn)) {
|
||||
del_function(fn);
|
||||
} else if(last) {
|
||||
|
||||
Reference in New Issue
Block a user