11
#include <libiberty/demangle.h>
15
#include "dwarf_stack.h"
16
#include "dwarf_utils.h"
17
#include "dwarf_function.h"
22
static bool get_frame(pst_function* fn)
26
Dwarf_Addr mod_bias = 0;
27
Dwarf_CFI* cfi = dwfl_module_eh_cfi(fn->ctx->module, &mod_bias);
29
cfi = dwfl_module_dwarf_cfi(fn->ctx->module, &mod_bias);
32
pst_log(SEVERITY_ERROR, "Cannot find CFI for module");
37
int result = dwarf_cfi_addrframe (cfi, fn->info.pc - mod_bias, &fn->frame);
39
pst_log(SEVERITY_ERROR, "Failed to find CFI frame for module");
44
fn->ctx->frame = fn->frame;
47
Dwarf_Addr start = fn->info.pc;
48
Dwarf_Addr end = fn->info.pc;
50
int ra_regno = dwarf_frame_info (fn->frame, &start, &end, &signalp);
54
reginfo info; info.regno = ra_regno;
55
dwfl_module_register_names(fn->ctx->module, regname_callback, &info);
56
pst_log(SEVERITY_INFO, "Function %s(...): '.eh/debug frame' info: PC range: => [%#" PRIx64 ", %#" PRIx64 "], return register: %s, in_signal = %s",
57
fn->info.name, start, end, info.regname, signalp ? "true" : "false");
59
pst_log(SEVERITY_WARNING, "Return address register info unavailable (%s)", dwarf_errmsg(0));
66
Dwarf_Op *cfa_ops = &dummy;
68
if(dwarf_frame_cfa(fn->frame, &cfa_ops, &cfa_nops)) {
69
pst_log(SEVERITY_ERROR, "Failed to get CFA for frame");
73
fn->ctx->print_expr(fn->ctx, cfa_ops, cfa_nops, NULL);
76
pst_decl(pst_dwarf_stack, stack, fn->ctx);
77
if(pst_dwarf_stack_calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && pst_dwarf_stack_get_value(&stack, &fn->info.cfa)) {
78
pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->info.name, fn->ctx->buff, fn->info.cfa);
81
fn->ctx->cfa = fn->info.cfa;
84
pst_log(SEVERITY_ERROR, "Failed to calculate CFA expression");
87
pst_dwarf_stack_fini(&stack);
92
static pst_parameter* add_param(pst_function* fn)
94
pst_new(pst_parameter, p, fn->ctx);
95
list_add_bottom(&fn->params, &p->node);
100
static void del_param(pst_parameter* p)
106
static void clear(pst_function* fn)
108
pst_parameter* param = NULL;
109
struct list_node *pos, *tn;
110
list_for_each_entry_safe(param, pos, tn, &fn->params, node) {
111
list_del(¶m->node);
112
pst_parameter_fini(param);
115
pst_call_site_storage_fini(&fn->call_sites);
118
static bool handle_lexical_block(pst_function* fn, Dwarf_Die* result)
120
Dwarf_Attribute attr_mem;
122
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
124
if(dwarf_child (&origin, &child) == 0) {
126
switch (dwarf_tag (&child))
128
case DW_TAG_variable:
129
case DW_TAG_formal_parameter:
130
pst_log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
136
} while (dwarf_siblingof (&child, &child) == 0);
141
if(dwarf_child (result, &child) == 0) {
143
switch (dwarf_tag (&child)) {
144
case DW_TAG_lexical_block:
145
handle_lexical_block(fn, &child);
147
case DW_TAG_variable: {
148
pst_parameter* param = add_param(fn);
149
if(!parameter_handle_dwarf(param, &child, fn)) {
154
case DW_TAG_GNU_call_site:
155
pst_call_site_storage_handle_dwarf(&fn->call_sites, &child, fn);
157
case DW_TAG_inlined_subroutine:
158
pst_log(SEVERITY_DEBUG, "Skipping Lexical block tag 'DW_TAG_inlined_subroutine'");
161
pst_log(SEVERITY_WARNING, "Unknown Lexical block tag 0x%X", dwarf_tag(&child));
164
}while (dwarf_siblingof (&child, &child) == 0);
170
pst_parameter* function_next_parameter(pst_function* fn, pst_parameter* p)
172
struct list_node* n = (p == NULL) ? list_first(&fn->params) : list_next(&p->node);
174
pst_parameter* ret = NULL;
176
ret = list_entry(n, pst_parameter, node);
182
void function_print_simple(pst_function* fn)
184
fn->ctx->print(fn->ctx, "%s() ", fn->info.name);
186
fn->ctx->print(fn->ctx, "at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc);
188
fn->ctx->print(fn->ctx, "at %p", (void*)fn->info.pc);
190
fn->ctx->print(fn->ctx, "\n");
193
bool function_print_pretty(pst_function* fn)
197
if(!asprintf(&at, " at %s:%d, %p", fn->info.file, fn->info.line, (void*)fn->info.pc))
199
} else if(!asprintf(&at, " at %p", (void*)fn->info.pc)){
204
pst_parameter* param = function_next_parameter(fn, NULL);
205
if(param && (param->info.flags & PARAM_RETURN)) {
207
parameter_print(param);
208
fn->ctx->print(fn->ctx, " %s(", fn->info.name);
209
param = function_next_parameter(fn, param);
211
fn->ctx->print(fn->ctx, "%s(", fn->info.name);
214
bool first = true; bool start_variable = false;
215
for(; param; param = function_next_parameter(fn, param)) {
216
if(param->info.flags & PARAM_RETURN) {
218
parameter_print(param);
219
fn->ctx->print(fn->ctx, " %s(", fn->info.name);
223
if(param->info.flags & PARAM_VARIABLE) {
224
if(!start_variable) {
225
fn->ctx->print(fn->ctx, ")%s\n", at);
226
fn->ctx->print(fn->ctx, "{\n");
227
start_variable = true;
229
if(param->info.line) {
230
fn->ctx->print(fn->ctx, "%04u: ", param->info.line);
232
fn->ctx->print(fn->ctx, " ");
234
parameter_print(param);
235
fn->ctx->print(fn->ctx, ";\n");
240
fn->ctx->print(fn->ctx, ", ");
242
parameter_print(param);
246
if(!start_variable) {
247
fn->ctx->print(fn->ctx, ")%s\n", at);
249
fn->ctx->print(fn->ctx, "}\n");
256
bool function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
261
Dwarf_Attribute attr_mem;
262
Dwarf_Attribute* attr;
266
dwarf_lowpc(d, &fn->info.lowpc);
267
dwarf_highpc(d, &fn->info.highpc);
273
unw_proc_info_t info;
274
unw_get_proc_info(&fn->context, &info);
275
fn->ctx->clean_print(fn->ctx);
277
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",
278
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);
279
fn->ctx->print_registers(fn->ctx, 0x0, 0x10);
280
pst_log(SEVERITY_INFO, "Function %s(...): CFA: %#lX %s", dwarf_diename(d), fn->parent ? fn->parent->info.sp : 0, fn->ctx->buff);
281
pst_log(SEVERITY_INFO, "Function %s(...): %s", dwarf_diename(d), fn->ctx->buff);
284
attr = dwarf_attr(fn->die, DW_AT_frame_base, &attr_mem);
286
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
289
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
290
fn->ctx->print_expr(fn->ctx, expr, exprlen, attr);
291
pst_decl(pst_dwarf_stack, stack, fn->ctx);
292
if(pst_dwarf_stack_calc(&stack, expr, exprlen, attr, fn)) {
294
if(pst_dwarf_stack_get_value(&stack, &value)) {
295
pst_log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", fn->ctx->buff, value);
297
pst_log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_framebase expression: %s", fn->ctx->buff);
300
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_framebase expression: %s", fn->ctx->buff);
302
pst_dwarf_stack_fini(&stack);
304
pst_log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
311
pst_parameter* ret_p = add_param(fn); ret_p->info.flags |= PARAM_RETURN;
312
if(dwarf_hasattr(fn->die, DW_AT_type)) {
313
if(!parameter_handle_type(ret_p, fn->die)) {
314
pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->info.name);
318
parameter_add_type(ret_p, "void", PARAM_TYPE_VOID);
338
if(dwarf_child(fn->die, &result) != 0)
343
switch (dwarf_tag(&result)) {
344
case DW_TAG_formal_parameter:
345
case DW_TAG_variable: {
346
pst_parameter* param = add_param(fn);
347
if(!parameter_handle_dwarf(param, &result, fn)) {
353
case DW_TAG_GNU_call_site:
354
pst_call_site_storage_handle_dwarf(&fn->call_sites, &result, fn);
361
case DW_TAG_lexical_block: {
362
handle_lexical_block(fn, &result);
365
case DW_TAG_unspecified_parameters: {
366
pst_parameter* param = add_param(fn);
367
param->info.flags |= PARAM_TYPE_UNSPEC;
368
param->info.name = pst_strdup("...");
375
pst_log(SEVERITY_WARNING, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
378
} while(dwarf_siblingof(&result, &result) == 0);
383
bool function_unwind(pst_function* fn)
385
Dwfl_Line *dwline = dwfl_getsrc(fn->ctx->dwfl, fn->info.pc);
387
const char* filename = dwfl_lineinfo (dwline, &fn->info.pc, &fn->info.line, NULL, NULL, NULL);
389
const char* file = strrchr(filename, '/');
390
if(file && *file != 0) {
395
fn->info.file = pst_strdup(file);
399
Dwfl_Module* module = dwfl_addrmodule(fn->ctx->dwfl, fn->info.pc);
400
const char* addrname = dwfl_module_addrname(module, fn->info.pc);
402
char* demangle_name = cplus_demangle(addrname, 0);
403
char* function_name = NULL;
404
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
405
pst_log(SEVERITY_ERROR, "Failed to allocate memory");
409
char* str = strchr(function_name, '(');
413
fn->info.name = pst_strdup(function_name);
424
void pst_function_init(pst_function* fn, pst_context* _ctx, pst_function* _parent)
426
list_node_init(&fn->node);
432
fn->info.name = NULL;
434
fn->info.file = NULL;
439
bzero(&fn->context, sizeof(fn->context));
441
list_head_init(&fn->params);
442
pst_call_site_storage_init(&fn->call_sites, _ctx);
444
memcpy(&fn->context, &_ctx->cursor, sizeof(fn->context));
445
fn->parent = _parent;
448
fn->allocated = false;
451
pst_function* pst_function_new(pst_context* _ctx, pst_function* _parent)
453
pst_function* fn = pst_alloc(pst_function);
455
pst_function_init(fn, _ctx, _parent);
456
fn->allocated = true;
462
void pst_function_fini(pst_function* fn)
472
pst_free(fn->info.name);
476
pst_free(fn->info.file);