| //===-- 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 <algorithm> |
| #include <set> |
| |
| #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<dw_offset_t> 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 |
| } |
| |