1 //===-- DWARFDebugInfo.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SymbolFileDWARF.h" 10 11 #include <algorithm> 12 #include <set> 13 14 #include "lldb/Host/PosixApi.h" 15 #include "lldb/Symbol/ObjectFile.h" 16 #include "lldb/Utility/RegularExpression.h" 17 #include "lldb/Utility/Stream.h" 18 #include "llvm/Support/Casting.h" 19 20 #include "DWARFCompileUnit.h" 21 #include "DWARFContext.h" 22 #include "DWARFDebugAranges.h" 23 #include "DWARFDebugInfo.h" 24 #include "DWARFDebugInfoEntry.h" 25 #include "DWARFFormValue.h" 26 #include "DWARFTypeUnit.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 // Constructor 32 DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, 33 lldb_private::DWARFContext &context) 34 : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {} 35 36 const DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { 37 if (m_cu_aranges_up) 38 return *m_cu_aranges_up; 39 40 m_cu_aranges_up = std::make_unique<DWARFDebugAranges>(); 41 const DWARFDataExtractor &debug_aranges_data = 42 m_context.getOrLoadArangesData(); 43 44 // Extract what we can from the .debug_aranges first. 45 m_cu_aranges_up->extract(debug_aranges_data); 46 47 // Make a list of all CUs represented by the .debug_aranges data. 48 std::set<dw_offset_t> cus_with_data; 49 for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) { 50 dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n); 51 if (offset != DW_INVALID_OFFSET) 52 cus_with_data.insert(offset); 53 } 54 55 // Manually build arange data for everything that wasn't in .debug_aranges. 56 const size_t num_units = GetNumUnits(); 57 for (size_t idx = 0; idx < num_units; ++idx) { 58 DWARFUnit *cu = GetUnitAtIndex(idx); 59 60 dw_offset_t offset = cu->GetOffset(); 61 if (cus_with_data.find(offset) == cus_with_data.end()) 62 cu->BuildAddressRangeTable(m_cu_aranges_up.get()); 63 } 64 65 const bool minimize = true; 66 m_cu_aranges_up->Sort(minimize); 67 return *m_cu_aranges_up; 68 } 69 70 void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { 71 DWARFDataExtractor data = section == DIERef::Section::DebugTypes 72 ? m_context.getOrLoadDebugTypesData() 73 : m_context.getOrLoadDebugInfoData(); 74 lldb::offset_t offset = 0; 75 while (data.ValidOffset(offset)) { 76 llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract( 77 m_dwarf, m_units.size(), data, section, &offset); 78 79 if (!unit_sp) { 80 // FIXME: Propagate this error up. 81 llvm::consumeError(unit_sp.takeError()); 82 return; 83 } 84 85 // If it didn't return an error, then it should be returning a valid Unit. 86 assert(*unit_sp); 87 m_units.push_back(*unit_sp); 88 offset = (*unit_sp)->GetNextUnitOffset(); 89 90 if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) { 91 m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(), 92 unit_sp.get()->GetID()); 93 } 94 } 95 } 96 97 void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { 98 llvm::call_once(m_units_once_flag, [&] { 99 ParseUnitsFor(DIERef::Section::DebugInfo); 100 ParseUnitsFor(DIERef::Section::DebugTypes); 101 llvm::sort(m_type_hash_to_unit_index, llvm::less_first()); 102 }); 103 } 104 105 size_t DWARFDebugInfo::GetNumUnits() { 106 ParseUnitHeadersIfNeeded(); 107 return m_units.size(); 108 } 109 110 DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) { 111 DWARFUnit *cu = nullptr; 112 if (idx < GetNumUnits()) 113 cu = m_units[idx].get(); 114 return cu; 115 } 116 117 uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section, 118 dw_offset_t offset) { 119 ParseUnitHeadersIfNeeded(); 120 121 // llvm::lower_bound is not used as for DIE offsets it would still return 122 // index +1 and GetOffset() returning index itself would be a special case. 123 auto pos = llvm::upper_bound( 124 m_units, std::make_pair(section, offset), 125 [](const std::pair<DIERef::Section, dw_offset_t> &lhs, 126 const DWARFUnitSP &rhs) { 127 return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset()); 128 }); 129 uint32_t idx = std::distance(m_units.begin(), pos); 130 if (idx == 0) 131 return DW_INVALID_OFFSET; 132 return idx - 1; 133 } 134 135 DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, 136 dw_offset_t cu_offset, 137 uint32_t *idx_ptr) { 138 uint32_t idx = FindUnitIndex(section, cu_offset); 139 DWARFUnit *result = GetUnitAtIndex(idx); 140 if (result && result->GetOffset() != cu_offset) { 141 result = nullptr; 142 idx = DW_INVALID_INDEX; 143 } 144 if (idx_ptr) 145 *idx_ptr = idx; 146 return result; 147 } 148 149 DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { 150 return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset()); 151 } 152 153 DWARFUnit * 154 DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, 155 dw_offset_t die_offset) { 156 uint32_t idx = FindUnitIndex(section, die_offset); 157 DWARFUnit *result = GetUnitAtIndex(idx); 158 if (result && !result->ContainsDIEOffset(die_offset)) 159 return nullptr; 160 return result; 161 } 162 163 DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { 164 auto pos = llvm::lower_bound(m_type_hash_to_unit_index, 165 std::make_pair(hash, 0u), llvm::less_first()); 166 if (pos == m_type_hash_to_unit_index.end() || pos->first != hash) 167 return nullptr; 168 return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second)); 169 } 170 171 bool DWARFDebugInfo::ContainsTypeUnits() { 172 ParseUnitHeadersIfNeeded(); 173 return !m_type_hash_to_unit_index.empty(); 174 } 175 176 // GetDIE() 177 // 178 // Get the DIE (Debug Information Entry) with the specified offset. 179 DWARFDIE 180 DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 181 DWARFUnit *cu = GetUnit(die_ref); 182 if (cu) 183 return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); 184 return DWARFDIE(); // Not found 185 } 186