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 using namespace lldb_private::plugin::dwarf; 31 32 // Constructor 33 DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, 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 // The .debug_aranges accelerator is not guaranteed to be complete. 57 // Tools such as dsymutil can provide stronger guarantees than required by the 58 // standard. Without that guarantee, we have to iterate over every CU in the 59 // .debug_info and make sure there's a corresponding entry in the table and if 60 // not, add one for every subprogram. 61 ObjectFile *OF = m_dwarf.GetObjectFile(); 62 if (!OF || !OF->CanTrustAddressRanges()) { 63 const size_t num_units = GetNumUnits(); 64 for (size_t idx = 0; idx < num_units; ++idx) { 65 DWARFUnit *cu = GetUnitAtIndex(idx); 66 67 dw_offset_t offset = cu->GetOffset(); 68 if (cus_with_data.find(offset) == cus_with_data.end()) 69 cu->BuildAddressRangeTable(m_cu_aranges_up.get()); 70 } 71 } 72 73 const bool minimize = true; 74 m_cu_aranges_up->Sort(minimize); 75 return *m_cu_aranges_up; 76 } 77 78 void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { 79 DWARFDataExtractor data = section == DIERef::Section::DebugTypes 80 ? m_context.getOrLoadDebugTypesData() 81 : m_context.getOrLoadDebugInfoData(); 82 lldb::offset_t offset = 0; 83 while (data.ValidOffset(offset)) { 84 llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract( 85 m_dwarf, m_units.size(), data, section, &offset); 86 87 if (!unit_sp) { 88 // FIXME: Propagate this error up. 89 llvm::consumeError(unit_sp.takeError()); 90 return; 91 } 92 93 // If it didn't return an error, then it should be returning a valid Unit. 94 assert(*unit_sp); 95 m_units.push_back(*unit_sp); 96 offset = (*unit_sp)->GetNextUnitOffset(); 97 98 if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) { 99 m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(), 100 unit_sp.get()->GetID()); 101 } 102 } 103 } 104 105 void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { 106 llvm::call_once(m_units_once_flag, [&] { 107 ParseUnitsFor(DIERef::Section::DebugInfo); 108 ParseUnitsFor(DIERef::Section::DebugTypes); 109 llvm::sort(m_type_hash_to_unit_index, llvm::less_first()); 110 }); 111 } 112 113 size_t DWARFDebugInfo::GetNumUnits() { 114 ParseUnitHeadersIfNeeded(); 115 return m_units.size(); 116 } 117 118 DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(size_t idx) { 119 DWARFUnit *cu = nullptr; 120 if (idx < GetNumUnits()) 121 cu = m_units[idx].get(); 122 return cu; 123 } 124 125 uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section, 126 dw_offset_t offset) { 127 ParseUnitHeadersIfNeeded(); 128 129 // llvm::lower_bound is not used as for DIE offsets it would still return 130 // index +1 and GetOffset() returning index itself would be a special case. 131 auto pos = llvm::upper_bound( 132 m_units, std::make_pair(section, offset), 133 [](const std::pair<DIERef::Section, dw_offset_t> &lhs, 134 const DWARFUnitSP &rhs) { 135 return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset()); 136 }); 137 uint32_t idx = std::distance(m_units.begin(), pos); 138 if (idx == 0) 139 return DW_INVALID_INDEX; 140 return idx - 1; 141 } 142 143 DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, 144 dw_offset_t cu_offset, 145 uint32_t *idx_ptr) { 146 uint32_t idx = FindUnitIndex(section, cu_offset); 147 DWARFUnit *result = GetUnitAtIndex(idx); 148 if (result && result->GetOffset() != cu_offset) { 149 result = nullptr; 150 idx = DW_INVALID_INDEX; 151 } 152 if (idx_ptr) 153 *idx_ptr = idx; 154 return result; 155 } 156 157 DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { 158 return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset()); 159 } 160 161 DWARFUnit * 162 DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, 163 dw_offset_t die_offset) { 164 uint32_t idx = FindUnitIndex(section, die_offset); 165 DWARFUnit *result = GetUnitAtIndex(idx); 166 if (result && !result->ContainsDIEOffset(die_offset)) 167 return nullptr; 168 return result; 169 } 170 171 DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { 172 auto pos = llvm::lower_bound(m_type_hash_to_unit_index, 173 std::make_pair(hash, 0u), llvm::less_first()); 174 if (pos == m_type_hash_to_unit_index.end() || pos->first != hash) 175 return nullptr; 176 return llvm::cast<DWARFTypeUnit>(GetUnitAtIndex(pos->second)); 177 } 178 179 bool DWARFDebugInfo::ContainsTypeUnits() { 180 ParseUnitHeadersIfNeeded(); 181 return !m_type_hash_to_unit_index.empty(); 182 } 183 184 // GetDIE() 185 // 186 // Get the DIE (Debug Information Entry) with the specified offset. 187 DWARFDIE 188 DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 189 DWARFUnit *cu = GetUnit(die_ref); 190 if (cu) 191 return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); 192 return DWARFDIE(); // Not found 193 } 194 195 llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) { 196 if (DWARFUnit *cu = GetUnit(die_ref)) 197 return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset()); 198 return llvm::StringRef(); 199 } 200