diff --git a/src/dwarf_parser.cc b/src/dwarf_parser.cc index b905c15..e5cb398 100644 --- a/src/dwarf_parser.cc +++ b/src/dwarf_parser.cc @@ -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( @@ -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) { @@ -412,7 +416,10 @@ void DwarfParser::translate_fields(Dwarf_Die *vardie, Dwarf_Die *typedie, 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; + } res[i].offset = varloc.offset; dwarf_die_type(vardie, typedie); @@ -538,7 +545,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; @@ -555,8 +569,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 @@ -608,14 +626,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; @@ -633,7 +656,7 @@ 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 { @@ -641,8 +664,13 @@ void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr, } } - 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; @@ -654,6 +682,7 @@ void DwarfParser::translate_expr(Dwarf_Attribute *fb_attr, Dwarf_Op *expr, default: break; } + return true; } Dwfl *DwarfParser::create_dwfl(int fd, const char *fname) { diff --git a/src/dwarf_parser.h b/src/dwarf_parser.h index 8432557..0f6e914 100644 --- a/src/dwarf_parser.h +++ b/src/dwarf_parser.h @@ -70,10 +70,10 @@ 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 *); @@ -83,7 +83,7 @@ class DwarfParser { std::vector, std::vector &); 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*);