//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "SymbolFileDWARF.h" #include #include #include "lldb/Host/PosixApi.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" #include "DWARFCompileUnit.h" #include "DWARFDebugAranges.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" #include "DWARFFormValue.h" #include "LogChannelDWARF.h" using namespace lldb; using namespace lldb_private; using namespace std; //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- DWARFDebugInfo::DWARFDebugInfo() : m_dwarf2Data(NULL), m_compile_units(), m_cu_aranges_ap() {} //---------------------------------------------------------------------- // SetDwarfData //---------------------------------------------------------------------- void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) { m_dwarf2Data = dwarf2Data; m_compile_units.clear(); } DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); m_cu_aranges_ap.reset(new DWARFDebugAranges()); const DWARFDataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data(); if (debug_aranges_data.GetByteSize() > 0) { if (log) log->Printf( "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from " ".debug_aranges", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); m_cu_aranges_ap->Extract(debug_aranges_data); } // Make a list of all CUs represented by the arange data in the file. std::set cus_with_data; for (size_t n = 0; n < m_cu_aranges_ap.get()->GetNumRanges(); n++) { dw_offset_t offset = m_cu_aranges_ap.get()->OffsetAtIndex(n); if (offset != DW_INVALID_OFFSET) cus_with_data.insert(offset); } // Manually build arange data for everything that wasn't in the // .debug_aranges table. bool printed = false; const size_t num_compile_units = GetNumCompileUnits(); for (size_t idx = 0; idx < num_compile_units; ++idx) { DWARFUnit *cu = GetCompileUnitAtIndex(idx); dw_offset_t offset = cu->GetOffset(); if (cus_with_data.find(offset) == cus_with_data.end()) { if (log) { if (!printed) log->Printf( "DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing", m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str()); printed = true; } cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_ap.get()); } } const bool minimize = true; m_cu_aranges_ap->Sort(minimize); } return *m_cu_aranges_ap.get(); } void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { if (m_compile_units.empty()) { if (m_dwarf2Data != NULL) { lldb::offset_t offset = 0; DWARFUnitSP cu_sp; const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, debug_info_data, &offset))) { m_compile_units.push_back(cu_sp); offset = cu_sp->GetNextCompileUnitOffset(); } } } } size_t DWARFDebugInfo::GetNumCompileUnits() { ParseCompileUnitHeadersIfNeeded(); return m_compile_units.size(); } DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { DWARFUnit *cu = NULL; if (idx < GetNumCompileUnits()) cu = m_compile_units[idx].get(); return cu; } bool DWARFDebugInfo::ContainsCompileUnit(const DWARFUnit *cu) const { // Not a verify efficient function, but it is handy for use in assertions to // make sure that a compile unit comes from a debug information file. CompileUnitColl::const_iterator end_pos = m_compile_units.end(); CompileUnitColl::const_iterator pos; for (pos = m_compile_units.begin(); pos != end_pos; ++pos) { if (pos->get() == cu) return true; } return false; } bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( dw_offset_t offset, const DWARFUnitSP &cu_sp) { return offset < cu_sp->GetOffset(); } DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr) { DWARFUnitSP cu_sp; uint32_t cu_idx = DW_INVALID_INDEX; if (cu_offset != DW_INVALID_OFFSET) { ParseCompileUnitHeadersIfNeeded(); // Watch out for single compile unit executable as they are pretty common const size_t num_cus = m_compile_units.size(); if (num_cus == 1) { if (m_compile_units[0]->GetOffset() == cu_offset) { cu_sp = m_compile_units[0]; cu_idx = 0; } } else if (num_cus) { CompileUnitColl::const_iterator end_pos = m_compile_units.end(); CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); CompileUnitColl::const_iterator pos = std::upper_bound( begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset); if (pos != begin_pos) { --pos; if ((*pos)->GetOffset() == cu_offset) { cu_sp = *pos; cu_idx = std::distance(begin_pos, pos); } } } } if (idx_ptr) *idx_ptr = cu_idx; return cu_sp.get(); } DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { if (die_ref.cu_offset == DW_INVALID_OFFSET) return GetCompileUnitContainingDIEOffset(die_ref.die_offset); else return GetCompileUnit(die_ref.cu_offset); } DWARFUnit * DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { ParseCompileUnitHeadersIfNeeded(); DWARFUnitSP cu_sp; // Watch out for single compile unit executable as they are pretty common const size_t num_cus = m_compile_units.size(); if (num_cus == 1) { if (m_compile_units[0]->ContainsDIEOffset(die_offset)) return m_compile_units[0].get(); } else if (num_cus) { CompileUnitColl::const_iterator end_pos = m_compile_units.end(); CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); CompileUnitColl::const_iterator pos = std::upper_bound( begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset); if (pos != begin_pos) { --pos; if ((*pos)->ContainsDIEOffset(die_offset)) return (*pos).get(); } } return nullptr; } DWARFDIE DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); if (cu) return cu->GetDIE(die_offset); return DWARFDIE(); } //---------------------------------------------------------------------- // GetDIE() // // Get the DIE (Debug Information Entry) with the specified offset. //---------------------------------------------------------------------- DWARFDIE DWARFDebugInfo::GetDIE(const DIERef &die_ref) { DWARFUnit *cu = GetCompileUnit(die_ref); if (cu) return cu->GetDIE(die_ref.die_offset); return DWARFDIE(); // Not found }