do not use struct function pointers elsewhere, use them only in case
when polymorphysm needed
This commit is contained in:
@@ -17,16 +17,8 @@
|
|||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// pst_call_site_param
|
// pst_call_site_param
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void param_set_location(pst_call_site_param* param, Dwarf_Op* expr, size_t exprlen)
|
|
||||||
{
|
|
||||||
param->location.setup(¶m->location, expr, exprlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pst_call_site_param_init(pst_call_site_param* param)
|
void pst_call_site_param_init(pst_call_site_param* param)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
param->set_location = param_set_location;
|
|
||||||
|
|
||||||
// fields
|
// fields
|
||||||
param->param = NULL;
|
param->param = NULL;
|
||||||
param->name = NULL;
|
param->name = NULL;
|
||||||
@@ -61,7 +53,7 @@ void pst_call_site_param_fini(pst_call_site_param* param)
|
|||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// pst_call_site
|
// pst_call_site
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
pst_call_site_param* site_add_param(pst_call_site* site)
|
pst_call_site_param* add_param(pst_call_site* site)
|
||||||
{
|
{
|
||||||
pst_call_site_param* p = pst_call_site_param_new();
|
pst_call_site_param* p = pst_call_site_param_new();
|
||||||
pst_call_site_param_init(p);
|
pst_call_site_param_init(p);
|
||||||
@@ -70,13 +62,13 @@ pst_call_site_param* site_add_param(pst_call_site* site)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void site_del_param(pst_call_site*, pst_call_site_param* p)
|
void del_param(pst_call_site*, pst_call_site_param* p)
|
||||||
{
|
{
|
||||||
list_del(&p->node);
|
list_del(&p->node);
|
||||||
pst_call_site_param_fini(p);
|
pst_call_site_param_fini(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_call_site_param* site_next_param(pst_call_site* site, pst_call_site_param* p)
|
pst_call_site_param* next_param(pst_call_site* site, pst_call_site_param* p)
|
||||||
{
|
{
|
||||||
list_node* n = (p == NULL) ? list_first(&site->params) : list_next(&p->node);
|
list_node* n = (p == NULL) ? list_first(&site->params) : list_next(&p->node);
|
||||||
pst_call_site_param* ret = NULL;
|
pst_call_site_param* ret = NULL;
|
||||||
@@ -87,10 +79,10 @@ pst_call_site_param* site_next_param(pst_call_site* site, pst_call_site_param* p
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_call_site_param* site_find_param(pst_call_site* site, pst_dwarf_expr* expr)
|
pst_call_site_param* pst_call_site_find(pst_call_site* site, pst_dwarf_expr* expr)
|
||||||
{
|
{
|
||||||
for(pst_call_site_param* param = site_next_param(site, NULL); param; param = site_next_param(site, param)) {
|
for(pst_call_site_param* param = next_param(site, NULL); param; param = next_param(site, param)) {
|
||||||
if(param->location.is_equal(¶m->location, expr)) {
|
if(pst_dwarf_expr_equal(¶m->location, expr)) {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +90,7 @@ pst_call_site_param* site_find_param(pst_call_site* site, pst_dwarf_expr* expr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool site_handle_dwarf(pst_call_site* site, Dwarf_Die* child)
|
bool handle_dwarf(pst_call_site* site, Dwarf_Die* child)
|
||||||
{
|
{
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
@@ -110,14 +102,14 @@ bool site_handle_dwarf(pst_call_site* site, Dwarf_Die* child)
|
|||||||
unw_get_reg(site->ctx->curr_frame, UNW_REG_IP, &pc);
|
unw_get_reg(site->ctx->curr_frame, UNW_REG_IP, &pc);
|
||||||
|
|
||||||
// expression represent where callee parameter will be stored
|
// expression represent where callee parameter will be stored
|
||||||
pst_call_site_param* param = site->add_param(site);
|
pst_call_site_param* param = add_param(site);
|
||||||
if(dwarf_hasattr(child, DW_AT_location)) {
|
if(dwarf_hasattr(child, DW_AT_location)) {
|
||||||
// handle location expression here
|
// handle location expression here
|
||||||
// determine location of parameter in stack/heap or CPU registers
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
attr = dwarf_attr(child, DW_AT_location, &attr_mem);
|
attr = dwarf_attr(child, DW_AT_location, &attr_mem);
|
||||||
if(!handle_location(site->ctx, attr, ¶m->location, pc, NULL)) {
|
if(!handle_location(site->ctx, attr, ¶m->location, pc, NULL)) {
|
||||||
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
|
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
|
||||||
site->del_param(site, param);
|
del_param(site, param);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +125,7 @@ bool site_handle_dwarf(pst_call_site* site, Dwarf_Die* child)
|
|||||||
pst_log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", site->ctx->buff, param->value);
|
pst_log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", site->ctx->buff, param->value);
|
||||||
} else {
|
} else {
|
||||||
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
|
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", site->ctx->buff);
|
||||||
site->del_param(site, param);
|
del_param(site, param);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,14 +141,6 @@ bool site_handle_dwarf(pst_call_site* site, Dwarf_Die* child)
|
|||||||
|
|
||||||
void pst_call_site_init(pst_call_site* site, pst_context* c, uint64_t tgt, const char* orn)
|
void pst_call_site_init(pst_call_site* site, pst_context* c, uint64_t tgt, const char* orn)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
site->add_param = site_add_param;
|
|
||||||
site->del_param = site_del_param;
|
|
||||||
site->next_param = site_next_param;
|
|
||||||
site->find_param = site_find_param;
|
|
||||||
site->handle_dwarf = site_handle_dwarf;
|
|
||||||
|
|
||||||
// fields
|
|
||||||
list_node_init(&site->node);
|
list_node_init(&site->node);
|
||||||
|
|
||||||
site->target = tgt;
|
site->target = tgt;
|
||||||
@@ -209,7 +193,7 @@ void pst_call_site_fini(pst_call_site* site)
|
|||||||
// DW_TAG_GNU_call_site_parameter is defined under child DIE of DW_TAG_GNU_call_site and defines value of subroutine before calling it
|
// DW_TAG_GNU_call_site_parameter is defined under child DIE of DW_TAG_GNU_call_site and defines value of subroutine before calling it
|
||||||
// relates to DW_OP_GNU_entry_value() handling in callee function to determine the value of an argument/variable of the callee
|
// relates to DW_OP_GNU_entry_value() handling in callee function to determine the value of an argument/variable of the callee
|
||||||
// get DIE of return type
|
// get DIE of return type
|
||||||
bool storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* info)
|
bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* info)
|
||||||
{
|
{
|
||||||
Dwarf_Die origin;
|
Dwarf_Die origin;
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
@@ -246,9 +230,9 @@ bool storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst
|
|||||||
|
|
||||||
Dwarf_Die child;
|
Dwarf_Die child;
|
||||||
if(dwarf_child (result, &child) == 0) {
|
if(dwarf_child (result, &child) == 0) {
|
||||||
pst_call_site* st = storage->add_call_site(storage, target, oname);
|
pst_call_site* st = pst_call_site_storage_add(storage, target, oname);
|
||||||
if(!st->handle_dwarf(st, &child)) {
|
if(!handle_dwarf(st, &child)) {
|
||||||
storage->del_call_site(storage, st);
|
pst_call_site_storage_del(storage, st);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,7 +262,7 @@ pst_call_site* storage_call_site_by_target(pst_call_site_storage* storage, uint6
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_call_site* storage_add_call_site(pst_call_site_storage* storage, uint64_t target, const char* origin)
|
pst_call_site* pst_call_site_storage_add(pst_call_site_storage* storage, uint64_t target, const char* origin)
|
||||||
{
|
{
|
||||||
pst_new(pst_call_site, st, storage->ctx, target, origin);
|
pst_new(pst_call_site, st, storage->ctx, target, origin);
|
||||||
list_add_bottom(&storage->call_sites, &st->node);
|
list_add_bottom(&storage->call_sites, &st->node);
|
||||||
@@ -292,7 +276,7 @@ pst_call_site* storage_add_call_site(pst_call_site_storage* storage, uint64_t ta
|
|||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_del_call_site(pst_call_site_storage* storage, pst_call_site* st)
|
void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st)
|
||||||
{
|
{
|
||||||
hash_node* node = NULL;
|
hash_node* node = NULL;
|
||||||
list_del(&st->node);
|
list_del(&st->node);
|
||||||
@@ -309,19 +293,8 @@ void storage_del_call_site(pst_call_site_storage* storage, pst_call_site* st)
|
|||||||
|
|
||||||
pst_free(st);
|
pst_free(st);
|
||||||
}
|
}
|
||||||
pst_call_site* storage_next_call_site(pst_call_site_storage* storage, pst_call_site* st)
|
|
||||||
{
|
|
||||||
struct list_node* n = (st == NULL) ? list_first(&storage->call_sites) : list_next(&st->node);
|
|
||||||
|
|
||||||
pst_call_site* ret = NULL;
|
pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_function* callee)
|
||||||
if(n) {
|
|
||||||
ret = list_entry(n, pst_call_site, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_call_site* storage_find_call_site(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->lowpc;
|
||||||
pst_call_site* cs = storage_call_site_by_target(storage, start_pc);
|
pst_call_site* cs = storage_call_site_by_target(storage, start_pc);
|
||||||
@@ -334,14 +307,6 @@ pst_call_site* storage_find_call_site(pst_call_site_storage* storage, pst_functi
|
|||||||
|
|
||||||
void pst_call_site_storage_init(pst_call_site_storage* storage, pst_context* ctx)
|
void pst_call_site_storage_init(pst_call_site_storage* storage, pst_context* ctx)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
storage->handle_dwarf = storage_handle_dwarf;
|
|
||||||
storage->add_call_site = storage_add_call_site;
|
|
||||||
storage->del_call_site = storage_del_call_site;
|
|
||||||
storage->find_call_site = storage_find_call_site;
|
|
||||||
storage->next_call_site = storage_next_call_site;
|
|
||||||
|
|
||||||
// fields
|
|
||||||
storage->ctx = ctx;
|
storage->ctx = ctx;
|
||||||
list_head_init(&storage->call_sites);
|
list_head_init(&storage->call_sites);
|
||||||
hash_head_init(&storage->cs_to_target);
|
hash_head_init(&storage->cs_to_target);
|
||||||
|
|||||||
+17
-28
@@ -29,15 +29,11 @@ typedef struct pst_callee_info {
|
|||||||
typedef struct pst_call_site_param {
|
typedef struct pst_call_site_param {
|
||||||
list_node node; // uplink. !!! must be first !!!
|
list_node node; // uplink. !!! must be first !!!
|
||||||
|
|
||||||
// methods
|
Dwarf_Die* param; // reference to parameter DIE in callee (DW_AT_call_parameter)
|
||||||
void (*set_location) (pst_call_site_param* param, Dwarf_Op* expr, size_t exprlen);
|
char* name; // name of parameter if present (DW_AT_name)
|
||||||
|
pst_dwarf_expr location; // DWARF stack containing location expression
|
||||||
// fields
|
uint64_t value; // parameter's value
|
||||||
Dwarf_Die* param; // reference to parameter DIE in callee (DW_AT_call_parameter)
|
bool allocated; // whether this object was allocated or not
|
||||||
char* name; // name of parameter if present (DW_AT_name)
|
|
||||||
pst_dwarf_expr location; // DWARF stack containing location expression
|
|
||||||
uint64_t value; // parameter's value
|
|
||||||
bool allocated; // whether this object was allocated or not
|
|
||||||
} pst_call_site_param;
|
} pst_call_site_param;
|
||||||
|
|
||||||
void pst_call_site_param_init(pst_call_site_param* param);
|
void pst_call_site_param_init(pst_call_site_param* param);
|
||||||
@@ -49,18 +45,10 @@ void pst_call_site_param_fini(pst_call_site_param* param);
|
|||||||
// DW_TAG_call_site
|
// DW_TAG_call_site
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
typedef struct pst_call_site {
|
typedef struct pst_call_site {
|
||||||
list_node node; // uplink. !!! must be first !!!
|
list_node node; // uplink to list of call-sites
|
||||||
hash_node tgt_node;
|
hash_node tgt_node; // uplink to call-site by node dictionary
|
||||||
hash_node org_node;
|
hash_node org_node; // uplink to call-site by origin dictionary
|
||||||
|
|
||||||
// methods
|
|
||||||
pst_call_site_param* (*add_param) (pst_call_site* site);
|
|
||||||
void (*del_param) (pst_call_site* site, pst_call_site_param* p);
|
|
||||||
pst_call_site_param* (*next_param) (pst_call_site* site, pst_call_site_param* p);
|
|
||||||
pst_call_site_param* (*find_param) (pst_call_site* site, pst_dwarf_expr* expr);
|
|
||||||
bool (*handle_dwarf) (pst_call_site* site, Dwarf_Die* die);
|
|
||||||
|
|
||||||
// fields
|
|
||||||
uint64_t target; // pointer to callee function's (it's Low PC + base address)
|
uint64_t target; // pointer to callee function's (it's Low PC + base address)
|
||||||
char* origin; // name of callee function
|
char* origin; // name of callee function
|
||||||
Dwarf_Die* die; // DIE of function for which this call site has parameters
|
Dwarf_Die* die; // DIE of function for which this call site has parameters
|
||||||
@@ -72,19 +60,14 @@ void pst_call_site_init(pst_call_site* site, pst_context* context, uint64_t targ
|
|||||||
pst_call_site* pst_call_site_new(pst_context* context, uint64_t target, const char* origin);
|
pst_call_site* pst_call_site_new(pst_context* context, uint64_t target, const char* origin);
|
||||||
void pst_call_site_fini(pst_call_site* site);
|
void pst_call_site_fini(pst_call_site* site);
|
||||||
|
|
||||||
|
pst_call_site_param* pst_call_site_find(pst_call_site* site, pst_dwarf_expr* expr);
|
||||||
|
bool pst_call_site_handle_dwarf(pst_call_site* site, Dwarf_Die* child);
|
||||||
|
|
||||||
typedef struct __pst_function pst_function;
|
typedef struct __pst_function pst_function;
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// storage for all of function's call sites
|
// storage for all of function's call sites
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
typedef struct pst_call_site_storage {
|
typedef struct pst_call_site_storage {
|
||||||
// methods
|
|
||||||
bool (*handle_dwarf) (pst_call_site_storage* storage, Dwarf_Die* result, pst_function* info);
|
|
||||||
pst_call_site* (*add_call_site) (pst_call_site_storage* storage, uint64_t target, const char* origin);
|
|
||||||
void (*del_call_site) (pst_call_site_storage* storage, pst_call_site* site);
|
|
||||||
pst_call_site* (*find_call_site) (pst_call_site_storage* storage, pst_function* callee);
|
|
||||||
pst_call_site* (*next_call_site) (pst_call_site_storage* storage, pst_call_site* st);
|
|
||||||
|
|
||||||
// fields
|
|
||||||
pst_context* ctx;
|
pst_context* ctx;
|
||||||
list_head call_sites; // Call-Site definitions
|
list_head call_sites; // Call-Site definitions
|
||||||
hash_head cs_to_target; // map pointer to caller to call-site
|
hash_head cs_to_target; // map pointer to caller to call-site
|
||||||
@@ -96,5 +79,11 @@ void pst_call_site_storage_init(pst_call_site_storage* storage, pst_context* ctx
|
|||||||
pst_call_site_storage* pst_call_site_storage_new(pst_context* ctx);
|
pst_call_site_storage* pst_call_site_storage_new(pst_context* ctx);
|
||||||
void pst_call_site_storage_fini(pst_call_site_storage* storage);
|
void pst_call_site_storage_fini(pst_call_site_storage* storage);
|
||||||
|
|
||||||
|
bool pst_call_site_storage_handle_dwarf(pst_call_site_storage* storage, Dwarf_Die* result, pst_function* info);
|
||||||
|
pst_call_site* pst_call_site_storage_find(pst_call_site_storage* storage, pst_function* callee);
|
||||||
|
pst_call_site* pst_call_site_storage_add(pst_call_site_storage* storage, uint64_t target, const char* origin);
|
||||||
|
void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st);
|
||||||
|
void pst_call_site_storage_del(pst_call_site_storage* storage, pst_call_site* st);
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DWARF_CALL_SITE_H_ */
|
#endif /* FRAMEWORK_DWARF_CALL_SITE_H_ */
|
||||||
|
|||||||
@@ -53,26 +53,7 @@ void pst_dwarf_op_fini(pst_dwarf_op* dwop)
|
|||||||
//
|
//
|
||||||
// pst_dwarf_expr
|
// pst_dwarf_expr
|
||||||
//
|
//
|
||||||
bool expr_is_equal(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs)
|
pst_dwarf_op* add_op(pst_dwarf_expr* expr, uint8_t operation, uint64_t arg1, uint64_t arg2)
|
||||||
{
|
|
||||||
if(list_count(&lhs->operations) != list_count(&rhs->operations)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_dwarf_op* lop = lhs->next_op(lhs, NULL);
|
|
||||||
pst_dwarf_op* rop = rhs->next_op(rhs, NULL);
|
|
||||||
while(lop && rop) {
|
|
||||||
if(lop->operation == rop->operation && lop->arg1 == rop->arg1 && lop->arg2 == rop->arg2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
lop = lhs->next_op(lhs, lop);
|
|
||||||
rop = rhs->next_op(rhs, rop);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_dwarf_op* expr_add_op(pst_dwarf_expr* expr, uint8_t operation, uint64_t arg1, uint64_t arg2)
|
|
||||||
{
|
{
|
||||||
pst_new(pst_dwarf_op, op, operation, arg1, arg2);
|
pst_new(pst_dwarf_op, op, operation, arg1, arg2);
|
||||||
list_add_bottom(&expr->operations, &op->node);
|
list_add_bottom(&expr->operations, &op->node);
|
||||||
@@ -80,7 +61,7 @@ pst_dwarf_op* expr_add_op(pst_dwarf_expr* expr, uint8_t operation, uint64_t arg1
|
|||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_dwarf_op* expr_next_op(pst_dwarf_expr* expr, pst_dwarf_op* op)
|
pst_dwarf_op* next_op(pst_dwarf_expr* expr, pst_dwarf_op* op)
|
||||||
{
|
{
|
||||||
struct list_node* n = (op == NULL) ? list_first(&expr->operations) : list_next(&op->node);
|
struct list_node* n = (op == NULL) ? list_first(&expr->operations) : list_next(&op->node);
|
||||||
|
|
||||||
@@ -92,7 +73,17 @@ pst_dwarf_op* expr_next_op(pst_dwarf_expr* expr, pst_dwarf_op* op)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool expr_print_op(pst_dwarf_expr* expr, const char* fmt, ...)
|
void clean(pst_dwarf_expr* expr)
|
||||||
|
{
|
||||||
|
pst_dwarf_op* op = NULL;
|
||||||
|
struct list_node *pos, *tn;
|
||||||
|
list_for_each_entry_safe(op, pos, tn, &expr->operations, node) {
|
||||||
|
list_del(&op->node);
|
||||||
|
pst_dwarf_op_fini(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_dwarf_expr_print_op(pst_dwarf_expr* expr, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
bool nret = true;
|
bool nret = true;
|
||||||
|
|
||||||
@@ -109,42 +100,41 @@ bool expr_print_op(pst_dwarf_expr* expr, const char* fmt, ...)
|
|||||||
return nret;
|
return nret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_set_value(pst_dwarf_expr* expr, uint64_t v)
|
void pst_dwarf_expr_set_value(pst_dwarf_expr* expr, uint64_t v)
|
||||||
{
|
{
|
||||||
expr->has_value = true;
|
expr->has_value = true;
|
||||||
expr->value = v;
|
expr->value = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_clean(pst_dwarf_expr* expr)
|
bool pst_dwarf_expr_equal(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs)
|
||||||
{
|
{
|
||||||
pst_dwarf_op* op = NULL;
|
if(list_count(&lhs->operations) != list_count(&rhs->operations)) {
|
||||||
struct list_node *pos, *tn;
|
return false;
|
||||||
list_for_each_entry_safe(op, pos, tn, &expr->operations, node) {
|
|
||||||
list_del(&op->node);
|
|
||||||
pst_dwarf_op_fini(op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pst_dwarf_op* lop = next_op(lhs, NULL);
|
||||||
|
pst_dwarf_op* rop = next_op(rhs, NULL);
|
||||||
|
while(lop && rop) {
|
||||||
|
if(lop->operation == rop->operation && lop->arg1 == rop->arg1 && lop->arg2 == rop->arg2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
lop = next_op(lhs, lop);
|
||||||
|
rop = next_op(rhs, rop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_setup(pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen)
|
void pst_dwarf_expr_setup(pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen)
|
||||||
{
|
{
|
||||||
expr->clean(expr);
|
clean(expr);
|
||||||
for(size_t i = 0; i < exprlen; ++i) {
|
for(size_t i = 0; i < exprlen; ++i) {
|
||||||
expr->add_op(expr, exprs[i].atom, exprs[i].number, exprs[i].number2);
|
add_op(expr, exprs[i].atom, exprs[i].number, exprs[i].number2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pst_dwarf_expr_init(pst_dwarf_expr* expr)
|
void pst_dwarf_expr_init(pst_dwarf_expr* expr)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
expr->is_equal = expr_is_equal;
|
|
||||||
expr->add_op = expr_add_op;
|
|
||||||
expr->next_op = expr_next_op;
|
|
||||||
expr->clean = expr_clean;
|
|
||||||
expr->setup = expr_setup;
|
|
||||||
expr->set_value = expr_set_value;
|
|
||||||
expr->print_op = expr_print_op;
|
|
||||||
|
|
||||||
// fields
|
|
||||||
list_head_init(&expr->operations);
|
list_head_init(&expr->operations);
|
||||||
expr->has_value = false;
|
expr->has_value = false;
|
||||||
expr->value = 0;
|
expr->value = 0;
|
||||||
@@ -167,7 +157,7 @@ pst_dwarf_expr* pst_dwarf_expr_new()
|
|||||||
|
|
||||||
void pst_dwarf_expr_fini(pst_dwarf_expr* expr)
|
void pst_dwarf_expr_fini(pst_dwarf_expr* expr)
|
||||||
{
|
{
|
||||||
expr->clean(expr);
|
clean(expr);
|
||||||
if(expr->allocated) {
|
if(expr->allocated) {
|
||||||
pst_free(expr);
|
pst_free(expr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,16 +30,6 @@ void pst_dwarf_op_fini(pst_dwarf_op* dwop);
|
|||||||
|
|
||||||
// DWARF expression
|
// DWARF expression
|
||||||
typedef struct pst_dwarf_expr {
|
typedef struct pst_dwarf_expr {
|
||||||
// methods
|
|
||||||
bool (*is_equal)(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs);
|
|
||||||
pst_dwarf_op* (*add_op) (pst_dwarf_expr* expr, uint8_t op, uint64_t arg1, uint64_t arg2);
|
|
||||||
pst_dwarf_op* (*next_op) (pst_dwarf_expr* expr, pst_dwarf_op* op);
|
|
||||||
void (*clean) (pst_dwarf_expr* expr);
|
|
||||||
void (*setup) (pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen);
|
|
||||||
void (*set_value) (pst_dwarf_expr* expr, uint64_t v);
|
|
||||||
bool (*print_op) (pst_dwarf_expr* expr, const char* fmt, ...);
|
|
||||||
|
|
||||||
// fields
|
|
||||||
list_head operations;
|
list_head operations;
|
||||||
bool has_value;
|
bool has_value;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
@@ -51,5 +41,9 @@ void pst_dwarf_expr_init(pst_dwarf_expr* expr);
|
|||||||
pst_dwarf_expr* pst_dwarf_expr_new();
|
pst_dwarf_expr* pst_dwarf_expr_new();
|
||||||
void pst_dwarf_expr_fini(pst_dwarf_expr* expr);
|
void pst_dwarf_expr_fini(pst_dwarf_expr* expr);
|
||||||
|
|
||||||
|
void pst_dwarf_expr_setup(pst_dwarf_expr* expr, Dwarf_Op* exprs, size_t exprlen);
|
||||||
|
bool pst_dwarf_expr_equal(pst_dwarf_expr* lhs, pst_dwarf_expr* rhs);
|
||||||
|
bool pst_dwarf_expr_print_op(pst_dwarf_expr* expr, const char* fmt, ...);
|
||||||
|
void pst_dwarf_expr_set_value(pst_dwarf_expr* expr, uint64_t v);
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DWARF_EXPRESSION_H_ */
|
#endif /* FRAMEWORK_DWARF_EXPRESSION_H_ */
|
||||||
|
|||||||
+342
-353
@@ -16,346 +16,7 @@
|
|||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// pst_function
|
// pst_function
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
pst_parameter* fn_add_param(pst_function* fn)
|
bool get_frame(pst_function* fn)
|
||||||
{
|
|
||||||
pst_new(pst_parameter, p, fn->ctx);
|
|
||||||
list_add_bottom(&fn->params, &p->node);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fn_del_param(pst_parameter* p)
|
|
||||||
{
|
|
||||||
list_del(&p->node);
|
|
||||||
pst_free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fn_clear(pst_function* fn)
|
|
||||||
{
|
|
||||||
pst_parameter* param = NULL;
|
|
||||||
struct list_node *pos, *tn;
|
|
||||||
list_for_each_entry_safe(param, pos, tn, &fn->params, node) {
|
|
||||||
list_del(¶m->node);
|
|
||||||
pst_parameter_fini(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_call_site_storage_fini(&fn->call_sites);
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_parameter* fn_next_param(pst_function* fn, pst_parameter* p)
|
|
||||||
{
|
|
||||||
struct list_node* n = (p == NULL) ? list_first(&fn->params) : list_next(&p->node);
|
|
||||||
|
|
||||||
pst_parameter* ret = NULL;
|
|
||||||
if(n) {
|
|
||||||
ret = list_entry(n, pst_parameter, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fn_print_dwarf(pst_function* fn)
|
|
||||||
{
|
|
||||||
char* at = NULL;
|
|
||||||
if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(at[4] == ':' && at[5] == '-') {
|
|
||||||
free(at);
|
|
||||||
if(!asprintf(&at, " at %p", (void*)fn->pc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ctx->print(ctx, "%s:%d: ", file.c_str(), line);
|
|
||||||
|
|
||||||
// handle return parameter and be safe if function haven't parameters (for example, dwar info for function is absent)
|
|
||||||
pst_parameter* param = fn->next_param(fn, NULL);
|
|
||||||
if(param && param->is_return) {
|
|
||||||
// print return value type, function name and start list of parameters
|
|
||||||
param->print_dwarf(param);
|
|
||||||
fn->ctx->print(fn->ctx, " %s(", fn->name);
|
|
||||||
param = fn->next_param(fn, param);
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, "%s(", fn->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool first = true; bool start_variable = false;
|
|
||||||
for(; param; param = fn->next_param(fn, param)) {
|
|
||||||
if(param->is_return) {
|
|
||||||
// print return value type, function name and start list of parameters
|
|
||||||
param->print_dwarf(param);
|
|
||||||
fn->ctx->print(fn->ctx, " %s(", fn->name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(param->is_variable) {
|
|
||||||
if(!start_variable) {
|
|
||||||
fn->ctx->print(fn->ctx, ")%s\n", at);
|
|
||||||
fn->ctx->print(fn->ctx, "{\n");
|
|
||||||
start_variable = true;
|
|
||||||
}
|
|
||||||
if(param->line) {
|
|
||||||
fn->ctx->print(fn->ctx, "%04u: ", param->line);
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, " ");
|
|
||||||
}
|
|
||||||
param->print_dwarf(param);
|
|
||||||
fn->ctx->print(fn->ctx, ";\n");
|
|
||||||
} else {
|
|
||||||
if(first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, ", ");
|
|
||||||
}
|
|
||||||
param->print_dwarf(param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!start_variable) {
|
|
||||||
fn->ctx->print(fn->ctx, ");%s\n", at);
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, "}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(at);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fn_handle_lexical_block(pst_function* fn, Dwarf_Die* result)
|
|
||||||
{
|
|
||||||
uint64_t lowpc = 0, highpc = 0; const char* origin_name = "";
|
|
||||||
dwarf_lowpc(result, &lowpc);
|
|
||||||
dwarf_highpc(result, &lowpc);
|
|
||||||
|
|
||||||
Dwarf_Attribute attr_mem;
|
|
||||||
Dwarf_Die origin;
|
|
||||||
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
|
||||||
origin_name = dwarf_diename(&origin);
|
|
||||||
Dwarf_Die child;
|
|
||||||
if(dwarf_child (&origin, &child) == 0) {
|
|
||||||
do {
|
|
||||||
switch (dwarf_tag (&child))
|
|
||||||
{
|
|
||||||
case DW_TAG_variable:
|
|
||||||
case DW_TAG_formal_parameter:
|
|
||||||
pst_log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
|
||||||
break;
|
|
||||||
// Also handle DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (dwarf_siblingof (&child, &child) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const char* die_name = "";
|
|
||||||
if(dwarf_diename(result)) {
|
|
||||||
die_name = dwarf_diename(result);
|
|
||||||
}
|
|
||||||
pst_log(SEVERITY_DEBUG, "Lexical block with name '%s', tag 0x%X and origin '%s' found. lowpc = 0x%lX, highpc = 0x%lX", die_name, dwarf_tag (result), origin_name, lowpc, highpc);
|
|
||||||
Dwarf_Die child;
|
|
||||||
if(dwarf_child (result, &child) == 0) {
|
|
||||||
do {
|
|
||||||
switch (dwarf_tag (&child)) {
|
|
||||||
case DW_TAG_lexical_block:
|
|
||||||
fn->handle_lexical_block(fn, &child);
|
|
||||||
break;
|
|
||||||
case DW_TAG_variable: {
|
|
||||||
pst_parameter* param = fn->add_param(fn);
|
|
||||||
if(!param->handle_dwarf(param, &child, fn)) {
|
|
||||||
fn->del_param(param);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DW_TAG_GNU_call_site:
|
|
||||||
fn->call_sites.handle_dwarf(&fn->call_sites, &child, fn);
|
|
||||||
break;
|
|
||||||
case DW_TAG_inlined_subroutine:
|
|
||||||
pst_log(SEVERITY_DEBUG, "Skipping Lexical block tag 'DW_TAG_inlined_subroutine'");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pst_log(SEVERITY_DEBUG, "Unknown Lexical block tag 0x%X", dwarf_tag(&child));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}while (dwarf_siblingof (&child, &child) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fn_handle_dwarf(pst_function * fn, Dwarf_Die* d)
|
|
||||||
{
|
|
||||||
fn->die = d;
|
|
||||||
fn->get_frame(fn);
|
|
||||||
|
|
||||||
Dwarf_Attribute attr_mem;
|
|
||||||
Dwarf_Attribute* attr;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
// } 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);
|
|
||||||
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->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(...): %s", dwarf_diename(d), fn->ctx->buff);
|
|
||||||
|
|
||||||
// determine function's stack frame base
|
|
||||||
attr = dwarf_attr(fn->die, DW_AT_frame_base, &attr_mem);
|
|
||||||
if(attr) {
|
|
||||||
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
|
||||||
Dwarf_Op *expr;
|
|
||||||
size_t exprlen;
|
|
||||||
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
|
|
||||||
fn->ctx->print_expr(fn->ctx, expr, exprlen, attr);
|
|
||||||
pst_decl(pst_dwarf_stack, stack, fn->ctx);
|
|
||||||
if(stack.calc(&stack, expr, exprlen, attr, fn)) {
|
|
||||||
uint64_t value;
|
|
||||||
if(stack.get_value(&stack, &value)) {
|
|
||||||
pst_log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", fn->ctx->buff, value);
|
|
||||||
} else {
|
|
||||||
pst_log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_framebase expression: %s", fn->ctx->buff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_framebase expression: %s", fn->ctx->buff);
|
|
||||||
}
|
|
||||||
pst_dwarf_stack_fini(&stack);
|
|
||||||
} else {
|
|
||||||
pst_log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get reference to return attribute type of the function
|
|
||||||
// may be to use dwfl_module_return_value_location() instead
|
|
||||||
pst_parameter* ret_p = fn->add_param(fn); ret_p->is_return = true;
|
|
||||||
attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem);
|
|
||||||
if(attr) {
|
|
||||||
if(!ret_p->handle_type(ret_p, attr)) {
|
|
||||||
pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->name);
|
|
||||||
fn->del_param(ret_p);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret_p->add_type(ret_p, "void", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle and save additionally these attributes:
|
|
||||||
// 1. string of DW_AT_linkage_name (mangled name of program if any)
|
|
||||||
// A debugging information entry may have a DW_AT_linkage_name attribute
|
|
||||||
// whose value is a null-terminated string containing the object file linkage name
|
|
||||||
// associated with the corresponding entity.
|
|
||||||
|
|
||||||
// 2. flag DW_AT_external attribute
|
|
||||||
// A DW_AT_external attribute, which is a flag, if the name of a variable is
|
|
||||||
// visible outside of its enclosing compilation unit.
|
|
||||||
|
|
||||||
// 3. A subroutine entry may contain a DW_AT_main_subprogram attribute which is
|
|
||||||
// a flag whose presence indicates that the subroutine has been identified as the
|
|
||||||
// starting function of the program. If more than one subprogram contains this flag,
|
|
||||||
// any one of them may be the starting subroutine of the program.
|
|
||||||
|
|
||||||
|
|
||||||
Dwarf_Die result;
|
|
||||||
if(dwarf_child(fn->die, &result) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// went through parameters and local variables of the function
|
|
||||||
do {
|
|
||||||
switch (dwarf_tag(&result)) {
|
|
||||||
case DW_TAG_formal_parameter:
|
|
||||||
case DW_TAG_variable: {
|
|
||||||
pst_parameter* param = fn->add_param(fn);
|
|
||||||
if(!param->handle_dwarf(param, &result, fn)) {
|
|
||||||
fn->del_param(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DW_TAG_GNU_call_site:
|
|
||||||
fn->call_sites.handle_dwarf(&fn->call_sites, &result, fn);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// case DW_TAG_inlined_subroutine:
|
|
||||||
// /* Recurse further down */
|
|
||||||
// HandleFunction(&result);
|
|
||||||
// break;
|
|
||||||
case DW_TAG_lexical_block: {
|
|
||||||
fn->handle_lexical_block(fn, &result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Also handle:
|
|
||||||
// DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
|
||||||
// DW_AT_inline
|
|
||||||
default:
|
|
||||||
pst_log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(dwarf_siblingof(&result, &result) == 0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fn_unwind(pst_function* fn, Dwarf_Addr addr)
|
|
||||||
{
|
|
||||||
fn->pc = addr;
|
|
||||||
|
|
||||||
Dwfl_Line *dwline = dwfl_getsrc(fn->ctx->dwfl, addr);
|
|
||||||
if(dwline != NULL) {
|
|
||||||
Dwarf_Addr addr;
|
|
||||||
const char* filename = dwfl_lineinfo (dwline, &addr, &fn->line, NULL, NULL, NULL);
|
|
||||||
if(filename) {
|
|
||||||
const char* str = strrchr(filename, '/');
|
|
||||||
if(str && *str != 0) {
|
|
||||||
str++;
|
|
||||||
} else {
|
|
||||||
str = filename;
|
|
||||||
}
|
|
||||||
fn->file = pst_strdup(str);
|
|
||||||
fn->ctx->print(fn->ctx, "%s:%d", str, fn->line);
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, "%p", (void*)addr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fn->ctx->print(fn->ctx, "%p", (void*)addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* addrname = dwfl_module_addrname(fn->ctx->module, addr);
|
|
||||||
char* demangle_name = NULL;
|
|
||||||
if(addrname) {
|
|
||||||
int status;
|
|
||||||
demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
|
|
||||||
char* function_name = NULL;
|
|
||||||
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
|
|
||||||
pst_log(SEVERITY_ERROR, "Failed to allocate memory");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fn->ctx->print(fn->ctx, " --> %s", function_name);
|
|
||||||
|
|
||||||
char* str = strchr(function_name, '(');
|
|
||||||
if(str) {
|
|
||||||
*str = 0;
|
|
||||||
}
|
|
||||||
fn->name = pst_strdup(function_name);
|
|
||||||
free(function_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(demangle_name) {
|
|
||||||
free(demangle_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fn_get_frame(pst_function* fn)
|
|
||||||
{
|
{
|
||||||
// get CFI (Call Frame Information) for current module
|
// get CFI (Call Frame Information) for current module
|
||||||
// from handle_cfi()
|
// from handle_cfi()
|
||||||
@@ -409,7 +70,7 @@ bool fn_get_frame(pst_function* fn)
|
|||||||
fn->ctx->print_expr(fn->ctx, cfa_ops, cfa_nops, NULL);
|
fn->ctx->print_expr(fn->ctx, cfa_ops, cfa_nops, NULL);
|
||||||
|
|
||||||
pst_decl(pst_dwarf_stack, stack, fn->ctx);
|
pst_decl(pst_dwarf_stack, stack, fn->ctx);
|
||||||
if(stack.calc(&stack, cfa_ops, cfa_nops, NULL, NULL) && stack.get_value(&stack, &fn->cfa)) {
|
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->name, fn->ctx->buff, fn->cfa);
|
pst_log(SEVERITY_INFO, "Function %s(...): CFA expression: %s ==> %#lX", fn->name, fn->ctx->buff, fn->cfa);
|
||||||
|
|
||||||
// setup context to match CFA for frame
|
// setup context to match CFA for frame
|
||||||
@@ -423,19 +84,347 @@ bool fn_get_frame(pst_function* fn)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pst_parameter* add_param(pst_function* fn)
|
||||||
|
{
|
||||||
|
pst_new(pst_parameter, p, fn->ctx);
|
||||||
|
list_add_bottom(&fn->params, &p->node);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_param(pst_parameter* p)
|
||||||
|
{
|
||||||
|
list_del(&p->node);
|
||||||
|
pst_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(pst_function* fn)
|
||||||
|
{
|
||||||
|
pst_parameter* param = NULL;
|
||||||
|
struct list_node *pos, *tn;
|
||||||
|
list_for_each_entry_safe(param, pos, tn, &fn->params, node) {
|
||||||
|
list_del(¶m->node);
|
||||||
|
pst_parameter_fini(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_call_site_storage_fini(&fn->call_sites);
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_parameter* next_param(pst_function* fn, pst_parameter* p)
|
||||||
|
{
|
||||||
|
struct list_node* n = (p == NULL) ? list_first(&fn->params) : list_next(&p->node);
|
||||||
|
|
||||||
|
pst_parameter* ret = NULL;
|
||||||
|
if(n) {
|
||||||
|
ret = list_entry(n, pst_parameter, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handle_lexical_block(pst_function* fn, Dwarf_Die* result)
|
||||||
|
{
|
||||||
|
uint64_t lowpc = 0, highpc = 0; const char* origin_name = "";
|
||||||
|
dwarf_lowpc(result, &lowpc);
|
||||||
|
dwarf_highpc(result, &lowpc);
|
||||||
|
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Die origin;
|
||||||
|
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
||||||
|
origin_name = dwarf_diename(&origin);
|
||||||
|
Dwarf_Die child;
|
||||||
|
if(dwarf_child (&origin, &child) == 0) {
|
||||||
|
do {
|
||||||
|
switch (dwarf_tag (&child))
|
||||||
|
{
|
||||||
|
case DW_TAG_variable:
|
||||||
|
case DW_TAG_formal_parameter:
|
||||||
|
pst_log(SEVERITY_DEBUG, "Abstract origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
||||||
|
break;
|
||||||
|
// Also handle DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (dwarf_siblingof (&child, &child) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* die_name = "";
|
||||||
|
if(dwarf_diename(result)) {
|
||||||
|
die_name = dwarf_diename(result);
|
||||||
|
}
|
||||||
|
pst_log(SEVERITY_DEBUG, "Lexical block with name '%s', tag 0x%X and origin '%s' found. lowpc = 0x%lX, highpc = 0x%lX", die_name, dwarf_tag (result), origin_name, lowpc, highpc);
|
||||||
|
Dwarf_Die child;
|
||||||
|
if(dwarf_child (result, &child) == 0) {
|
||||||
|
do {
|
||||||
|
switch (dwarf_tag (&child)) {
|
||||||
|
case DW_TAG_lexical_block:
|
||||||
|
handle_lexical_block(fn, &child);
|
||||||
|
break;
|
||||||
|
case DW_TAG_variable: {
|
||||||
|
pst_parameter* param = add_param(fn);
|
||||||
|
if(!pst_parameter_handle_dwarf(param, &child, fn)) {
|
||||||
|
del_param(param);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_TAG_GNU_call_site:
|
||||||
|
pst_call_site_storage_handle_dwarf(&fn->call_sites, &child, fn);
|
||||||
|
break;
|
||||||
|
case DW_TAG_inlined_subroutine:
|
||||||
|
pst_log(SEVERITY_DEBUG, "Skipping Lexical block tag 'DW_TAG_inlined_subroutine'");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pst_log(SEVERITY_DEBUG, "Unknown Lexical block tag 0x%X", dwarf_tag(&child));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while (dwarf_siblingof (&child, &child) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_function_print_dwarf(pst_function* fn)
|
||||||
|
{
|
||||||
|
char* at = NULL;
|
||||||
|
if(!asprintf(&at, " at %s:%d, %p", fn->file, fn->line, (void*)fn->pc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(at[4] == ':' && at[5] == '-') {
|
||||||
|
free(at);
|
||||||
|
if(!asprintf(&at, " at %p", (void*)fn->pc)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ctx->print(ctx, "%s:%d: ", file.c_str(), line);
|
||||||
|
|
||||||
|
// handle return parameter and be safe if function haven't parameters (for example, dwar info for function is absent)
|
||||||
|
pst_parameter* param = next_param(fn, NULL);
|
||||||
|
if(param && param->is_return) {
|
||||||
|
// print return value type, function name and start list of parameters
|
||||||
|
pst_parameter_print_dwarf(param);
|
||||||
|
fn->ctx->print(fn->ctx, " %s(", fn->name);
|
||||||
|
param = next_param(fn, param);
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, "%s(", fn->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool first = true; bool start_variable = false;
|
||||||
|
for(; param; param = next_param(fn, param)) {
|
||||||
|
if(param->is_return) {
|
||||||
|
// print return value type, function name and start list of parameters
|
||||||
|
pst_parameter_print_dwarf(param);
|
||||||
|
fn->ctx->print(fn->ctx, " %s(", fn->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(param->is_variable) {
|
||||||
|
if(!start_variable) {
|
||||||
|
fn->ctx->print(fn->ctx, ")%s\n", at);
|
||||||
|
fn->ctx->print(fn->ctx, "{\n");
|
||||||
|
start_variable = true;
|
||||||
|
}
|
||||||
|
if(param->line) {
|
||||||
|
fn->ctx->print(fn->ctx, "%04u: ", param->line);
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, " ");
|
||||||
|
}
|
||||||
|
pst_parameter_print_dwarf(param);
|
||||||
|
fn->ctx->print(fn->ctx, ";\n");
|
||||||
|
} else {
|
||||||
|
if(first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, ", ");
|
||||||
|
}
|
||||||
|
pst_parameter_print_dwarf(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!start_variable) {
|
||||||
|
fn->ctx->print(fn->ctx, ");%s\n", at);
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(at);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
|
||||||
|
{
|
||||||
|
fn->die = d;
|
||||||
|
get_frame(fn);
|
||||||
|
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// } 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);
|
||||||
|
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->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(...): %s", dwarf_diename(d), fn->ctx->buff);
|
||||||
|
|
||||||
|
// determine function's stack frame base
|
||||||
|
attr = dwarf_attr(fn->die, DW_AT_frame_base, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
||||||
|
Dwarf_Op *expr;
|
||||||
|
size_t exprlen;
|
||||||
|
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
|
||||||
|
fn->ctx->print_expr(fn->ctx, expr, exprlen, attr);
|
||||||
|
pst_decl(pst_dwarf_stack, stack, fn->ctx);
|
||||||
|
if(pst_dwarf_stack_calc(&stack, expr, exprlen, attr, fn)) {
|
||||||
|
uint64_t value;
|
||||||
|
if(pst_dwarf_stack_get_value(&stack, &value)) {
|
||||||
|
pst_log(SEVERITY_DEBUG, "DW_AT_framebase expression: \"%s\" ==> 0x%lX", fn->ctx->buff, value);
|
||||||
|
} else {
|
||||||
|
pst_log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_framebase expression: %s", fn->ctx->buff);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pst_log(SEVERITY_ERROR, "Failed to calculate DW_AT_framebase expression: %s", fn->ctx->buff);
|
||||||
|
}
|
||||||
|
pst_dwarf_stack_fini(&stack);
|
||||||
|
} else {
|
||||||
|
pst_log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get reference to return attribute type of the function
|
||||||
|
// may be to use dwfl_module_return_value_location() instead
|
||||||
|
pst_parameter* ret_p = add_param(fn); ret_p->is_return = true;
|
||||||
|
attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
if(!pst_parameter_handle_type(ret_p, attr)) {
|
||||||
|
pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->name);
|
||||||
|
del_param(ret_p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pst_parameter_add_type(ret_p, "void", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle and save additionally these attributes:
|
||||||
|
// 1. string of DW_AT_linkage_name (mangled name of program if any)
|
||||||
|
// A debugging information entry may have a DW_AT_linkage_name attribute
|
||||||
|
// whose value is a null-terminated string containing the object file linkage name
|
||||||
|
// associated with the corresponding entity.
|
||||||
|
|
||||||
|
// 2. flag DW_AT_external attribute
|
||||||
|
// A DW_AT_external attribute, which is a flag, if the name of a variable is
|
||||||
|
// visible outside of its enclosing compilation unit.
|
||||||
|
|
||||||
|
// 3. A subroutine entry may contain a DW_AT_main_subprogram attribute which is
|
||||||
|
// a flag whose presence indicates that the subroutine has been identified as the
|
||||||
|
// starting function of the program. If more than one subprogram contains this flag,
|
||||||
|
// any one of them may be the starting subroutine of the program.
|
||||||
|
|
||||||
|
|
||||||
|
Dwarf_Die result;
|
||||||
|
if(dwarf_child(fn->die, &result) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// went through parameters and local variables of the function
|
||||||
|
do {
|
||||||
|
switch (dwarf_tag(&result)) {
|
||||||
|
case DW_TAG_formal_parameter:
|
||||||
|
case DW_TAG_variable: {
|
||||||
|
pst_parameter* param = add_param(fn);
|
||||||
|
if(!pst_parameter_handle_dwarf(param, &result, fn)) {
|
||||||
|
del_param(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_TAG_GNU_call_site:
|
||||||
|
pst_call_site_storage_handle_dwarf(&fn->call_sites, &result, fn);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// case DW_TAG_inlined_subroutine:
|
||||||
|
// /* Recurse further down */
|
||||||
|
// HandleFunction(&result);
|
||||||
|
// break;
|
||||||
|
case DW_TAG_lexical_block: {
|
||||||
|
handle_lexical_block(fn, &result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Also handle:
|
||||||
|
// DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
||||||
|
// DW_AT_inline
|
||||||
|
default:
|
||||||
|
pst_log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(dwarf_siblingof(&result, &result) == 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_function_unwind(pst_function* fn, Dwarf_Addr addr)
|
||||||
|
{
|
||||||
|
fn->pc = addr;
|
||||||
|
|
||||||
|
Dwfl_Line *dwline = dwfl_getsrc(fn->ctx->dwfl, addr);
|
||||||
|
if(dwline != NULL) {
|
||||||
|
Dwarf_Addr addr;
|
||||||
|
const char* filename = dwfl_lineinfo (dwline, &addr, &fn->line, NULL, NULL, NULL);
|
||||||
|
if(filename) {
|
||||||
|
const char* str = strrchr(filename, '/');
|
||||||
|
if(str && *str != 0) {
|
||||||
|
str++;
|
||||||
|
} else {
|
||||||
|
str = filename;
|
||||||
|
}
|
||||||
|
fn->file = pst_strdup(str);
|
||||||
|
fn->ctx->print(fn->ctx, "%s:%d", str, fn->line);
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, "%p", (void*)addr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn->ctx->print(fn->ctx, "%p", (void*)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* addrname = dwfl_module_addrname(fn->ctx->module, addr);
|
||||||
|
char* demangle_name = NULL;
|
||||||
|
if(addrname) {
|
||||||
|
int status;
|
||||||
|
demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
|
||||||
|
char* function_name = NULL;
|
||||||
|
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
|
||||||
|
pst_log(SEVERITY_ERROR, "Failed to allocate memory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fn->ctx->print(fn->ctx, " --> %s", function_name);
|
||||||
|
|
||||||
|
char* str = strchr(function_name, '(');
|
||||||
|
if(str) {
|
||||||
|
*str = 0;
|
||||||
|
}
|
||||||
|
fn->name = pst_strdup(function_name);
|
||||||
|
free(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(demangle_name) {
|
||||||
|
free(demangle_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void pst_function_init(pst_function* fn, pst_context* _ctx, __pst_function* _parent)
|
void pst_function_init(pst_function* fn, pst_context* _ctx, __pst_function* _parent)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
fn->clear = fn_clear;
|
|
||||||
fn->add_param = fn_add_param;
|
|
||||||
fn->del_param = fn_del_param;
|
|
||||||
fn->next_param = fn_next_param;
|
|
||||||
fn->unwind = fn_unwind;
|
|
||||||
fn->handle_dwarf = fn_handle_dwarf;
|
|
||||||
fn->print_dwarf = fn_print_dwarf;
|
|
||||||
fn->handle_lexical_block = fn_handle_lexical_block;
|
|
||||||
fn->get_frame = fn_get_frame;
|
|
||||||
|
|
||||||
list_node_init(&fn->node);
|
list_node_init(&fn->node);
|
||||||
|
|
||||||
// fields
|
// fields
|
||||||
@@ -471,7 +460,7 @@ pst_function* pst_function_new(pst_context* _ctx, __pst_function* _parent)
|
|||||||
|
|
||||||
void pst_function_fini(pst_function* fn)
|
void pst_function_fini(pst_function* fn)
|
||||||
{
|
{
|
||||||
fn->clear(fn);
|
clear(fn);
|
||||||
|
|
||||||
if(fn->frame) {
|
if(fn->frame) {
|
||||||
// use free here because it was allocate out of our control by libdw
|
// use free here because it was allocate out of our control by libdw
|
||||||
|
|||||||
@@ -18,18 +18,7 @@
|
|||||||
// pst_function
|
// pst_function
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
typedef struct __pst_function {
|
typedef struct __pst_function {
|
||||||
list_node node; // uplink. !!! must be first !!!
|
list_node node;
|
||||||
|
|
||||||
void (*clear) (pst_function* fn);
|
|
||||||
pst_parameter* (*add_param) (pst_function* fn);
|
|
||||||
void (*del_param) (pst_parameter* p);
|
|
||||||
pst_parameter* (*next_param) (pst_function* fn, pst_parameter* p);
|
|
||||||
|
|
||||||
bool (*unwind) (pst_function* fn, Dwarf_Addr addr);
|
|
||||||
bool (*handle_dwarf) (pst_function* fn, Dwarf_Die* d);
|
|
||||||
bool (*print_dwarf) (pst_function* fn);
|
|
||||||
bool (*handle_lexical_block) (pst_function* fn, Dwarf_Die* result);
|
|
||||||
bool (*get_frame) (pst_function* fn);
|
|
||||||
|
|
||||||
Dwarf_Addr lowpc; // offset to start of the function against base address
|
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
|
Dwarf_Addr highpc; // offset to the next address after the end of the function against base address
|
||||||
@@ -53,4 +42,8 @@ void pst_function_init(pst_function* fn, pst_context* _ctx, __pst_function* _par
|
|||||||
void pst_function_fini(pst_function* fn);
|
void pst_function_fini(pst_function* fn);
|
||||||
pst_function* pst_function_new(pst_context* _ctx, __pst_function* _parent);
|
pst_function* pst_function_new(pst_context* _ctx, __pst_function* _parent);
|
||||||
|
|
||||||
|
bool pst_function_unwind(pst_function* fn, Dwarf_Addr addr);
|
||||||
|
bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d);
|
||||||
|
bool pst_function_print_dwarf(pst_function* fn);
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DWARF_FUNCTION_H_ */
|
#endif /* FRAMEWORK_DWARF_FUNCTION_H_ */
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ bool dw_op_notimpl(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word o
|
|||||||
// address and whose size is the size of an address on the target machine.
|
// address and whose size is the size of an address on the target machine.
|
||||||
bool dw_op_addr(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_addr(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
stack->push(stack, &op1, sizeof(op1), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &op1, sizeof(op1), DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ bool dw_op_addr(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
|
|
||||||
bool dw_op_deref_size(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_deref_size(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->pop(stack);
|
pst_dwarf_value* value = pst_dwarf_stack_pop(stack);
|
||||||
if(value) {
|
if(value) {
|
||||||
uint64_t addr = value->value.uint64;
|
uint64_t addr = value->value.uint64;
|
||||||
uint64_t res = 0;
|
uint64_t res = 0;
|
||||||
@@ -55,7 +55,7 @@ bool dw_op_deref_size(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Wor
|
|||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ bool dw_op_const_x_u(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->push(stack, &op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &op1, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ bool dw_op_const_x_s(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->push(stack, &v, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &v, size, type | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ bool dw_op_const_x_s(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word
|
|||||||
bool dw_op_constu(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_constu(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
uint64_t value = decode_uleb128((unsigned char*)&op1);
|
uint64_t value = decode_uleb128((unsigned char*)&op1);
|
||||||
stack->push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_UNSIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_UNSIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,15 +150,15 @@ bool dw_op_consts(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op
|
|||||||
{
|
{
|
||||||
// The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant.
|
// The single operand of the DW_OP_consts operation provides a signed LEB128 integer constant.
|
||||||
int64_t value = decode_sleb128((unsigned char*)&op1);
|
int64_t value = decode_sleb128((unsigned char*)&op1);
|
||||||
stack->push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_SIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &value, sizeof(value), DWARF_TYPE_LONG | DWARF_TYPE_SIGNED | DWARF_TYPE_CONST | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The DW_OP_dup operation duplicates the value (including its type identifier) at the top of the stack.
|
// The DW_OP_dup operation duplicates the value (including its type identifier) at the top of the stack.
|
||||||
bool dw_op_dup(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_dup(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 0);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 0);
|
||||||
stack->push(stack, &value->value, sizeof(value->value), value->type);
|
pst_dwarf_stack_push(stack, &value->value, sizeof(value->value), value->type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ bool dw_op_dup(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_drop operation pops the value (including its type identifier) at the top of the stack.
|
// The DW_OP_drop operation pops the value (including its type identifier) at the top of the stack.
|
||||||
bool dw_op_drop(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_drop(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->pop(stack);
|
pst_dwarf_value* value = pst_dwarf_stack_pop(stack);
|
||||||
pst_dwarf_value_fini(value);
|
pst_dwarf_value_fini(value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -176,8 +176,8 @@ bool dw_op_drop(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// This is equivalent to a DW_OP_pick operation, with index 1.
|
// This is equivalent to a DW_OP_pick operation, with index 1.
|
||||||
bool dw_op_over(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_over(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 1);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 1);
|
||||||
stack->push(stack, &value->value, sizeof(value->value), value->type);
|
pst_dwarf_stack_push(stack, &value->value, sizeof(value->value), value->type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -186,9 +186,9 @@ bool dw_op_over(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// A copy of the stack entry (including its type identifier) with the specified index (0 through 255, inclusive) is pushed onto the stack.
|
// A copy of the stack entry (including its type identifier) with the specified index (0 through 255, inclusive) is pushed onto the stack.
|
||||||
bool dw_op_pick(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_pick(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, op1);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, op1);
|
||||||
if(value) {
|
if(value) {
|
||||||
stack->push(stack, &value->value, sizeof(value->value), value->type);
|
pst_dwarf_stack_push(stack, &value->value, sizeof(value->value), value->type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,11 +199,11 @@ bool dw_op_pick(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// entry, and the second entry (including its type identifier) becomes the top of the stack.
|
// entry, and the second entry (including its type identifier) becomes the top of the stack.
|
||||||
bool dw_op_swap(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_swap(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->pop(stack);
|
pst_dwarf_value* value1 = pst_dwarf_stack_pop(stack);
|
||||||
pst_dwarf_value* value2 = stack->pop(stack);
|
pst_dwarf_value* value2 = pst_dwarf_stack_pop(stack);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
stack->push_value(stack, value1);
|
pst_dwarf_stack_push_value(stack, value1);
|
||||||
stack->push_value(stack, value2);
|
pst_dwarf_stack_push_value(stack, value2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,13 +223,13 @@ bool dw_op_swap(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// and the third entry (including its type identifier) becomes the second entry
|
// and the third entry (including its type identifier) becomes the second entry
|
||||||
bool dw_op_rot(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_rot(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->pop(stack);
|
pst_dwarf_value* value1 = pst_dwarf_stack_pop(stack);
|
||||||
pst_dwarf_value* value2 = stack->pop(stack);
|
pst_dwarf_value* value2 = pst_dwarf_stack_pop(stack);
|
||||||
pst_dwarf_value* value3 = stack->pop(stack);
|
pst_dwarf_value* value3 = pst_dwarf_stack_pop(stack);
|
||||||
if(value1 && value2 && value3) {
|
if(value1 && value2 && value3) {
|
||||||
stack->push_value(stack, value1);
|
pst_dwarf_stack_push_value(stack, value1);
|
||||||
stack->push_value(stack, value3);
|
pst_dwarf_stack_push_value(stack, value3);
|
||||||
stack->push_value(stack, value2);
|
pst_dwarf_stack_push_value(stack, value2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,10 +250,10 @@ bool dw_op_rot(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// If the absolute value cannot be represented, the result is undefined.
|
// If the absolute value cannot be represented, the result is undefined.
|
||||||
bool dw_op_abs(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_abs(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 0);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 0);
|
||||||
if(value) {
|
if(value) {
|
||||||
uint64_t res = llabs(value->value.int64);
|
uint64_t res = llabs(value->value.int64);
|
||||||
value->set(value, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG);
|
pst_dwarf_value_set(value, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC | DWARF_TYPE_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -262,16 +262,16 @@ bool dw_op_abs(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_and operation pops the top two stack values, performs a bitwise and operation on the two, and pushes the result.
|
// The DW_OP_and operation pops the top two stack values, performs a bitwise and operation on the two, and pushes the result.
|
||||||
bool dw_op_and(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_and(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t res = value1->value.uint64 & value2->value.uint64;
|
uint64_t res = value1->value.uint64 & value2->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
pst_dwarf_value_fini(value1);
|
pst_dwarf_value_fini(value1);
|
||||||
pst_dwarf_value_fini(value2);
|
pst_dwarf_value_fini(value2);
|
||||||
@@ -284,8 +284,8 @@ bool dw_op_and(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result.
|
// The DW_OP_div operation pops the top two stack values, divides the former second entry by the former top of the stack using signed division, and pushes the result.
|
||||||
bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -297,16 +297,16 @@ bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint64_t res = value2->value.int64 / value1->value.int64;
|
uint64_t res = value2->value.int64 / value1->value.int64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if(value1->value.uint64 == 0) {
|
if(value1->value.uint64 == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int64_t res = value2->value.int64 / value1->value.uint64;
|
int64_t res = value2->value.int64 / value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -315,16 +315,16 @@ bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int64_t res = value2->value.uint64 / value1->value.int64;
|
int64_t res = value2->value.uint64 / value1->value.int64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if(value1->value.uint64 == 0) {
|
if(value1->value.uint64 == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint64_t res = value2->value.uint64 / value1->value.uint64;
|
uint64_t res = value2->value.uint64 / value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,8 +336,8 @@ bool dw_op_div(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_minus operation pops the top two stack values, subtracts the former top of the stack from the former second entry, and pushes the result.
|
// The DW_OP_minus operation pops the top two stack values, subtracts the former top of the stack from the former second entry, and pushes the result.
|
||||||
bool dw_op_minus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_minus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -349,8 +349,8 @@ bool dw_op_minus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
}
|
}
|
||||||
// use arithmetic by modulo 1 plus
|
// use arithmetic by modulo 1 plus
|
||||||
uint64_t res = value2->value.uint64 - value1->value.uint64;
|
uint64_t res = value2->value.uint64 - value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), res_type);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), res_type);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -361,8 +361,8 @@ bool dw_op_minus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
// The DW_OP_mod operation pops the top two stack values and pushes the result of the calculation: former second stack entry modulo the former top of the stack.
|
// The DW_OP_mod operation pops the top two stack values and pushes the result of the calculation: former second stack entry modulo the former top of the stack.
|
||||||
bool dw_op_mod(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_mod(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -373,8 +373,8 @@ bool dw_op_mod(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t res = value2->value.uint64 % value1->value.uint64;
|
uint64_t res = value2->value.uint64 % value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -385,8 +385,8 @@ bool dw_op_mod(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_mul operation pops the top two stack entries, multiplies them together, and pushes the result.
|
// The DW_OP_mul operation pops the top two stack entries, multiplies them together, and pushes the result.
|
||||||
bool dw_op_mul(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_mul(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
pst_log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type);
|
pst_log(SEVERITY_ERROR, "Different types of two stack values for operation: %s(%0x%X, %0x%X)", map->op_name, value1->type, value2->type);
|
||||||
@@ -396,28 +396,28 @@ bool dw_op_mul(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
if(value2->type & DWARF_TYPE_SIGNED) {
|
if(value2->type & DWARF_TYPE_SIGNED) {
|
||||||
if(value1->type & DWARF_TYPE_SIGNED) {
|
if(value1->type & DWARF_TYPE_SIGNED) {
|
||||||
uint64_t res = value2->value.int64 * value1->value.int64;
|
uint64_t res = value2->value.int64 * value1->value.int64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
int64_t res = value2->value.int64 * value1->value.uint64;
|
int64_t res = value2->value.int64 * value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(value1->type & DWARF_TYPE_SIGNED) {
|
if(value1->type & DWARF_TYPE_SIGNED) {
|
||||||
int64_t res = value2->value.uint64 * value1->value.int64;
|
int64_t res = value2->value.uint64 * value1->value.int64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_SIGNED | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
uint64_t res = value2->value.uint64 * value1->value.uint64;
|
uint64_t res = value2->value.uint64 * value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), DWARF_TYPE_UNSIGNED | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -431,7 +431,7 @@ bool dw_op_mul(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// If the negation cannot be represented, the result is undefined.
|
// If the negation cannot be represented, the result is undefined.
|
||||||
bool dw_op_neg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_neg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 0);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 0);
|
||||||
if(value) {
|
if(value) {
|
||||||
if(value->type & DWARF_TYPE_CHAR) {
|
if(value->type & DWARF_TYPE_CHAR) {
|
||||||
value->value.int8 *= -1;
|
value->value.int8 *= -1;
|
||||||
@@ -451,7 +451,7 @@ bool dw_op_neg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_not operation pops the top stack entry, and pushes its bitwise complement.
|
// The DW_OP_not operation pops the top stack entry, and pushes its bitwise complement.
|
||||||
bool dw_op_not(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_not(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 0);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 0);
|
||||||
if(value) {
|
if(value) {
|
||||||
value->value.uint64 = ~value->value.uint64;
|
value->value.uint64 = ~value->value.uint64;
|
||||||
|
|
||||||
@@ -464,16 +464,16 @@ bool dw_op_not(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// The DW_OP_or operation pops the top two stack entries, performs a bitwise or operation on the two, and pushes the result.
|
// The DW_OP_or operation pops the top two stack entries, performs a bitwise or operation on the two, and pushes the result.
|
||||||
bool dw_op_or(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_or(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t res = value2->value.uint64 | value1->value.uint64;
|
uint64_t res = value2->value.uint64 | value1->value.uint64;
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
stack->push(stack, &res, sizeof(res), value1->type);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), value1->type);
|
||||||
|
|
||||||
pst_dwarf_value_fini(value1);
|
pst_dwarf_value_fini(value1);
|
||||||
pst_dwarf_value_fini(value2);
|
pst_dwarf_value_fini(value2);
|
||||||
@@ -487,8 +487,8 @@ bool dw_op_or(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, D
|
|||||||
// The DW_OP_plus operation pops the top two stack entries, adds them together, and pushes the result
|
// The DW_OP_plus operation pops the top two stack entries, adds them together, and pushes the result
|
||||||
bool dw_op_plus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_plus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value1 = stack->get(stack, 0);
|
pst_dwarf_value* value1 = pst_dwarf_stack_get(stack, 0);
|
||||||
pst_dwarf_value* value2 = stack->get(stack, 1);
|
pst_dwarf_value* value2 = pst_dwarf_stack_get(stack, 1);
|
||||||
if(value1 && value2) {
|
if(value1 && value2) {
|
||||||
if(!(value1->type & value2->type)) {
|
if(!(value1->type & value2->type)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -496,15 +496,15 @@ bool dw_op_plus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
|
|
||||||
if((value1->type & DWARF_TYPE_SIGNED) && (value2->type & DWARF_TYPE_SIGNED)) {
|
if((value1->type & DWARF_TYPE_SIGNED) && (value2->type & DWARF_TYPE_SIGNED)) {
|
||||||
int64_t res = value2->value.int64 + value1->value.int64;
|
int64_t res = value2->value.int64 + value1->value.int64;
|
||||||
stack->push(stack, &res, sizeof(res), value1->type);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), value1->type);
|
||||||
} else {
|
} else {
|
||||||
// if in arithmetic expression even one operand is unsigned then result is unsigned as well
|
// if in arithmetic expression even one operand is unsigned then result is unsigned as well
|
||||||
int type = (value1->type & (~DWARF_TYPE_SIGNED)) | DWARF_TYPE_UNSIGNED;
|
int type = (value1->type & (~DWARF_TYPE_SIGNED)) | DWARF_TYPE_UNSIGNED;
|
||||||
uint64_t res = value2->value.uint64 + value1->value.uint64;
|
uint64_t res = value2->value.uint64 + value1->value.uint64;
|
||||||
stack->push(stack, &res, sizeof(res), type);
|
pst_dwarf_stack_push(stack, &res, sizeof(res), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->pop(stack); stack->pop(stack);
|
pst_dwarf_stack_pop(stack); pst_dwarf_stack_pop(stack);
|
||||||
pst_dwarf_value_fini(value1);
|
pst_dwarf_value_fini(value1);
|
||||||
pst_dwarf_value_fini(value2);
|
pst_dwarf_value_fini(value2);
|
||||||
|
|
||||||
@@ -520,7 +520,7 @@ bool dw_op_plus(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1,
|
|||||||
// bytes than can be done with “DW_OP_lit<n> DW_OP_plus.”
|
// bytes than can be done with “DW_OP_lit<n> DW_OP_plus.”
|
||||||
bool dw_op_plus_uconst(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_plus_uconst(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = stack->get(stack, 0);
|
pst_dwarf_value* value = pst_dwarf_stack_get(stack, 0);
|
||||||
if(value) {
|
if(value) {
|
||||||
uint64_t op = decode_uleb128((unsigned char*)&op1);
|
uint64_t op = decode_uleb128((unsigned char*)&op1);
|
||||||
value->value.uint64 += op;
|
value->value.uint64 += op;
|
||||||
@@ -547,7 +547,7 @@ bool dw_op_reg_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
regno = map->op_num - DW_OP_reg0;
|
regno = map->op_num - DW_OP_reg0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->push(stack, ®no, sizeof(regno), DWARF_TYPE_REGISTER_LOC);
|
pst_dwarf_stack_push(stack, ®no, sizeof(regno), DWARF_TYPE_REGISTER_LOC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -577,7 +577,7 @@ bool dw_op_breg_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op
|
|||||||
}
|
}
|
||||||
|
|
||||||
val += off;
|
val += off;
|
||||||
stack->push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ bool dw_op_lit_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t val = map->op_num - DW_OP_lit0;
|
uint64_t val = map->op_num - DW_OP_lit0;
|
||||||
stack->push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &val, sizeof(val), DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -602,7 +602,7 @@ bool dw_op_lit_x(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
bool dw_op_stack_value(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
bool dw_op_stack_value(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1, Dwarf_Word op2)
|
||||||
{
|
{
|
||||||
|
|
||||||
pst_dwarf_value* v = stack->get(stack, 0);
|
pst_dwarf_value* v = pst_dwarf_stack_get(stack, 0);
|
||||||
if(v) {
|
if(v) {
|
||||||
v->type = DWARF_TYPE_GENERIC;
|
v->type = DWARF_TYPE_GENERIC;
|
||||||
return true;
|
return true;
|
||||||
@@ -622,7 +622,7 @@ bool dw_op_call_frame_cfa(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf
|
|||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
stack->push(stack, &stack->ctx->cfa, sizeof(stack->ctx->cfa), /*DWARF_TYPE_MEMORY_LOC | */DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &stack->ctx->cfa, sizeof(stack->ctx->cfa), /*DWARF_TYPE_MEMORY_LOC | */DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -643,7 +643,7 @@ bool dw_op_fbreg(pst_dwarf_stack* stack, const dwarf_op_map* map, Dwarf_Word op1
|
|||||||
int64_t off = decode_sleb128((unsigned char*)&op1);
|
int64_t off = decode_sleb128((unsigned char*)&op1);
|
||||||
sp += off;
|
sp += off;
|
||||||
|
|
||||||
stack->push(stack, &sp, sizeof(sp), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(stack, &sp, sizeof(sp), DWARF_TYPE_MEMORY_LOC | DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,17 +45,38 @@ void pst_type_fini(pst_type* t)
|
|||||||
//
|
//
|
||||||
// pst_parameter
|
// pst_parameter
|
||||||
//
|
//
|
||||||
bool param_print_dwarf(pst_parameter* param)
|
void clear(pst_parameter* param)
|
||||||
|
{
|
||||||
|
pst_type* t = NULL;
|
||||||
|
struct list_node *pos, *tn;
|
||||||
|
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
|
||||||
|
list_del(&t->node);
|
||||||
|
pst_type_fini(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_type* next_type(pst_parameter* param, pst_type* t)
|
||||||
|
{
|
||||||
|
list_node* n = (t == NULL) ? list_first(¶m->types) : list_next(&t->node);
|
||||||
|
pst_type* ret = NULL;
|
||||||
|
if(n) {
|
||||||
|
ret = list_entry(n, pst_type, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_parameter_print_dwarf(pst_parameter* param)
|
||||||
{
|
{
|
||||||
if(list_count(¶m->types)) {
|
if(list_count(¶m->types)) {
|
||||||
if(!param->is_return) {
|
if(!param->is_return) {
|
||||||
if(param->has_value) {
|
if(param->has_value) {
|
||||||
param->ctx->print(param->ctx, "%s %s = 0x%lX", param->next_type(param, NULL)->name, param->name, param->location.value);
|
param->ctx->print(param->ctx, "%s %s = 0x%lX", next_type(param, NULL)->name, param->name, param->location.value);
|
||||||
} else {
|
} else {
|
||||||
param->ctx->print(param->ctx, "%s %s = <undefined>", param->next_type(param, NULL)->name, param->name);
|
param->ctx->print(param->ctx, "%s %s = <undefined>", next_type(param, NULL)->name, param->name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
param->ctx->print(param->ctx, "%s", param->next_type(param, NULL)->name);
|
param->ctx->print(param->ctx, "%s", next_type(param, NULL)->name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(param->has_value) {
|
if(param->has_value) {
|
||||||
@@ -67,7 +88,15 @@ bool param_print_dwarf(pst_parameter* param)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool param_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, int type)
|
||||||
|
{
|
||||||
|
pst_new(pst_type, t, name, type);
|
||||||
|
list_add_bottom(¶m->types, &t->node);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
||||||
{
|
{
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute* attr;
|
Dwarf_Attribute* attr;
|
||||||
@@ -89,7 +118,7 @@ bool param_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
|||||||
dwarf_formudata(attr, ¶m->size);
|
dwarf_formudata(attr, ¶m->size);
|
||||||
}
|
}
|
||||||
pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->size);
|
pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->size);
|
||||||
param->add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type);
|
pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type);
|
||||||
param->type = DW_TAG_base_type;
|
param->type = DW_TAG_base_type;
|
||||||
|
|
||||||
attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
|
attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
|
||||||
@@ -101,38 +130,38 @@ bool param_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
|||||||
}
|
}
|
||||||
case DW_TAG_array_type:
|
case DW_TAG_array_type:
|
||||||
pst_log(SEVERITY_DEBUG, "array type");
|
pst_log(SEVERITY_DEBUG, "array type");
|
||||||
param->add_type(param, "[]", DW_TAG_array_type);
|
pst_parameter_add_type(param, "[]", DW_TAG_array_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_structure_type:
|
case DW_TAG_structure_type:
|
||||||
pst_log(SEVERITY_DEBUG, "structure type");
|
pst_log(SEVERITY_DEBUG, "structure type");
|
||||||
param->add_type(param, "struct", DW_TAG_structure_type);
|
pst_parameter_add_type(param, "struct", DW_TAG_structure_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_union_type:
|
case DW_TAG_union_type:
|
||||||
pst_log(SEVERITY_DEBUG, "union type");
|
pst_log(SEVERITY_DEBUG, "union type");
|
||||||
param->add_type(param, "union", DW_TAG_union_type);
|
pst_parameter_add_type(param, "union", DW_TAG_union_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_class_type:
|
case DW_TAG_class_type:
|
||||||
pst_log(SEVERITY_DEBUG, "class type");
|
pst_log(SEVERITY_DEBUG, "class type");
|
||||||
param->add_type(param, "class", DW_TAG_class_type);
|
pst_parameter_add_type(param, "class", DW_TAG_class_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_pointer_type:
|
case DW_TAG_pointer_type:
|
||||||
pst_log(SEVERITY_DEBUG, "pointer type");
|
pst_log(SEVERITY_DEBUG, "pointer type");
|
||||||
param->add_type(param, "*", DW_TAG_pointer_type);
|
pst_parameter_add_type(param, "*", DW_TAG_pointer_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_enumeration_type:
|
case DW_TAG_enumeration_type:
|
||||||
pst_log(SEVERITY_DEBUG, "enumeration type");
|
pst_log(SEVERITY_DEBUG, "enumeration type");
|
||||||
param->add_type(param, "enum", DW_TAG_enumeration_type);
|
pst_parameter_add_type(param, "enum", DW_TAG_enumeration_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_const_type:
|
case DW_TAG_const_type:
|
||||||
pst_log(SEVERITY_DEBUG, "constant type");
|
pst_log(SEVERITY_DEBUG, "constant type");
|
||||||
param->add_type(param, "const", DW_TAG_const_type);
|
pst_parameter_add_type(param, "const", DW_TAG_const_type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_subroutine_type:
|
case DW_TAG_subroutine_type:
|
||||||
pst_log(SEVERITY_DEBUG, "Skipping subroutine type");
|
pst_log(SEVERITY_DEBUG, "Skipping subroutine type");
|
||||||
break;
|
break;
|
||||||
case DW_TAG_typedef:
|
case DW_TAG_typedef:
|
||||||
pst_log(SEVERITY_DEBUG, "typedef '%s' type", dwarf_diename(&ret_die));
|
pst_log(SEVERITY_DEBUG, "typedef '%s' type", dwarf_diename(&ret_die));
|
||||||
param->add_type(param, dwarf_diename(&ret_die), DW_TAG_typedef);
|
pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_typedef);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pst_log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
pst_log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
|
||||||
@@ -141,42 +170,13 @@ bool param_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
|||||||
|
|
||||||
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
|
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
return param->handle_type(param, attr);
|
return pst_parameter_handle_type(param, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_type* param_add_type(pst_parameter* param, const char* name, int type)
|
bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun)
|
||||||
{
|
|
||||||
pst_new(pst_type, t, name, type);
|
|
||||||
list_add_bottom(¶m->types, &t->node);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void param_clear(pst_parameter* param)
|
|
||||||
{
|
|
||||||
pst_type* t = NULL;
|
|
||||||
struct list_node *pos, *tn;
|
|
||||||
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
|
|
||||||
list_del(&t->node);
|
|
||||||
pst_type_fini(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pst_type* param_next_type(pst_parameter* param, pst_type* t)
|
|
||||||
{
|
|
||||||
list_node* n = (t == NULL) ? list_first(¶m->types) : list_next(&t->node);
|
|
||||||
pst_type* ret = NULL;
|
|
||||||
if(n) {
|
|
||||||
ret = list_entry(n, pst_type, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool param_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun)
|
|
||||||
{
|
{
|
||||||
param->die = result;
|
param->die = result;
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ bool param_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* f
|
|||||||
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
|
||||||
pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
|
||||||
if(attr) {
|
if(attr) {
|
||||||
param->handle_type(param, attr);
|
pst_parameter_handle_type(param, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwarf_hasattr(result, DW_AT_location)) {
|
if(dwarf_hasattr(result, DW_AT_location)) {
|
||||||
@@ -257,15 +257,6 @@ bool param_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* f
|
|||||||
|
|
||||||
void pst_parameter_init(pst_parameter* param, pst_context* ctx)
|
void pst_parameter_init(pst_parameter* param, pst_context* ctx)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
param->clear = param_clear;
|
|
||||||
param->add_type = param_add_type;
|
|
||||||
param->next_type = param_next_type;
|
|
||||||
param->handle_dwarf = param_handle_dwarf;
|
|
||||||
param->handle_type = param_handle_type;
|
|
||||||
param->print_dwarf = param_print_dwarf;
|
|
||||||
|
|
||||||
// fields
|
|
||||||
list_node_init(¶m->node);
|
list_node_init(¶m->node);
|
||||||
param->die = NULL;
|
param->die = NULL;
|
||||||
param->name = NULL;
|
param->name = NULL;
|
||||||
@@ -294,7 +285,7 @@ pst_parameter* pst_parameter_new(pst_context* ctx)
|
|||||||
}
|
}
|
||||||
void pst_parameter_fini(pst_parameter* param)
|
void pst_parameter_fini(pst_parameter* param)
|
||||||
{
|
{
|
||||||
param->clear(param);
|
clear(param);
|
||||||
if(param->name) {
|
if(param->name) {
|
||||||
pst_free(param->name);
|
pst_free(param->name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,6 @@ typedef struct __pst_function pst_function;
|
|||||||
typedef struct pst_parameter{
|
typedef struct pst_parameter{
|
||||||
list_node node; // uplink. !!! must be first !!!
|
list_node node; // uplink. !!! must be first !!!
|
||||||
|
|
||||||
// methods
|
|
||||||
void (*clear) (pst_parameter* param);
|
|
||||||
pst_type* (*add_type) (pst_parameter* param, const char* name, int type);
|
|
||||||
pst_type* (*next_type) (pst_parameter* param, pst_type* t);
|
|
||||||
bool (*handle_dwarf) (pst_parameter* param, Dwarf_Die* d, pst_function* fun);
|
|
||||||
bool (*handle_type) (pst_parameter* param, Dwarf_Attribute* attr);
|
|
||||||
bool (*print_dwarf) (pst_parameter* param);
|
|
||||||
|
|
||||||
// fields
|
// fields
|
||||||
Dwarf_Die* die; // DWARF DIE containing parameter's definition
|
Dwarf_Die* die; // DWARF DIE containing parameter's definition
|
||||||
char* name; // parameter's name
|
char* name; // parameter's name
|
||||||
@@ -59,5 +51,9 @@ void pst_parameter_init(pst_parameter* param, pst_context* ctx);
|
|||||||
pst_parameter* pst_parameter_new(pst_context* ctx);
|
pst_parameter* pst_parameter_new(pst_context* ctx);
|
||||||
void pst_parameter_fini(pst_parameter* param);
|
void pst_parameter_fini(pst_parameter* param);
|
||||||
|
|
||||||
|
bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun);
|
||||||
|
bool pst_parameter_print_dwarf(pst_parameter* param);
|
||||||
|
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base);
|
||||||
|
pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, int type);
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DWARF_PARAMETER_H_ */
|
#endif /* FRAMEWORK_DWARF_PARAMETER_H_ */
|
||||||
|
|||||||
+22
-27
@@ -19,7 +19,7 @@
|
|||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// DWARF Stack value
|
// DWARF Stack value
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void value_set(pst_dwarf_value* value, void* v, uint32_t s, int t)
|
void pst_dwarf_value_set(pst_dwarf_value* value, void* v, uint32_t s, int t)
|
||||||
{
|
{
|
||||||
pst_assert(value && v && s > 0 && s <= sizeof(value->value));
|
pst_assert(value && v && s > 0 && s <= sizeof(value->value));
|
||||||
|
|
||||||
@@ -70,8 +70,7 @@ void pst_dwarf_value_init(pst_dwarf_value* dv, char* v, uint32_t s, int t)
|
|||||||
list_node_init(&dv->node);
|
list_node_init(&dv->node);
|
||||||
dv->type = t;
|
dv->type = t;
|
||||||
dv->allocated = false;
|
dv->allocated = false;
|
||||||
dv->set = value_set;
|
pst_dwarf_value_set(dv, v, s, t);
|
||||||
value_set(dv, v, s, t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t)
|
pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t)
|
||||||
@@ -104,16 +103,19 @@ void pst_dwarf_value_fini(pst_dwarf_value* value)
|
|||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// DWARF stack
|
// DWARF stack
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
void stack_push(pst_dwarf_stack* st, void* v, uint32_t s, int t) {
|
void pst_dwarf_stack_push(pst_dwarf_stack* st, void* v, uint32_t s, int t)
|
||||||
|
{
|
||||||
pst_new(pst_dwarf_value, value, (char*)v, s, t);
|
pst_new(pst_dwarf_value, value, (char*)v, s, t);
|
||||||
list_add_head(&st->values, &value->node);
|
list_add_head(&st->values, &value->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack_push_value(pst_dwarf_stack* st, pst_dwarf_value* value) {
|
void pst_dwarf_stack_push_value(pst_dwarf_stack* st, pst_dwarf_value* value)
|
||||||
|
{
|
||||||
list_add_head(&st->values, &value->node);
|
list_add_head(&st->values, &value->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_dwarf_value* stack_pop(pst_dwarf_stack* st) {
|
pst_dwarf_value* pst_dwarf_stack_pop(pst_dwarf_stack* st)
|
||||||
|
{
|
||||||
pst_dwarf_value* value = (pst_dwarf_value*)list_first(&st->values);
|
pst_dwarf_value* value = (pst_dwarf_value*)list_first(&st->values);
|
||||||
if(value) {
|
if(value) {
|
||||||
list_del(&value->node);
|
list_del(&value->node);
|
||||||
@@ -122,7 +124,8 @@ pst_dwarf_value* stack_pop(pst_dwarf_stack* st) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_dwarf_value* stack_get(pst_dwarf_stack* st, uint32_t idx = 0) {
|
pst_dwarf_value* pst_dwarf_stack_get(pst_dwarf_stack* st, uint32_t idx)
|
||||||
|
{
|
||||||
pst_dwarf_value* value = NULL;
|
pst_dwarf_value* value = NULL;
|
||||||
struct list_node *pos;
|
struct list_node *pos;
|
||||||
list_for_each_entry(value, pos, &st->values, node) {
|
list_for_each_entry(value, pos, &st->values, node) {
|
||||||
@@ -135,7 +138,7 @@ pst_dwarf_value* stack_get(pst_dwarf_stack* st, uint32_t idx = 0) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stack_get_value(pst_dwarf_stack* st, uint64_t* value)
|
bool pst_dwarf_stack_get_value(pst_dwarf_stack* st, uint64_t* value)
|
||||||
{
|
{
|
||||||
assert(st && value);
|
assert(st && value);
|
||||||
|
|
||||||
@@ -143,7 +146,7 @@ bool stack_get_value(pst_dwarf_stack* st, uint64_t* value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_dwarf_value* v = st->get(st, 0);
|
pst_dwarf_value* v = pst_dwarf_stack_get(st, 0);
|
||||||
if(v->type & DWARF_TYPE_REGISTER_LOC) {
|
if(v->type & DWARF_TYPE_REGISTER_LOC) {
|
||||||
// dereference register location
|
// dereference register location
|
||||||
int ret = unw_get_reg(st->ctx->curr_frame, v->value.uint64, value);
|
int ret = unw_get_reg(st->ctx->curr_frame, v->value.uint64, value);
|
||||||
@@ -161,7 +164,7 @@ bool stack_get_value(pst_dwarf_stack* st, uint64_t* value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack_clear(pst_dwarf_stack* st)
|
void pst_dwarf_stack_clear(pst_dwarf_stack* st)
|
||||||
{
|
{
|
||||||
pst_dwarf_value* value = NULL;
|
pst_dwarf_value* value = NULL;
|
||||||
struct list_node *pos, *tn;
|
struct list_node *pos, *tn;
|
||||||
@@ -177,9 +180,9 @@ void stack_clear(pst_dwarf_stack* st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun = NULL)
|
bool pst_dwarf_stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun)
|
||||||
{
|
{
|
||||||
st->clear(st);
|
pst_dwarf_stack_clear(st);
|
||||||
|
|
||||||
for (int i = 0; i < expr_len; i++) {
|
for (int i = 0; i < expr_len; i++) {
|
||||||
const dwarf_op_map* map = find_op_map(exprs[i].atom);
|
const dwarf_op_map* map = find_op_map(exprs[i].atom);
|
||||||
@@ -191,7 +194,7 @@ bool stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attrib
|
|||||||
pst_new(pst_dwarf_op, op, exprs[i].atom, exprs[i].number, exprs[i].number2);
|
pst_new(pst_dwarf_op, op, exprs[i].atom, exprs[i].number, exprs[i].number2);
|
||||||
list_add_bottom(&st->expr, &op->node);
|
list_add_bottom(&st->expr, &op->node);
|
||||||
|
|
||||||
pst_dwarf_value* v = st->get(st, 0);
|
pst_dwarf_value* v = pst_dwarf_stack_get(st, 0);
|
||||||
// dereference register location there if it is not last in stack
|
// dereference register location there if it is not last in stack
|
||||||
if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) {
|
if(v && (v->type & DWARF_TYPE_REGISTER_LOC)) {
|
||||||
unw_word_t value = 0;
|
unw_word_t value = 0;
|
||||||
@@ -201,7 +204,7 @@ bool stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attrib
|
|||||||
pst_log(SEVERITY_ERROR, "Failed to ger value of register 0x%X. Error: %d", regno, ret);
|
pst_log(SEVERITY_ERROR, "Failed to ger value of register 0x%X. Error: %d", regno, ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v->set(v, &value, sizeof(value), DWARF_TYPE_GENERIC);
|
pst_dwarf_value_set(v, &value, sizeof(value), DWARF_TYPE_GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle there because it contains sub-expression of a Location in caller's frame
|
// handle there because it contains sub-expression of a Location in caller's frame
|
||||||
@@ -221,22 +224,22 @@ bool stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attrib
|
|||||||
Dwarf_Op *expr;
|
Dwarf_Op *expr;
|
||||||
size_t exprlen;
|
size_t exprlen;
|
||||||
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
|
if (dwarf_getlocation(&attr_mem, &expr, &exprlen) == 0) {
|
||||||
pst_call_site* cs = fun->parent->call_sites.find_call_site(&fun->parent->call_sites, fun);
|
pst_call_site* cs = pst_call_site_storage_find(&fun->parent->call_sites, fun);
|
||||||
if(!cs) {
|
if(!cs) {
|
||||||
pst_log(SEVERITY_ERROR, "Failed to find call site while calculate DW_OP_GNU_entry_value expression");
|
pst_log(SEVERITY_ERROR, "Failed to find call site while calculate DW_OP_GNU_entry_value expression");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pst_dwarf_expr loc;
|
pst_dwarf_expr loc;
|
||||||
pst_dwarf_expr_init(&loc);
|
pst_dwarf_expr_init(&loc);
|
||||||
loc.setup(&loc, expr, exprlen);
|
pst_dwarf_expr_setup(&loc, expr, exprlen);
|
||||||
pst_call_site_param* param = cs->find_param(cs, &loc);
|
pst_call_site_param* param = pst_call_site_find(cs, &loc);
|
||||||
pst_dwarf_expr_fini(&loc);
|
pst_dwarf_expr_fini(&loc);
|
||||||
if(!param) {
|
if(!param) {
|
||||||
pst_log(SEVERITY_ERROR, "Failed to find call site parameter while calculate DW_OP_GNU_entry_value expression");
|
pst_log(SEVERITY_ERROR, "Failed to find call site parameter while calculate DW_OP_GNU_entry_value expression");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->push(st, ¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC);
|
pst_dwarf_stack_push(st, ¶m->value, sizeof(param->value), DWARF_TYPE_GENERIC);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@@ -265,14 +268,6 @@ void pst_dwarf_stack_init(pst_dwarf_stack* st, pst_context* ctx)
|
|||||||
|
|
||||||
list_head_init(&st->expr);
|
list_head_init(&st->expr);
|
||||||
list_head_init(&st->values);
|
list_head_init(&st->values);
|
||||||
st->push = stack_push;
|
|
||||||
st->push_value = stack_push_value;
|
|
||||||
st->pop = stack_pop;
|
|
||||||
st->get = stack_get;
|
|
||||||
st->get_value = stack_get_value;
|
|
||||||
st->calc = stack_calc;
|
|
||||||
st->clear = stack_clear;
|
|
||||||
|
|
||||||
st->ctx = ctx;
|
st->ctx = ctx;
|
||||||
st->allocated = false;
|
st->allocated = false;
|
||||||
}
|
}
|
||||||
@@ -294,7 +289,7 @@ void pst_dwarf_stack_fini(pst_dwarf_stack* st)
|
|||||||
{
|
{
|
||||||
pst_assert(st);
|
pst_assert(st);
|
||||||
|
|
||||||
st->clear(st);
|
pst_dwarf_stack_clear(st);
|
||||||
if(st->allocated) {
|
if(st->allocated) {
|
||||||
pst_free(st);
|
pst_free(st);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+9
-32
@@ -57,18 +57,9 @@ typedef union {
|
|||||||
void* ptr;
|
void* ptr;
|
||||||
} pst_sized_value;
|
} pst_sized_value;
|
||||||
|
|
||||||
// forward declaration
|
|
||||||
typedef struct __pst_dwarf_value pst_dwarf_value;
|
|
||||||
|
|
||||||
// typedefs for member function pointers
|
|
||||||
typedef void (*pst_dwarf_value_set) (pst_dwarf_value* value, void* v, uint32_t s, int t);
|
|
||||||
|
|
||||||
typedef struct __pst_dwarf_value {
|
typedef struct __pst_dwarf_value {
|
||||||
list_node node; // uplink, !!! must be 1st field in structure !!!
|
list_node node; // uplink, !!! must be 1st field in structure !!!
|
||||||
|
|
||||||
// methods
|
|
||||||
pst_dwarf_value_set set; // replace value data
|
|
||||||
|
|
||||||
// fields
|
// fields
|
||||||
pst_sized_value value; // value itself
|
pst_sized_value value; // value itself
|
||||||
int type; // value type. bitmask of DWARF_TYPE_XXX
|
int type; // value type. bitmask of DWARF_TYPE_XXX
|
||||||
@@ -78,35 +69,13 @@ typedef struct __pst_dwarf_value {
|
|||||||
void pst_dwarf_value_init(pst_dwarf_value* value, char* v, uint32_t s, int t);
|
void pst_dwarf_value_init(pst_dwarf_value* value, char* v, uint32_t s, int t);
|
||||||
pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t);
|
pst_dwarf_value* pst_dwarf_value_new(char* v, uint32_t s, int t);
|
||||||
void pst_dwarf_value_fini(pst_dwarf_value* value);
|
void pst_dwarf_value_fini(pst_dwarf_value* value);
|
||||||
|
void pst_dwarf_value_set(pst_dwarf_value* value, void* v, uint32_t s, int t);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
// DWARF stack
|
// DWARF stack
|
||||||
// -----------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// forward declaration
|
|
||||||
typedef struct __pst_dwarf_stack pst_dwarf_stack;
|
|
||||||
|
|
||||||
// typedefs for member function pointers
|
|
||||||
typedef void (*pst_dwarf_stack_push) (pst_dwarf_stack* st, void* v, uint32_t s, int t);
|
|
||||||
typedef void (*pst_dwarf_stack_push_val) (pst_dwarf_stack* st, pst_dwarf_value* value);
|
|
||||||
typedef pst_dwarf_value* (*pst_dwarf_stack_pop) (pst_dwarf_stack* st);
|
|
||||||
typedef pst_dwarf_value* (*pst_dwarf_stack_get) (pst_dwarf_stack* st, uint32_t idx);
|
|
||||||
typedef bool (*pst_dwarf_stack_calc) (pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun);
|
|
||||||
typedef bool (*pst_dwarf_stack_get_value) (pst_dwarf_stack* st, uint64_t* value);
|
|
||||||
typedef void (*pst_dwarf_stack_clear) (pst_dwarf_stack* st);
|
|
||||||
|
|
||||||
typedef struct __pst_dwarf_stack {
|
typedef struct __pst_dwarf_stack {
|
||||||
// methods
|
|
||||||
pst_dwarf_stack_push push; // push new value on the top of the stack
|
|
||||||
pst_dwarf_stack_push_val push_value; // push an existing value on the top of the stack
|
|
||||||
pst_dwarf_stack_pop pop; // pop value from the top of the stack
|
|
||||||
pst_dwarf_stack_get get; // get value from top of the stack without popping
|
|
||||||
pst_dwarf_stack_calc calc; // calculate DWARF expression
|
|
||||||
pst_dwarf_stack_get_value get_value; // get result of calculation
|
|
||||||
pst_dwarf_stack_clear clear; // clean-up the stack
|
|
||||||
|
|
||||||
// fields
|
|
||||||
list_head expr; // DWARF expression
|
list_head expr; // DWARF expression
|
||||||
list_head values; // list of values on the stack
|
list_head values; // list of values on the stack
|
||||||
pst_context* ctx; // context of execution
|
pst_context* ctx; // context of execution
|
||||||
@@ -117,4 +86,12 @@ void pst_dwarf_stack_init(pst_dwarf_stack* st, pst_context* ctx);
|
|||||||
pst_dwarf_stack* pst_dwarf_stack_new(pst_context* ctx);
|
pst_dwarf_stack* pst_dwarf_stack_new(pst_context* ctx);
|
||||||
void pst_dwarf_stack_fini(pst_dwarf_stack* st);
|
void pst_dwarf_stack_fini(pst_dwarf_stack* st);
|
||||||
|
|
||||||
|
bool pst_dwarf_stack_calc(pst_dwarf_stack* st, Dwarf_Op *exprs, int expr_len, Dwarf_Attribute* attr, pst_function* fun = NULL);
|
||||||
|
void pst_dwarf_stack_clear(pst_dwarf_stack* st);
|
||||||
|
bool pst_dwarf_stack_get_value(pst_dwarf_stack* st, uint64_t* value);
|
||||||
|
pst_dwarf_value* pst_dwarf_stack_get(pst_dwarf_stack* st, uint32_t idx = 0);
|
||||||
|
pst_dwarf_value* pst_dwarf_stack_pop(pst_dwarf_stack* st);
|
||||||
|
void pst_dwarf_stack_push_value(pst_dwarf_stack* st, pst_dwarf_value* value);
|
||||||
|
void pst_dwarf_stack_push(pst_dwarf_stack* st, void* v, uint32_t s, int t);
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DWARF_STACK_H_ */
|
#endif /* FRAMEWORK_DWARF_STACK_H_ */
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr* lo
|
|||||||
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
|
||||||
// Location expression (exprloc class of location in DWARF terms)
|
// Location expression (exprloc class of location in DWARF terms)
|
||||||
if(dwarf_getlocation(attr, &expr, &exprlen) == 0) {
|
if(dwarf_getlocation(attr, &expr, &exprlen) == 0) {
|
||||||
loc->setup(loc, expr, exprlen);
|
pst_dwarf_expr_setup(loc, expr, exprlen);
|
||||||
ctx->print_expr(ctx, expr, exprlen, attr);
|
ctx->print_expr(ctx, expr, exprlen, attr);
|
||||||
ret = stack.calc(&stack, expr, exprlen, attr, fun);
|
ret = pst_dwarf_stack_calc(&stack, expr, exprlen, attr, fun);
|
||||||
stack.get_value(&stack, &loc->value);
|
pst_dwarf_stack_get_value(&stack, &loc->value);
|
||||||
}
|
}
|
||||||
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
|
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
|
||||||
// Location list (loclist class of location in DWARF terms)
|
// Location list (loclist class of location in DWARF terms)
|
||||||
@@ -46,10 +46,10 @@ bool handle_location(pst_context* ctx, Dwarf_Attribute* attr, pst_dwarf_expr* lo
|
|||||||
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
|
for(int i = 0; (off = dwarf_getlocations (attr, off, &base, &start, &end, &expr, &exprlen)) > 0; ++i) {
|
||||||
ctx->print_expr(ctx, expr, exprlen, attr);
|
ctx->print_expr(ctx, expr, exprlen, attr);
|
||||||
if(offset >= start && offset <= end) {
|
if(offset >= start && offset <= end) {
|
||||||
loc->setup(loc, expr, exprlen);
|
pst_dwarf_expr_setup(loc, expr, exprlen);
|
||||||
// actual location, try to calculate Location expression
|
// actual location, try to calculate Location expression
|
||||||
ret = stack.calc(&stack, expr, exprlen, attr, fun);
|
ret = pst_dwarf_stack_calc(&stack, expr, exprlen, attr, fun);
|
||||||
stack.get_value(&stack, &loc->value);
|
pst_dwarf_stack_get_value(&stack, &loc->value);
|
||||||
} else {
|
} else {
|
||||||
// Location skipped due to don't match current PC offset
|
// Location skipped due to don't match current PC offset
|
||||||
pst_log(SEVERITY_DEBUG, "Skip Location list expression: [%d] (low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 "), \"%s\"", i, start, end, ctx->buff);
|
pst_log(SEVERITY_DEBUG, "Skip Location list expression: [%d] (low_offset: 0x%" PRIx64 ", high_offset: 0x%" PRIx64 "), \"%s\"", i, start, end, ctx->buff);
|
||||||
|
|||||||
+20
-31
@@ -34,7 +34,7 @@
|
|||||||
// dwarf_getattrs() allows to enumerate all DIE attributes
|
// dwarf_getattrs() allows to enumerate all DIE attributes
|
||||||
// dwarf_getfuncs() allows to enumerate functions within CU
|
// dwarf_getfuncs() allows to enumerate functions within CU
|
||||||
|
|
||||||
bool handler_get_dwarf_function(pst_handler* h, pst_function* fun)
|
bool get_dwarf_function(pst_handler* h, pst_function* fun)
|
||||||
{
|
{
|
||||||
Dwarf_Addr mod_cu = 0;
|
Dwarf_Addr mod_cu = 0;
|
||||||
// get CU(Compilation Unit) debug definition
|
// get CU(Compilation Unit) debug definition
|
||||||
@@ -64,7 +64,7 @@ bool handler_get_dwarf_function(pst_handler* h, pst_function* fun)
|
|||||||
if(tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) {
|
if(tag == DW_TAG_subprogram || tag == DW_TAG_entry_point || tag == DW_TAG_inlined_subroutine) {
|
||||||
//ctx.log(SEVERITY_DEBUG, "function die name %s", dwarf_diename(&result));
|
//ctx.log(SEVERITY_DEBUG, "function die name %s", dwarf_diename(&result));
|
||||||
if(!strcmp(fun->name, dwarf_diename(&result))) {
|
if(!strcmp(fun->name, dwarf_diename(&result))) {
|
||||||
return fun->handle_dwarf(fun, &result);
|
return pst_function_handle_dwarf(fun, &result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(dwarf_siblingof(&result, &result) == 0);
|
} while(dwarf_siblingof(&result, &result) == 0);
|
||||||
@@ -72,7 +72,7 @@ bool handler_get_dwarf_function(pst_handler* h, pst_function* fun)
|
|||||||
return nret;
|
return nret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_function* handler_add_function(pst_handler* h, pst_function* parent)
|
pst_function* add_function(pst_handler* h, pst_function* parent)
|
||||||
{
|
{
|
||||||
pst_new(pst_function, fn, &h->ctx, parent);
|
pst_new(pst_function, fn, &h->ctx, parent);
|
||||||
list_add_bottom(&h->functions, &fn->node);
|
list_add_bottom(&h->functions, &fn->node);
|
||||||
@@ -80,13 +80,13 @@ pst_function* handler_add_function(pst_handler* h, pst_function* parent)
|
|||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handler_del_function(pst_function* fn)
|
void del_function(pst_function* fn)
|
||||||
{
|
{
|
||||||
list_del(&fn->node);
|
list_del(&fn->node);
|
||||||
pst_function_fini(fn);
|
pst_function_fini(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handler_clear(pst_handler* h)
|
void clear(pst_handler* h)
|
||||||
{
|
{
|
||||||
pst_function* fn = NULL;
|
pst_function* fn = NULL;
|
||||||
struct list_node *pos, *tn;
|
struct list_node *pos, *tn;
|
||||||
@@ -96,7 +96,7 @@ void handler_clear(pst_handler* h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_function* handler_next_function(pst_handler* h, pst_function* fn)
|
pst_function* next_function(pst_handler* h, pst_function* fn)
|
||||||
{
|
{
|
||||||
list_node* n = (fn == NULL) ? list_first(&h->functions) : list_next(&fn->node);
|
list_node* n = (fn == NULL) ? list_first(&h->functions) : list_next(&fn->node);
|
||||||
pst_function* ret = NULL;
|
pst_function* ret = NULL;
|
||||||
@@ -107,7 +107,7 @@ pst_function* handler_next_function(pst_handler* h, pst_function* fn)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_function* handler_prev_function(pst_handler* h, pst_function* fn)
|
pst_function* prev_function(pst_handler* h, pst_function* fn)
|
||||||
{
|
{
|
||||||
list_node* n = (fn == NULL) ? list_last(&h->functions) : list_prev(&fn->node);
|
list_node* n = (fn == NULL) ? list_last(&h->functions) : list_prev(&fn->node);
|
||||||
pst_function* ret = NULL;
|
pst_function* ret = NULL;
|
||||||
@@ -118,7 +118,7 @@ pst_function* handler_prev_function(pst_handler* h, pst_function* fn)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pst_function* handler_last_function(pst_handler* h)
|
pst_function* last_function(pst_handler* h)
|
||||||
{
|
{
|
||||||
list_node* n = list_last(&h->functions);
|
list_node* n = list_last(&h->functions);
|
||||||
if(n) {
|
if(n) {
|
||||||
@@ -128,13 +128,13 @@ pst_function* handler_last_function(pst_handler* h)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handler_handle_dwarf(pst_handler* h)
|
bool pst_handler_handle_dwarf(pst_handler* h)
|
||||||
{
|
{
|
||||||
h->ctx.clean_print(&h->ctx);
|
h->ctx.clean_print(&h->ctx);
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
|
|
||||||
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) {
|
//for(pst_function* fun = next_function(NULL); fun; fun = next_function(fun)) {
|
||||||
for(pst_function* fun = handler_last_function(h); fun; fun = h->prev_function(h, fun)) {
|
for(pst_function* fun = last_function(h); fun; fun = prev_function(h, fun)) {
|
||||||
dladdr((void*)(fun->pc), &info);
|
dladdr((void*)(fun->pc), &info);
|
||||||
pst_log(SEVERITY_INFO, "Function %s(...): module name: %s, base address: %p, CFA: %#lX", fun->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->name, info.dli_fname, info.dli_fbase, fun->parent ? fun->parent->sp : 0);
|
||||||
|
|
||||||
@@ -146,20 +146,20 @@ bool handler_handle_dwarf(pst_handler* h)
|
|||||||
h->ctx.cfa = fun->cfa;
|
h->ctx.cfa = fun->cfa;
|
||||||
h->ctx.curr_frame = &fun->cursor;
|
h->ctx.curr_frame = &fun->cursor;
|
||||||
|
|
||||||
handler_get_dwarf_function(h, fun);
|
get_dwarf_function(h, fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handler_print_dwarf(pst_handler* h)
|
void pst_handler_print_dwarf(pst_handler* h)
|
||||||
{
|
{
|
||||||
h->ctx.clean_print(&h->ctx);
|
h->ctx.clean_print(&h->ctx);
|
||||||
h->ctx.print(&h->ctx, "DWARF-based stack trace information:\n");
|
h->ctx.print(&h->ctx, "DWARF-based stack trace information:\n");
|
||||||
uint32_t idx = 0;
|
uint32_t idx = 0;
|
||||||
for(pst_function* fn = h->next_function(h, NULL); fn; fn = h->next_function(h, fn)) {
|
for(pst_function* fn = next_function(h, NULL); fn; fn = next_function(h, fn)) {
|
||||||
h->ctx.print(&h->ctx, "[%-2u] ", idx); idx++;
|
h->ctx.print(&h->ctx, "[%-2u] ", idx); idx++;
|
||||||
fn->print_dwarf(fn);
|
pst_function_print_dwarf(fn);
|
||||||
h->ctx.print(&h->ctx, "\n");
|
h->ctx.print(&h->ctx, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ Dwfl_Callbacks callbacks = {
|
|||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
bool handler_unwind(pst_handler* h)
|
bool pst_handler_unwind(pst_handler* h)
|
||||||
{
|
{
|
||||||
h->ctx.clean_print(&h->ctx);
|
h->ctx.clean_print(&h->ctx);
|
||||||
#ifdef REG_RIP // x86_64
|
#ifdef REG_RIP // x86_64
|
||||||
@@ -239,12 +239,12 @@ bool handler_unwind(pst_handler* h)
|
|||||||
|
|
||||||
h->ctx.print(&h->ctx, "[%-2d] ", i);
|
h->ctx.print(&h->ctx, "[%-2d] ", i);
|
||||||
h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, h->addr);
|
h->ctx.module = dwfl_addrmodule(h->ctx.dwfl, h->addr);
|
||||||
pst_function* last = handler_last_function(h);
|
pst_function* last = last_function(h);
|
||||||
pst_function* fn = h->add_function(h, NULL);
|
pst_function* fn = add_function(h, NULL);
|
||||||
fn->sp = sp;
|
fn->sp = sp;
|
||||||
pst_log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, h->addr, sp);
|
pst_log(SEVERITY_DEBUG, "Analyze frame #%d: PC = %#lX, SP = %#lX", i, h->addr, sp);
|
||||||
if(!fn->unwind(fn, h->addr)) {
|
if(!pst_function_unwind(fn, h->addr)) {
|
||||||
h->del_function(fn);
|
del_function(fn);
|
||||||
} else {
|
} else {
|
||||||
if(last) {
|
if(last) {
|
||||||
last->parent = fn;
|
last->parent = fn;
|
||||||
@@ -259,17 +259,6 @@ bool handler_unwind(pst_handler* h)
|
|||||||
|
|
||||||
void pst_handler_init(pst_handler* h, ucontext_t* hctx)
|
void pst_handler_init(pst_handler* h, ucontext_t* hctx)
|
||||||
{
|
{
|
||||||
// methods
|
|
||||||
h->clear = handler_clear;
|
|
||||||
h->add_function = handler_add_function;
|
|
||||||
h->del_function = handler_del_function;
|
|
||||||
h->next_function = handler_next_function;
|
|
||||||
h->prev_function = handler_prev_function;
|
|
||||||
h->handle_dwarf = handler_handle_dwarf;
|
|
||||||
h->print_dwarf = handler_print_dwarf;
|
|
||||||
h->unwind = handler_unwind;
|
|
||||||
|
|
||||||
// fields
|
|
||||||
pst_context_init(&h->ctx, hctx);
|
pst_context_init(&h->ctx, hctx);
|
||||||
h->handle = NULL;
|
h->handle = NULL;
|
||||||
h->addr = 0;
|
h->addr = 0;
|
||||||
@@ -284,7 +273,7 @@ void pst_handler_fini(pst_handler* h)
|
|||||||
dlclose(h->handle);
|
dlclose(h->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
h->clear(h);
|
clear(h);
|
||||||
pst_context_fini(&h->ctx);
|
pst_context_fini(&h->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-12
@@ -32,18 +32,6 @@
|
|||||||
#include "dwarf_function.h"
|
#include "dwarf_function.h"
|
||||||
|
|
||||||
typedef struct pst_handler {
|
typedef struct pst_handler {
|
||||||
// methods
|
|
||||||
void (*clear) (pst_handler* h);
|
|
||||||
pst_function* (*add_function) (pst_handler* h, pst_function* fun);
|
|
||||||
void (*del_function) (pst_function* f);
|
|
||||||
pst_function* (*next_function) (pst_handler* h, pst_function* f);
|
|
||||||
pst_function* (*prev_function) (pst_handler* h, pst_function* fn);
|
|
||||||
|
|
||||||
bool (*handle_dwarf) (pst_handler* h);
|
|
||||||
void (*print_dwarf) (pst_handler* h);
|
|
||||||
bool (*unwind) (pst_handler* h);
|
|
||||||
|
|
||||||
// fields
|
|
||||||
pst_context ctx; // context of unwinding
|
pst_context ctx; // context of unwinding
|
||||||
void* handle; // process handle
|
void* handle; // process handle
|
||||||
Dwarf_Addr addr; // address of currently processed function
|
Dwarf_Addr addr; // address of currently processed function
|
||||||
@@ -54,4 +42,8 @@ typedef struct pst_handler {
|
|||||||
void pst_handler_init(pst_handler* h, ucontext_t* hctx);
|
void pst_handler_init(pst_handler* h, ucontext_t* hctx);
|
||||||
void pst_handler_fini(pst_handler* h);
|
void pst_handler_fini(pst_handler* h);
|
||||||
|
|
||||||
|
bool pst_handler_handle_dwarf(pst_handler* h);
|
||||||
|
void pst_handler_print_dwarf(pst_handler* h);
|
||||||
|
bool pst_handler_unwind(pst_handler* h);
|
||||||
|
|
||||||
#endif /* SC_SYSUTILS_H_ */
|
#endif /* SC_SYSUTILS_H_ */
|
||||||
|
|||||||
@@ -65,13 +65,13 @@ void FatalSignalHandler(int sig, siginfo_t* info, void* context)
|
|||||||
|
|
||||||
if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE))
|
if((context != 0) && (sig == SIGSEGV || sig == SIGABRT || sig == SIGBUS || sig == SIGFPE))
|
||||||
{
|
{
|
||||||
ret = handler.unwind(&handler);
|
ret = pst_handler_unwind(&handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret) {
|
if(ret) {
|
||||||
pst_log(SEVERITY_INFO, "%s", handler.ctx.buff);
|
pst_log(SEVERITY_INFO, "%s", handler.ctx.buff);
|
||||||
handler.handle_dwarf(&handler);
|
pst_handler_handle_dwarf(&handler);
|
||||||
handler.print_dwarf(&handler);
|
pst_handler_print_dwarf(&handler);
|
||||||
pst_log(SEVERITY_INFO, "%s", handler.ctx.buff);
|
pst_log(SEVERITY_INFO, "%s", handler.ctx.buff);
|
||||||
} else {
|
} else {
|
||||||
pst_log(SEVERITY_ERROR, "No stack trace obtained");
|
pst_log(SEVERITY_ERROR, "No stack trace obtained");
|
||||||
|
|||||||
Reference in New Issue
Block a user