//---------------------------------------------------------------------- // Parse // // Parses the .debug_info section and uses the .debug_abbrev section // and various other sections in the SymbolFileDWARF class and calls the // supplied callback function each time a compile unit header, or debug // information entry is successfully parsed. This function can be used // for different tasks such as parsing the file contents into a // structured data, dumping, verifying and much more. //---------------------------------------------------------------------- void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, void *userData) { if (dwarf2Data) { lldb::offset_t offset = 0; uint32_t depth = 0; DWARFDebugInfoEntry die; DWARFCompileUnitSP cu; while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) { const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); depth = 0; // Call the callback function with no DIE pointer for the compile unit // and get the offset that we are to continue to parse from offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); // Make sure we are within our compile unit if (offset < next_cu_offset) { // We are in our compile unit, parse starting at the offset // we were told to parse bool done = false; while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { // Call the callback function with DIE pointer that falls within the // compile unit offset = callback(dwarf2Data, cu.get(), &die, offset, depth, userData); if (die.IsNULL()) { if (depth) --depth; else done = true; // We are done with this compile unit! } else if (die.HasChildren()) ++depth; } } // Make sure the offset returned is valid, and if not stop parsing. // Returning DW_INVALID_OFFSET from this callback is a good way to end // all parsing if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) break; // Make sure we start on a proper offset = next_cu_offset; } } }
static dw_offset_t FindCallbackString ( SymbolFileDWARF* dwarf2Data, DWARFCompileUnitSP& cu_sp, DWARFDebugInfoEntry* die, const dw_offset_t next_offset, const uint32_t curr_depth, void* userData ) { FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData; const DWARFCompileUnit* cu = cu_sp.get(); if (die) { const char* die_name = die->GetName(dwarf2Data, cu); if (die_name) { if (info->regex) { if (info->regex->Execute(die_name)) info->die_offsets.push_back(die->GetOffset()); } else { if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0) info->die_offsets.push_back(die->GetOffset()); } } } // Just return the current offset to parse the next CU or DIE entry return next_offset; }
static dw_offset_t DWARFDebugInfo_ParseCallback ( SymbolFileDWARF* dwarf2Data, DWARFCompileUnitSP& cu_sp, DWARFDebugInfoEntry* die, const dw_offset_t next_offset, const uint32_t curr_depth, void* userData ) { DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData; DWARFCompileUnit* cu = cu_sp.get(); if (die) { cu->AddDIE(*die); } else if (cu) { debug_info->AddCompileUnit(cu_sp); } // Just return the current offset to parse the next CU or DIE entry return next_offset; }
//---------------------------------------------------------------------- // LookupAddress //---------------------------------------------------------------------- bool DWARFDebugInfo::LookupAddress ( const dw_addr_t address, const dw_offset_t hint_die_offset, DWARFCompileUnitSP& cu_sp, DWARFDebugInfoEntry** function_die, DWARFDebugInfoEntry** block_die ) { if (hint_die_offset != DW_INVALID_OFFSET) cu_sp = GetCompileUnit(hint_die_offset); else { DWARFDebugAranges &cu_aranges = GetCompileUnitAranges (); const dw_offset_t cu_offset = cu_aranges.FindAddress (address); cu_sp = GetCompileUnit(cu_offset); } if (cu_sp.get()) { if (cu_sp->LookupAddress(address, function_die, block_die)) return true; cu_sp.reset(); } else { // The hint_die_offset may have been a pointer to the actual item that // we are looking for DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp); if (die_ptr) { if (cu_sp.get()) { if (function_die || block_die) return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die); // We only wanted the compile unit that contained this address return true; } } } return false; }
bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) { return offset < cu_sp->GetOffset(); }
//---------------------------------------------------------------------- // DumpCallback // // A callback function for the static DWARFDebugInfo::Parse() function // that gets called each time a compile unit header or debug information // entry is successfully parsed. // // This function dump DWARF information and obey recurse depth and // whether a single DIE is to be dumped (or all of the data). //---------------------------------------------------------------------- static dw_offset_t DumpCallback ( SymbolFileDWARF* dwarf2Data, DWARFCompileUnitSP& cu_sp, DWARFDebugInfoEntry* die, const dw_offset_t next_offset, const uint32_t curr_depth, void* userData ) { DumpInfo* dumpInfo = (DumpInfo*)userData; const DWARFCompileUnit* cu = cu_sp.get(); Stream *s = dumpInfo->strm; bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); if (die) { // Are we dumping everything? if (dumpInfo->die_offset == DW_INVALID_OFFSET) { // Yes we are dumping everything. Obey our recurse level though if (curr_depth < dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } else { // We are dumping a specific DIE entry by offset if (dumpInfo->die_offset == die->GetOffset()) { // We found the DIE we were looking for, dump it! if (show_parents) { s->SetIndentLevel(0); const uint32_t num_ancestors = dumpInfo->ancestors.size(); if (num_ancestors > 0) { for (uint32_t i=0; i<num_ancestors-1; ++i) { dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); s->IndentMore(); } } } dumpInfo->found_depth = curr_depth; die->Dump(dwarf2Data, cu, *s, 0); // Note that we found the DIE we were looking for dumpInfo->found_die = true; // Since we are dumping a single DIE, if there are no children we are done! if (!die->HasChildren() || dumpInfo->recurse_depth == 0) return DW_INVALID_OFFSET; // Return an invalid address to end parsing } else if (dumpInfo->found_die) { // Are we done with all the children? if (curr_depth <= dumpInfo->found_depth) return DW_INVALID_OFFSET; // We have already found our DIE and are printing it's children. Obey // our recurse depth and return an invalid offset if we get done // dumping all the the children if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } else if (dumpInfo->die_offset > die->GetOffset()) { if (show_parents) dumpInfo->ancestors.back() = *die; } } // Keep up with our indent level if (die->IsNULL()) { if (show_parents) dumpInfo->ancestors.pop_back(); if (curr_depth <= 1) return cu->GetNextCompileUnitOffset(); else s->IndentLess(); } else if (die->HasChildren()) { if (show_parents) { DWARFDebugInfoEntry null_die; dumpInfo->ancestors.push_back(null_die); } s->IndentMore(); } } else { if (cu == NULL) s->PutCString("NULL - cu"); // We have a compile unit, reset our indent level to zero just in case s->SetIndentLevel(0); // See if we are dumping everything? if (dumpInfo->die_offset == DW_INVALID_OFFSET) { // We are dumping everything cu->Dump(s); return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit } else { if (show_parents) { dumpInfo->ancestors.clear(); dumpInfo->ancestors.resize(1); } // We are dumping only a single DIE possibly with it's children and // we must find it's compile unit before we can dump it properly if (dumpInfo->die_offset < cu->GetFirstDIEOffset()) { // Not found, maybe the DIE offset provided wasn't correct? // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl; return DW_INVALID_OFFSET; } else { // See if the DIE is in this compile unit? if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { // This DIE is in this compile unit! if (s->GetVerbose()) cu->Dump(s); // Dump the compile unit for the DIE in verbose mode return next_offset; // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE... // return dumpInfo->die_offset; } else { // Skip to the next compile unit as the DIE isn't in the current one! return cu->GetNextCompileUnitOffset(); } } } } // Just return the current offset to parse the next CU or DIE entry return next_offset; }
static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b) { return a->GetOffset() < b->GetOffset(); }