Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 72 additions & 34 deletions src/dwarf_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,12 @@ void DwarfParser::traverse_module(Dwfl_Module *mod, Dwarf *dw, bool want_type) {
}
}

Dwarf_Die DwarfParser::find_param(Dwarf_Die *func, string symbol) {
Dwarf_Die vardie;

dwarf_getscopevar(func, 1, symbol.c_str(), 0, NULL, 0, 0, &vardie);

return vardie;
bool DwarfParser::find_param(Dwarf_Die *func, string symbol,
Dwarf_Die &vardie) {
// dwarf_getscopevar: returns a non-negative scope index on success, -1 on
// error or -2 when no matching variable exists. On failure it leaves
// vardie untouched, so the caller must not use it.
return dwarf_getscopevar(func, 1, symbol.c_str(), 0, NULL, 0, 0, &vardie) >= 0;
}

Dwarf_Attribute *DwarfParser::find_func_frame_base(
Expand All @@ -217,27 +217,31 @@ Dwarf_Attribute *DwarfParser::find_func_frame_base(
return fb_attr;
}

VarLocation DwarfParser::translate_param_location(Dwarf_Die *func,
string symbol, Dwarf_Addr pc,
Dwarf_Die &vardie) {
vardie = find_param(func, symbol);
Dwarf_Attribute fb_attr_mem;
Dwarf_Attribute *fb_attr = find_func_frame_base(func, &fb_attr_mem);
bool DwarfParser::translate_param_location(Dwarf_Die *func, string symbol,
Dwarf_Addr pc, Dwarf_Die &vardie,
VarLocation &varloc) {
if (!find_param(func, symbol, vardie)) {
cerr << "Couldn't find parameter " << symbol << endl;
return false;
}

// Assume the vardie must has a DW_AT_location
Dwarf_Attribute loc_attr;
dwarf_attr_integrate(&vardie, DW_AT_location, &loc_attr);
if (dwarf_attr_integrate(&vardie, DW_AT_location, &loc_attr) == NULL) {
cerr << "Parameter " << symbol << " has no DW_AT_location" << endl;
return false;
}

Dwarf_Op *expr;
size_t len;
int r = dwarf_getlocation_addr(&loc_attr, pc, &expr, &len, 1);
if (r != 1 || len <= 0) {
if (r != 1 || len == 0) {
cerr << "Get param location expr failed for symbol " << symbol << endl;
return false;
}

VarLocation varloc;
translate_expr(fb_attr, expr, pc, varloc);
return varloc;
Dwarf_Attribute fb_attr_mem;
Dwarf_Attribute *fb_attr = find_func_frame_base(func, &fb_attr_mem);
return translate_expr(fb_attr, expr, pc, varloc);
}

bool DwarfParser::find_prologue(Dwarf_Die *func, Dwarf_Addr &pc) {
Expand Down Expand Up @@ -307,20 +311,20 @@ Dwarf_Die * DwarfParser::dwarf_attr_die(Dwarf_Die *die, unsigned int attr_flag,
return NULL;
}

void DwarfParser::find_class_member(Dwarf_Die *vardie, Dwarf_Die *typedie,
bool DwarfParser::find_class_member(Dwarf_Die *vardie, Dwarf_Die *typedie,
string member, Dwarf_Attribute *attr) {
// TODO deal with inheritance later

std::queue<Dwarf_Die> die_queue;
die_queue.push(*typedie);
bool found = false;
while (!die_queue.empty()) {
bool found = false;
Dwarf_Die die;
int r = dwarf_child(&die_queue.front(), &die);
if (r != 0) {
cerr << "the class " << dwarf_diename(typedie)
<< " has no children, unexpected and exit" << endl;
return;
return false;
Comment on lines 325 to +327
}
do {
int tag = dwarf_tag(&die);
Expand All @@ -345,15 +349,21 @@ void DwarfParser::find_class_member(Dwarf_Die *vardie, Dwarf_Die *typedie,

} while (dwarf_siblingof(&die, &die) == 0);
die_queue.pop();
if (found)
if (found)
break;
}

if (!found) {
cerr << "couldn't find member " << member << endl;
return false;
}
if (dwarf_hasattr_integrate(vardie, DW_AT_data_member_location)) {
dwarf_attr_integrate(vardie, DW_AT_data_member_location, attr);
} else if (dwarf_hasattr_integrate(vardie, DW_AT_data_bit_offset)) {
// TODO deal with bit member
return true;
}
// DW_AT_data_bit_offset (bitfield) is not handled yet; report failure
// instead of leaving attr unset for the caller to dereference.
return false;
}

void DwarfParser::translate_fields(Dwarf_Die *vardie, Dwarf_Die *typedie,
Expand Down Expand Up @@ -404,15 +414,21 @@ void DwarfParser::translate_fields(Dwarf_Die *vardie, Dwarf_Die *typedie,
*typedie = *tmpdie;
}
Dwarf_Attribute attr;
find_class_member(vardie, typedie, fields[i], &attr);
if (!find_class_member(vardie, typedie, fields[i], &attr)) {
clog << "failed to find member location for " << fields[i] << endl;
return;
}
Comment on lines +417 to +420
Dwarf_Op *expr;
size_t len;
if (dwarf_getlocation_addr(&attr, pc, &expr, &len, 1) != 1) {
if (dwarf_getlocation_addr(&attr, pc, &expr, &len, 1) != 1 || len == 0) {
clog << "failed to get location of attr for " << fields[i] << endl;
return;
}
VarLocation varloc;
translate_expr(NULL, expr, pc, varloc);
if (!translate_expr(NULL, expr, pc, varloc)) {
clog << "failed to translate location of " << fields[i] << endl;
return;
}
Comment thread
xtrusia marked this conversation as resolved.
res[i].offset = varloc.offset;

dwarf_die_type(vardie, typedie);
Expand Down Expand Up @@ -538,7 +554,14 @@ static int handle_function(Dwarf_Die *die, void *data) {
for (int i = 0; i < (int)arr.size(); ++i) {
string varname = arr[i][0];
Dwarf_Die vardie, typedie;
VarLocation varloc = dp->translate_param_location(die, varname, pc, vardie);
VarLocation varloc;
if (!dp->translate_param_location(die, varname, pc, vardie, varloc)) {
cerr << "Skip probe on " << fullname << ": parameter " << varname
<< " unresolved" << endl;
func2pc.erase(fullname);
func2vf.erase(fullname);
return 0;
}
//printf("var %s location : register %d, offset %d, stack %d\n",
//varname.c_str(), varloc.reg, varloc.offset, varloc.stack);
vf[i].varloc = varloc;
Expand All @@ -555,8 +578,12 @@ static int handle_function(Dwarf_Die *die, void *data) {
return 0;
}

void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr,
bool DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr,
Dwarf_Addr pc, VarLocation &varloc) {
if (expr == NULL) {
cerr << "translate_expr: null location expression" << endl;
return false;
}
int atom = expr->atom;

// TODO can put a debug message to print the atom's name in string
Expand Down Expand Up @@ -608,14 +635,19 @@ void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr,
break;

case DW_OP_fbreg: {
if (fb_attr == NULL) {
cerr << "translate_expr: DW_OP_fbreg with no frame base" << endl;
return false;
}
Dwarf_Op *fb_expr;
size_t fb_exprlen;
int res = dwarf_getlocation_addr(fb_attr, pc, &fb_expr, &fb_exprlen, 1);
if (res != 1) {
if (res != 1 || fb_exprlen == 0) {
cerr << "translate_expr get fb_expr failed" << endl;
return false;
}

translate_expr(fb_attr, fb_expr, pc, varloc);
if (!translate_expr(fb_attr, fb_expr, pc, varloc)) return false;
varloc.offset += expr->number;
varloc.stack = true;
} break;
Expand All @@ -633,16 +665,21 @@ void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr,
}
}

if (cfa_ops == NULL) {
if (cfa_ops == NULL && cfi_eh != NULL) {
if (dwarf_cfi_addrframe(cfi_eh, pc, &frame) == 0) {
dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
} else {
cerr << "dwarf_frame_cfa add eh frame failed" << endl;
}
}

translate_expr(fb_attr, cfa_ops, pc, varloc);
} break;
if (cfa_ops == NULL) {
cerr << "translate_expr: could not resolve call frame CFA" << endl;
return false;
}

return translate_expr(fb_attr, cfa_ops, pc, varloc);
}
case DW_OP_reg0 ... DW_OP_reg31:
varloc.reg = expr->atom - DW_OP_reg0;
break;
Expand All @@ -654,6 +691,7 @@ void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr,
default:
break;
}
return true;
Comment on lines 691 to +694
}

Dwfl *DwarfParser::create_dwfl(int fd, const char *fname) {
Expand Down
10 changes: 5 additions & 5 deletions src/dwarf_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,20 @@ class DwarfParser {
const char *cache_type_prefix(Dwarf_Die *);
int iterate_types_in_cu(mod_cu_type_cache_t &, Dwarf_Die *);
void traverse_module(Dwfl_Module *, Dwarf *, bool);
Dwarf_Die find_param(Dwarf_Die *, std::string);
bool find_param(Dwarf_Die *, std::string, Dwarf_Die &);
Dwarf_Attribute *find_func_frame_base(Dwarf_Die *, Dwarf_Attribute *);
VarLocation translate_param_location(Dwarf_Die *, std::string, Dwarf_Addr,
Dwarf_Die &);
bool translate_param_location(Dwarf_Die *, std::string, Dwarf_Addr,
Dwarf_Die &, VarLocation &);
bool func_entrypc(Dwarf_Die *, Dwarf_Addr *);
bool find_prologue(Dwarf_Die *func, Dwarf_Addr &pc);
void dwarf_die_type(Dwarf_Die *, Dwarf_Die *);
void find_class_member(Dwarf_Die *, Dwarf_Die *, std::string,
bool find_class_member(Dwarf_Die *, Dwarf_Die *, std::string,
Dwarf_Attribute *);
void translate_fields(Dwarf_Die *, Dwarf_Die *, Dwarf_Addr,
std::vector<std::string>, std::vector<Field> &);
bool filter_func(std::string);
bool filter_cu(std::string);
void translate_expr(Dwarf_Attribute *, Dwarf_Op *, Dwarf_Addr, VarLocation &);
bool translate_expr(Dwarf_Attribute *, Dwarf_Op *, Dwarf_Addr, VarLocation &);
Dwfl *create_dwfl(int, const char *);
std::string special_inlined_function_scope(const char *);
Dwarf_Die * dwarf_attr_die(Dwarf_Die*, unsigned int, Dwarf_Die*);
Expand Down
Loading