int dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen, Dwarf_Error *error) { Dwarf_Locdesc **_llbuf; int i, ret; ret = dwarf_loclist_n(at, &_llbuf, listlen, error); if (ret != DW_DLV_OK) return (ret); /* Only return the first location description of the list. */ *llbuf = _llbuf[0]; /* Free the rest of the list. */ for (i = 1; i < *listlen; i++) { if (_llbuf[i]->ld_s) free(_llbuf[i]->ld_s); free(_llbuf[i]); } free(_llbuf); *listlen = 1; return (DW_DLV_OK); }
Dwarf_Loc dwarf_get_variable_location(Dwarf_Die die, struct dwarf_compilation_unit * unit){ Dwarf_Error error = 0; Dwarf_Attribute *attrbuf = 0; Dwarf_Signed attrcount = 0; Dwarf_Unsigned i; Dwarf_Locdesc *llbuf = 0; Dwarf_Locdesc **llbufarray = 0; Dwarf_Signed no_of_elements; int lres = 0; Dwarf_Loc first_loc; int res = dwarf_attrlist(die,&attrbuf,&attrcount,&error); if(res != DW_DLV_OK) { return first_loc; } for(i = 0; i < attrcount ; ++i) { Dwarf_Half aform; res = dwarf_whatattr(attrbuf[i],&aform,&error); if(aform == DW_AT_location) { lres = dwarf_loclist_n(attrbuf[i], &llbufarray, &no_of_elements, &error); if (llbufarray[0]->ld_s){ first_loc = (llbufarray[0]->ld_s)[0]; return first_loc; } } } return first_loc; }
bool DieHolder::get_operand(int const attr, ea_t const rel_addr, Dwarf_Small const atom, Dwarf_Unsigned *operand, bool only_locblock) { Dwarf_Attribute attrib = get_attr(attr); Dwarf_Locdesc **llbuf = NULL; Dwarf_Locdesc *locdesc = NULL; Dwarf_Signed count = 0; Dwarf_Error err = NULL; DwarfDealloc dealloc(m_dbg); bool found = false; bool ret = false; CHECK_DWERR2(attrib == NULL, NULL, "retrieving an operand implies finding the attribute..."); CHECK_DWERR(dwarf_loclist_n(attrib, &llbuf, &count, &err), err, "cannot get location descriptions"); dealloc.add(llbuf, DW_DLA_LIST); for(Dwarf_Signed idx = 0; idx < count; ++idx) { locdesc = llbuf[idx]; // handle deallocation too dealloc.add(llbuf[idx], DW_DLA_LOCDESC); dealloc.add(llbuf[idx]->ld_s, DW_DLA_LOC_BLOCK); if(!found) { // from a location block? if(!locdesc->ld_from_loclist) { // no need to check the address found = true; } // this loc desc is from a location list else if(!only_locblock && (locdesc->ld_lopc <= rel_addr && locdesc->ld_hipc > rel_addr)) { found = true; } } } if(found) { CHECK_DWERR2(locdesc->ld_cents != 1, NULL, "only 1 location in a location description is supported"); Dwarf_Loc *loc = &locdesc->ld_s[0]; if(loc->lr_atom == atom) { *operand = loc->lr_number; ret = true; } } return ret; }
void DieHolder::get_frame_base_offsets(OffsetAreas &offset_areas) { Dwarf_Attribute attrib = get_attr(DW_AT_frame_base); Dwarf_Locdesc **llbuf = NULL; Dwarf_Locdesc *locdesc = NULL; Dwarf_Signed count = 0; Dwarf_Error err = NULL; DwarfDealloc dealloc(m_dbg); CHECK_DWERR2(attrib == NULL, NULL, "retrieving an operand implies finding the attribute..."); CHECK_DWERR(dwarf_loclist_n(attrib, &llbuf, &count, &err), err, "cannot get location descriptions"); dealloc.add(llbuf, DW_DLA_LIST); for(Dwarf_Signed idx = 0; idx < count; ++idx) { ea_t low_pc = 0; ea_t high_pc = 0; locdesc = llbuf[idx]; // handle deallocation too dealloc.add(llbuf[idx], DW_DLA_LOCDESC); dealloc.add(llbuf[idx]->ld_s, DW_DLA_LOC_BLOCK); // only 1 location in a location description is supported if(locdesc->ld_cents == 1) { Dwarf_Loc *loc = &locdesc->ld_s[0]; Dwarf_Small const atom = loc->lr_atom; // from a location block? if(!locdesc->ld_from_loclist) { low_pc = BADADDR; high_pc = BADADDR; } // this loc desc is from a location list else { low_pc = static_cast<ea_t>(locdesc->ld_lopc); high_pc = static_cast<ea_t>(locdesc->ld_hipc); } // is it the right atom to get the offset from? if(atom == DW_OP_breg4 || atom == DW_OP_breg5) { offset_areas.push_back(OffsetArea(low_pc, high_pc, // operand is unsigned, but should be signed... static_cast<sval_t>(loc->lr_number), (atom == DW_OP_breg5))); } } } }
void DieHolder::retrieve_var(func_t *funptr, ea_t const cu_low_pc, OffsetAreas const &offset_areas, func_type_info_t *info, var_visitor_fun visit) { Dwarf_Attribute attrib = get_attr(DW_AT_location); if(attrib != NULL) { Dwarf_Locdesc **llbuf = NULL; Dwarf_Locdesc *locdesc = NULL; Dwarf_Signed count = 0; Dwarf_Error err = NULL; DwarfDealloc dealloc(m_dbg); size_t const nb_args = (info == NULL) ? 0 : info->size(); CHECK_DWERR(dwarf_loclist_n(attrib, &llbuf, &count, &err), err, "cannot get location descriptions"); dealloc.add(llbuf, DW_DLA_LIST); for(Dwarf_Signed idx = 0; idx < count; ++idx) { locdesc = llbuf[idx]; // handle deallocation too dealloc.add(llbuf[idx], DW_DLA_LOCDESC); dealloc.add(llbuf[idx]->ld_s, DW_DLA_LOC_BLOCK); visit(*this, locdesc, funptr, cu_low_pc, offset_areas, info); if(info != NULL && info->size() != nb_args) { // parameter has already been added, do not add it twice! info = NULL; } } } }