save call-site parameters in caller
This commit is contained in:
+156
-60
@@ -310,6 +310,94 @@ bool __pst_parameter::handle_dwarf(Dwarf_Die* result)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pst_call_site_param* __pst_call_site::add_param()
|
||||||
|
{
|
||||||
|
pst_call_site_param* p = new pst_call_site_param(ctx);
|
||||||
|
params.InsertLast(p);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __pst_call_site::del_param(pst_call_site_param* p)
|
||||||
|
{
|
||||||
|
params.Remove(p);
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_call_site_param* __pst_call_site::next_param(pst_call_site_param* p)
|
||||||
|
{
|
||||||
|
pst_call_site_param* param = NULL;
|
||||||
|
if(p == NULL) {
|
||||||
|
param = (pst_call_site_param*)params.First();
|
||||||
|
} else {
|
||||||
|
param = (pst_call_site_param*)params.Next(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __pst_call_site::handle_dwarf(Dwarf_Die* child)
|
||||||
|
{
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Attribute* attr;
|
||||||
|
|
||||||
|
do {
|
||||||
|
switch(dwarf_tag(child))
|
||||||
|
{
|
||||||
|
case DW_TAG_GNU_call_site_parameter: {
|
||||||
|
Dwarf_Addr pc;
|
||||||
|
unw_get_reg(ctx->curr_frame, UNW_REG_IP, &pc);
|
||||||
|
|
||||||
|
char str[1024];
|
||||||
|
// expression represent where callee parameter will be stored
|
||||||
|
pst_call_site_param* param = new pst_call_site_param(ctx);
|
||||||
|
if(dwarf_hasattr(child, DW_AT_location)) {
|
||||||
|
// handle location expression here
|
||||||
|
// determine location of parameter in stack/heap or CPU registers
|
||||||
|
attr = dwarf_attr(child, DW_AT_location, &attr_mem);
|
||||||
|
if(handle_location(ctx, attr, param->location, pc, str, sizeof(str))) {
|
||||||
|
uint64_t value = 0;
|
||||||
|
if(param->location.get_value(value)) {
|
||||||
|
ctx->log(SEVERITY_DEBUG, "\tDW_TAG_GNU_call_site_parameter: \"%s\" ==> 0x%lX", str, value);
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_WARNING, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
||||||
|
del_param(param);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// expression represents call parameter's value
|
||||||
|
if(dwarf_hasattr(child, DW_AT_GNU_call_site_value)) {
|
||||||
|
// handle value expression here
|
||||||
|
attr = dwarf_attr(child, DW_AT_GNU_call_site_value, &attr_mem);
|
||||||
|
dwarf_stack stack(ctx);
|
||||||
|
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
||||||
|
if(stack.get_value(param->value)) {
|
||||||
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", str, param->value);
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
||||||
|
del_param(param);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
||||||
|
del_param(param);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (dwarf_siblingof (child, child) == 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pst_parameter* __pst_function::add_param()
|
pst_parameter* __pst_function::add_param()
|
||||||
{
|
{
|
||||||
pst_parameter* p = new pst_parameter(ctx);
|
pst_parameter* p = new pst_parameter(ctx);
|
||||||
@@ -344,6 +432,55 @@ pst_parameter* __pst_function::next_param(pst_parameter* p)
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pst_call_site* __pst_function::add_call_site(uint64_t target, const char* origin)
|
||||||
|
{
|
||||||
|
pst_call_site* st = new pst_call_site(ctx, target, origin);
|
||||||
|
call_sites.InsertLast(st);
|
||||||
|
if(target) {
|
||||||
|
mCallStToTarget.Insert(&target, sizeof(target), st);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(origin) {
|
||||||
|
mCallStToOrigin.Insert(origin, strlen(origin), st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
void __pst_function::del_call_site(pst_call_site* st)
|
||||||
|
{
|
||||||
|
call_sites.Remove(st);
|
||||||
|
if(st->target && mCallStToTarget.Lookup(&st->target, sizeof(st->target))) {
|
||||||
|
mCallStToTarget.Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(st->origin && mCallStToTarget.Lookup(st->origin, strlen(st->origin))) {
|
||||||
|
mCallStToTarget.Remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete st;
|
||||||
|
}
|
||||||
|
pst_call_site* __pst_function::next_call_site(pst_call_site* st)
|
||||||
|
{
|
||||||
|
pst_call_site* next = NULL;
|
||||||
|
if(st) {
|
||||||
|
next = (pst_call_site*)call_sites.First();
|
||||||
|
} else {
|
||||||
|
next = (pst_call_site*)call_sites.Next(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_call_site* __pst_function::call_site_by_origin(const char* origin)
|
||||||
|
{
|
||||||
|
return (pst_call_site*)mCallStToOrigin.Lookup(origin, strlen(origin));
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_call_site* __pst_function::call_site_by_target(uint64_t target)
|
||||||
|
{
|
||||||
|
return (pst_call_site*)mCallStToTarget.Lookup(&target, sizeof(target));
|
||||||
|
}
|
||||||
|
|
||||||
bool __pst_function::print_dwarf()
|
bool __pst_function::print_dwarf()
|
||||||
{
|
{
|
||||||
char* at = NULL;
|
char* at = NULL;
|
||||||
@@ -490,87 +627,46 @@ bool __pst_function::handle_call_site(Dwarf_Die* result)
|
|||||||
|
|
||||||
ctx->log(SEVERITY_DEBUG, "***** DW_TAG_GNU_call_site contents:");
|
ctx->log(SEVERITY_DEBUG, "***** DW_TAG_GNU_call_site contents:");
|
||||||
// reference to DIE which represents callee's parameter if compiler knows where it is at compile time
|
// reference to DIE which represents callee's parameter if compiler knows where it is at compile time
|
||||||
|
const char* oname = NULL;
|
||||||
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
if(dwarf_hasattr (result, DW_AT_abstract_origin) && dwarf_formref_die (dwarf_attr (result, DW_AT_abstract_origin, &attr_mem), &origin) != NULL) {
|
||||||
Dwarf_Die child;
|
oname = dwarf_diename(&origin);
|
||||||
if(dwarf_child (&origin, &child) == 0) {
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_abstract_origin: '%s'", oname);
|
||||||
do {
|
|
||||||
switch (dwarf_tag (&child))
|
|
||||||
{
|
|
||||||
case DW_TAG_variable:
|
|
||||||
case DW_TAG_formal_parameter:
|
|
||||||
ctx->log(SEVERITY_DEBUG, "\tDW_AT_abstract_origin: %s('%s')", dwarf_diename(&origin), dwarf_diename (&child));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (dwarf_siblingof (&child, &child) == 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The call site may have a DW_AT_call_site_target attribute which is a DWARF expression. For indirect calls or jumps where it is unknown at
|
// The call site may have a DW_AT_call_site_target attribute which is a DWARF expression. For indirect calls or jumps where it is unknown at
|
||||||
// compile time which subprogram will be called the expression computes the address of the subprogram that will be called.
|
// compile time which subprogram will be called the expression computes the address of the subprogram that will be called.
|
||||||
|
uint64_t target = 0;
|
||||||
if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) {
|
if(dwarf_hasattr (result, DW_AT_GNU_call_site_target)) {
|
||||||
attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
|
attr = dwarf_attr(result, DW_AT_GNU_call_site_target, &attr_mem);
|
||||||
if(attr) {
|
if(attr) {
|
||||||
dwarf_stack stack(ctx);
|
dwarf_stack stack(ctx);
|
||||||
char str[1024]; str[0] = 0;
|
char str[1024]; str[0] = 0;
|
||||||
uint64_t value;
|
|
||||||
if(handle_location(ctx, &attr_mem, stack, pc, str, sizeof(str))) {
|
if(handle_location(ctx, &attr_mem, stack, pc, str, sizeof(str))) {
|
||||||
if(stack.get_value(value)) {
|
if(stack.get_value(target)) {
|
||||||
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_target: %s ==> %#lX", str, (void*)value);
|
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_target: %s ==> %#lX", str, (void*)target);
|
||||||
} else {
|
} else {
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_GNU_call_site_target expression: %s", str);
|
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_GNU_call_site_target expression: %s", str);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_GNU_call_site_target expression: %s", str);
|
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_GNU_call_site_target expression: %s", str);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(target == 0 && oname == NULL) {
|
||||||
|
ctx->log(SEVERITY_ERROR, "Cannot determine both call-site target and origin");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Dwarf_Die child;
|
Dwarf_Die child;
|
||||||
if(dwarf_child (result, &child) == 0) {
|
if(dwarf_child (result, &child) == 0) {
|
||||||
do {
|
pst_call_site* st = add_call_site(target, oname);
|
||||||
switch (dwarf_tag (&child))
|
if(!st->handle_dwarf(&child)) {
|
||||||
{
|
del_call_site(st);
|
||||||
case DW_TAG_GNU_call_site_parameter: {
|
return false;
|
||||||
Dwarf_Addr pc;
|
}
|
||||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
|
||||||
|
|
||||||
dwarf_stack stack(ctx); char str[1024]; uint64_t value;
|
|
||||||
// expression represent where calle parameter vill be stored
|
|
||||||
if(dwarf_hasattr(&child, DW_AT_location)) {
|
|
||||||
// handle location expression here
|
|
||||||
// determine location of parameter in stack/heap or CPU registers
|
|
||||||
attr = dwarf_attr(&child, DW_AT_location, &attr_mem);
|
|
||||||
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
|
||||||
if(stack.get_value(value)) {
|
|
||||||
ctx->log(SEVERITY_DEBUG, "\tDW_TAG_GNU_call_site_parameter: \"%s\" ==> 0x%lX", str, value);
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// expression represents call parameter's value
|
|
||||||
if(dwarf_hasattr(&child, DW_AT_GNU_call_site_value)) {
|
|
||||||
// handle value expression here
|
|
||||||
attr = dwarf_attr(&child, DW_AT_GNU_call_site_value, &attr_mem);
|
|
||||||
if(handle_location(ctx, attr, stack, pc, str, sizeof(str))) {
|
|
||||||
if(stack.get_value(value)) {
|
|
||||||
ctx->log(SEVERITY_DEBUG, "\tDW_AT_GNU_call_site_value:\"%s\" ==> 0x%lX", str, value);
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to get value of calculated DW_AT_location expression: %s", str);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx->log(SEVERITY_ERROR, "Failed to calculate DW_AT_location expression: %s", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (dwarf_siblingof (&child, &child) == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+70
-4
@@ -20,8 +20,11 @@
|
|||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
#include <elfutils/libdwfl.h>
|
#include <elfutils/libdwfl.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "dictionary.h"
|
||||||
|
#include "dwarf_operations.h"
|
||||||
|
|
||||||
typedef struct __pst_function pst_function;
|
typedef struct __pst_function pst_function;
|
||||||
|
|
||||||
@@ -76,6 +79,57 @@ typedef struct __pst_parameter : public SC_ListNode {
|
|||||||
pst_context* ctx;
|
pst_context* ctx;
|
||||||
} pst_parameter;
|
} pst_parameter;
|
||||||
|
|
||||||
|
// DW_TAG_call_site_parameter
|
||||||
|
typedef struct __pst_call_site_param : public SC_ListNode {
|
||||||
|
__pst_call_site_param(pst_context* ctx) : location(ctx) {
|
||||||
|
param = NULL; name = NULL; value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~__pst_call_site_param() {
|
||||||
|
if(name) {
|
||||||
|
free(name); name = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dwarf_Die* param; // reference to parameter DIE in callee (DW_AT_call_parameter)
|
||||||
|
char* name; // name of parameter if present (DW_AT_name)
|
||||||
|
dwarf_stack location; // DWARF stack containing location expression
|
||||||
|
uint64_t value; // parameter's value
|
||||||
|
} pst_call_site_param;
|
||||||
|
|
||||||
|
// DW_TAG_call_site
|
||||||
|
typedef struct __pst_call_site : public SC_ListNode {
|
||||||
|
__pst_call_site(pst_context* c, uint64_t tgt, const char* orn) {
|
||||||
|
target = tgt;
|
||||||
|
if(orn) {
|
||||||
|
origin = strdup(orn);
|
||||||
|
} else {
|
||||||
|
origin = NULL;
|
||||||
|
}
|
||||||
|
die = NULL;
|
||||||
|
ctx = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
~__pst_call_site() {
|
||||||
|
if(origin) {
|
||||||
|
free(origin);
|
||||||
|
origin = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pst_call_site_param* add_param();
|
||||||
|
void del_param(pst_call_site_param* p);
|
||||||
|
pst_call_site_param* next_param(pst_call_site_param* p);
|
||||||
|
|
||||||
|
bool handle_dwarf(Dwarf_Die* die);
|
||||||
|
|
||||||
|
uint64_t target; // pointer to callee function's (it's Low PC + base address)
|
||||||
|
char* origin; // name of callee function
|
||||||
|
Dwarf_Die* die; // DIE of function for which this call site has parameters
|
||||||
|
SC_ListHead params; // list of parameters and their values
|
||||||
|
pst_context* ctx;
|
||||||
|
} pst_call_site;
|
||||||
|
|
||||||
typedef struct __pst_handler pst_handler;
|
typedef struct __pst_handler pst_handler;
|
||||||
|
|
||||||
typedef struct __pst_function : public SC_ListNode {
|
typedef struct __pst_function : public SC_ListNode {
|
||||||
@@ -100,20 +154,32 @@ typedef struct __pst_function : public SC_ListNode {
|
|||||||
void del_param(pst_parameter* p);
|
void del_param(pst_parameter* p);
|
||||||
pst_parameter* next_param(pst_parameter* p);
|
pst_parameter* next_param(pst_parameter* p);
|
||||||
|
|
||||||
|
pst_call_site* add_call_site(uint64_t target, const char* origin);
|
||||||
|
void del_call_site(pst_call_site* st);
|
||||||
|
pst_call_site* next_call_site(pst_call_site* st);
|
||||||
|
pst_call_site* call_site_by_origin(const char* origin);
|
||||||
|
pst_call_site* call_site_by_target(uint64_t target);
|
||||||
|
|
||||||
bool unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr);
|
bool unwind(Dwfl* dwfl, Dwfl_Module* module, Dwarf_Addr addr);
|
||||||
bool handle_dwarf(Dwarf_Die* d);
|
bool handle_dwarf(Dwarf_Die* d);
|
||||||
bool print_dwarf();
|
bool print_dwarf();
|
||||||
bool handle_lexical_block(Dwarf_Die* result);
|
bool handle_lexical_block(Dwarf_Die* result);
|
||||||
bool handle_call_site(Dwarf_Die* result);
|
bool handle_call_site(Dwarf_Die* result);
|
||||||
|
|
||||||
Dwarf_Addr lowpc; // start of the function
|
Dwarf_Addr lowpc; // offset to start of the function against base address
|
||||||
Dwarf_Addr highpc; // next address after the end of the function
|
Dwarf_Addr highpc; // offset to the next address after the end of the function against base address
|
||||||
Dwarf_Die* die; // DWARF DIE containing definition of the function
|
Dwarf_Die* die; // DWARF DIE containing definition of the function
|
||||||
std::string name; // function's name
|
std::string name; // function's name
|
||||||
SC_ListHead params; // function's parameters
|
SC_ListHead params; // function's parameters
|
||||||
|
|
||||||
|
// call-site
|
||||||
|
SC_ListHead call_sites; // Call-Site definitions
|
||||||
|
SC_Dict mCallStToTarget; // map pointer to caller to call-site
|
||||||
|
SC_Dict mCallStToOrigin; // map caller name to call-site
|
||||||
|
|
||||||
unw_word_t pc; // address between lowpc & highpc (plus base address offset). actually, currently executed command
|
unw_word_t pc; // address between lowpc & highpc (plus base address offset). actually, currently executed command
|
||||||
unw_word_t sp; // SP register in function's frame
|
unw_word_t sp; // SP register in function's frame
|
||||||
unw_word_t cfa;
|
unw_word_t cfa; // CFA (Canonical Frame Adress) of the function
|
||||||
unw_cursor_t cursor; // copy of stack state of the function
|
unw_cursor_t cursor; // copy of stack state of the function
|
||||||
int line; // line in code where function is defined
|
int line; // line in code where function is defined
|
||||||
std::string file; // file name (DWARF Compilation Unit) where function is defined
|
std::string file; // file name (DWARF Compilation Unit) where function is defined
|
||||||
|
|||||||
Reference in New Issue
Block a user