diff --git a/src/dwarf_parser.cc b/src/dwarf_parser.cc index 7d0b767..db6c55c 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) { @@ -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 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; } do { int tag = dwarf_tag(&die); @@ -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, @@ -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; + } 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; + } res[i].offset = varloc.offset; dwarf_die_type(vardie, typedie); @@ -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; @@ -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 @@ -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; @@ -633,7 +665,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 +673,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 +691,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 cbed636..12bf22d 100644 --- a/src/dwarf_parser.h +++ b/src/dwarf_parser.h @@ -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::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*);