10
#include <elfutils/libdw.h>
12
#include "dwarf_call_site.h"
13
#include "dwarf_function.h"
14
#include "dwarf_utils.h"
15
#include "dwarf_utils.h"
16
#include "utils/hash_multimap.h"
21
void pst_call_site_param_init(pst_call_site_param* param)
27
pst_dwarf_expr_init(¶m->location);
28
param->allocated = false;
31
pst_call_site_param* pst_call_site_param_new()
33
pst_call_site_param* param = pst_alloc(pst_call_site_param);
35
pst_call_site_param_init(param);
36
param->allocated = true;
42
void pst_call_site_param_fini(pst_call_site_param* param)
45
pst_free(param->name);
49
if(param->allocated) {
57
static pst_call_site_param* add_param(pst_call_site* site)
59
pst_call_site_param* p = pst_call_site_param_new();
60
pst_call_site_param_init(p);
61
list_add_bottom(&site->params, &p->node);
66
static void del_param(pst_call_site_param* p)
69
pst_call_site_param_fini(p);
72
static pst_call_site_param* next_param(pst_call_site* site, pst_call_site_param* p)
74
list_node* n = (p == NULL) ? list_first(&site->params) : list_next(&p->node);
75
pst_call_site_param* ret = NULL;
77
ret = list_entry(n, pst_call_site_param, node);
83
pst_call_site_param* pst_call_site_find(pst_call_site* site, pst_dwarf_expr* expr)
85
for(pst_call_site_param* param = next_param(site, NULL); param; param = next_param(site, param)) {
86
if(pst_dwarf_expr_equal(¶m->location, expr)) {
94
bool call_site_handle_dwarf(pst_call_site* site, Dwarf_Die* child)
96
Dwarf_Attribute attr_mem;
97
Dwarf_Attribute* attr;
100
switch(dwarf_tag(child)) {
101
case DW_TAG_GNU_call_site_parameter: {
103
unw_get_reg(site->ctx->curr_frame, UNW_REG_IP, &pc);
106
pst_call_site_param* param = add_param(site);
107
if(dwarf_hasattr(child, DW_AT_location)) {
109
attr = dwarf_attr(child, DW_AT_location, &attr_mem);
110
if(!handle_location(site->ctx, attr, ¶m->location, pc, NULL)) {
111
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
115
pst_log(SEVERITY_DEBUG, " DW_AT_location: %s", site->ctx->buff);
119
if(dwarf_hasattr(child, DW_AT_GNU_call_site_value)) {
121
attr = dwarf_attr(child, DW_AT_GNU_call_site_value, &attr_mem);
122
pst_decl0(pst_dwarf_expr, loc);
123
if(handle_location(site->ctx, attr, &loc, pc, NULL)) {
124
param->value = loc.value;
125
pst_dwarf_expr_fini(&loc);
126
pst_log(SEVERITY_DEBUG, " DW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", site->ctx->buff, param->value);
128
pst_log(SEVERITY_WARNING, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
130
pst_dwarf_expr_fini(&loc);
139
} while (dwarf_siblingof (child, child) == 0);
144
void pst_call_site_init(pst_call_site* site, pst_context* c, uint64_t tgt, const char* orn)
146
list_node_init(&site->node);
150
site->origin = pst_strdup(orn);
155
list_head_init(&site->params);
157
site->allocated = false;
160
pst_call_site* pst_call_site_new(pst_context* c, uint64_t tgt, const char* orn)
162
pst_call_site* nc = pst_alloc(pst_call_site);
164
pst_call_site_init(nc, c, tgt, orn);
165
nc->allocated = true;
171
void pst_call_site_fini(pst_call_site* site)
174
pst_free(site->origin);
178
if(site->allocated) {
198
bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* fn)
201
Dwarf_Attribute attr_mem;
202
Dwarf_Attribute* attr;
204
pst_log(SEVERITY_DEBUG, "***** DW_TAG_GNU_call_site contents:");
206
const char* oname = NULL;
207
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
208
oname = dwarf_diename(&origin);
209
pst_log(SEVERITY_DEBUG, "DW_AT_abstract_origin: '%s'", oname);
215
if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) {
216
attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
218
pst_decl0(pst_dwarf_expr, expr);
219
if(handle_location(storage->ctx, &attr_mem, &expr, fn->info.pc, fn)) {
221
pst_log(SEVERITY_DEBUG, "DW_AT_GNU_call_site_target: %#lX", target);
223
pst_dwarf_expr_fini(&expr);
227
if(target == 0 && oname == NULL) {
228
pst_log(SEVERITY_ERROR, "Cannot determine both call-site target and origin");
233
if(dwarf_child (result, &child) == 0) {
234
pst_call_site* st = pst_call_site_storage_add(storage, target, oname);
236
st->tail_call = (dwarf_hasattr(result, DW_AT_call_tail_call) != 0);
239
if(dwarf_hasattr (result, DW_AT_low_pc) && dwarf_attr(result, DW_AT_low_pc, &attr_mem)) {
240
if(!dwarf_formaddr(&attr_mem, &st->call_pc)) {
241
pst_log(SEVERITY_DEBUG, "DW_AT_low_pc: %#lX", st->call_pc);
245
if(!call_site_handle_dwarf(st, &child)) {
246
pst_call_site_storage_del(storage, st);
254
pst_call_site* storage_call_site_by_origin(pst_call_site_storage* storage, const char* origin)
256
pst_call_site* ret = NULL;
257
hash_node* node = hash_find(&storage->cs_to_origin, origin, strlen(origin));
259
ret = hash_entry(node, pst_call_site, org_node);
265
pst_call_site* storage_call_site_by_target(pst_call_site_storage* storage, uint64_t target)
267
pst_call_site* ret = NULL;
268
hash_node* node = hash_find(&storage->cs_to_target, (char*)&target, sizeof(target));
270
ret = hash_entry(node, pst_call_site, tgt_node);
276
pst_call_site* pst_call_site_storage_add(pst_call_site_storage* storage, uint64_t target, const char* origin)
278
pst_new(pst_call_site, st, storage->ctx, target, origin);
279
list_add_bottom(&storage->call_sites, &st->node);
282
hash_add(&storage->cs_to_target, &st->tgt_node, &target, sizeof(target));
284
hash_add(&storage->cs_to_origin, &st->org_node, origin, strlen(origin));
290
void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st)
292
hash_node* node = NULL;
296
node = hash_find(&storage->cs_to_target, &st->target, sizeof(st->target));
297
} else if(st->origin) {
298
node = hash_find(&storage->cs_to_origin, st->origin, strlen(st->origin));
308
pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_function* callee)
310
uint64_t start_pc = storage->ctx->base_addr + callee->info.lowpc;
311
pst_call_site* cs = storage_call_site_by_target(storage, start_pc);
313
cs = storage_call_site_by_origin(storage, callee->info.name);
319
void pst_call_site_storage_init(pst_call_site_storage* storage, pst_context* ctx)
322
list_head_init(&storage->call_sites);
323
hash_head_init(&storage->cs_to_target, HASH_MIN_SHIFT, 0, 0);
324
hash_head_init(&storage->cs_to_origin, HASH_MIN_SHIFT, 0 ,0);
325
storage->allocated = false;
328
pst_call_site_storage* pst_call_site_storage_new(pst_context* ctx)
330
pst_call_site_storage* ns = pst_alloc(pst_call_site_storage);
332
pst_call_site_storage_init(ns, ctx);
333
ns->allocated = true;
339
void pst_call_site_storage_fini(pst_call_site_storage* storage)
341
pst_call_site* site = NULL;
342
struct list_node *pos, *tn;
343
list_for_each_entry_safe(site, pos, tn, &storage->call_sites, node) {
344
list_del(&site->node);
345
pst_call_site_fini(site);
348
if(storage->allocated) {