1 //===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===// 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 19 #include "DWARFCompileUnit.h" 20 #include "DWARFContext.h" 21 #include "DWARFDebugAranges.h" 22 #include "DWARFDebugInfo.h" 23 #include "DWARFDebugInfoEntry.h" 24 #include "DWARFFormValue.h" 25 #include "DWARFTypeUnit.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 using namespace std; 30 31 // Constructor 32 DWARFDebugInfo::DWARFDebugInfo(lldb_private::DWARFContext &context) 33 : m_dwarf2Data(NULL), m_context(context), m_units(), m_cu_aranges_up() {} 34 35 // SetDwarfData 36 void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) { 37 m_dwarf2Data = dwarf2Data; 38 m_units.clear(); 39 } 40 41 llvm::Expected<DWARFDebugAranges &> DWARFDebugInfo::GetCompileUnitAranges() { 42 if (m_cu_aranges_up) 43 return *m_cu_aranges_up; 44 45 assert(m_dwarf2Data); 46 47 m_cu_aranges_up = llvm::make_unique<DWARFDebugAranges>(); 48 const DWARFDataExtractor &debug_aranges_data = 49 m_context.getOrLoadArangesData(); 50 if (llvm::Error error = m_cu_aranges_up->extract(debug_aranges_data)) 51 return std::move(error); 52 53 // Make a list of all CUs represented by the arange data in the file. 54 std::set<dw_offset_t> cus_with_data; 55 for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) { 56 dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n); 57 if (offset != DW_INVALID_OFFSET) 58 cus_with_data.insert(offset); 59 } 60 61 // Manually build arange data for everything that wasn't in the 62 // .debug_aranges table. 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 const bool minimize = true; 73 m_cu_aranges_up->Sort(minimize); 74 return *m_cu_aranges_up; 75 } 76 77 void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data, 78 DIERef::Section section, std::vector<DWARFUnitSP> &units) { 79 lldb::offset_t offset = 0; 80 while (data.ValidOffset(offset)) { 81 llvm::Expected<DWARFUnitSP> unit_sp = 82 DWARFUnit::extract(dwarf, units.size(), data, section, &offset); 83 84 if (!unit_sp) { 85 // FIXME: Propagate this error up. 86 llvm::consumeError(unit_sp.takeError()); 87 return; 88 } 89 90 // If it didn't return an error, then it should be returning a valid Unit. 91 assert(*unit_sp); 92 93 units.push_back(*unit_sp); 94 95 offset = (*unit_sp)->GetNextUnitOffset(); 96 } 97 } 98 99 void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { 100 if (!m_units.empty()) 101 return; 102 if (!m_dwarf2Data) 103 return; 104 105 Parse(m_dwarf2Data, m_context.getOrLoadDebugInfoData(), 106 DIERef::Section::DebugInfo, m_units); 107 Parse(m_dwarf2Data, m_context.getOrLoadDebugTypesData(), 108 DIERef::Section::DebugTypes, m_units); 109 } 110 111 size_t DWARFDebugInfo::GetNumUnits() { 112 ParseUnitHeadersIfNeeded(); 113 return m_units.size(); 114 } 115 116 DWARFUnit *DWARFDebugInfo::GetUnitAtIndex(user_id_t idx) { 117 DWARFUnit *cu = NULL; 118 if (idx < GetNumUnits()) 119 cu = m_units[idx].get(); 120 return cu; 121 } 122 123 uint32_t DWARFDebugInfo::FindUnitIndex(DIERef::Section section, 124 dw_offset_t offset) { 125 ParseUnitHeadersIfNeeded(); 126 127 // llvm::lower_bound is not used as for DIE offsets it would still return 128 // index +1 and GetOffset() returning index itself would be a special case. 129 auto pos = llvm::upper_bound( 130 m_units, std::make_pair(section, offset), 131 [](const std::pair<DIERef::Section, dw_offset_t> &lhs, 132 const DWARFUnitSP &rhs) { 133 return lhs < std::make_pair(rhs->GetDebugSection(), rhs->GetOffset()); 134 }); 135 uint32_t idx = std::distance(m_units.begin(), pos); 136 if (idx == 0) 137 return DW_INVALID_OFFSET; 138 return idx - 1; 139 } 140 141 DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, 142 dw_offset_t cu_offset, 143 uint32_t *idx_ptr) { 144 uint32_t idx = FindUnitIndex(section, cu_offset); 145 DWARFUnit *result = GetUnitAtIndex(idx); 146 if (result && result->GetOffset() != cu_offset) { 147 result = nullptr; 148 idx = DW_INVALID_INDEX; 149 } 150 if (idx_ptr) 151 *idx_ptr = idx; 152 return result; 153 } 154 155 DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { 156 if (die_ref.cu_offset == DW_INVALID_OFFSET) 157 return GetUnitContainingDIEOffset(die_ref.section, die_ref.die_offset); 158 else 159 return GetUnitAtOffset(die_ref.section, die_ref.cu_offset); 160 } 161 162 DWARFUnit * 163 DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, 164 dw_offset_t die_offset) { 165 uint32_t idx = FindUnitIndex(section, die_offset); 166 DWARFUnit *result = GetUnitAtIndex(idx); 167 if (result && !result->ContainsDIEOffset(die_offset)) 168 return nullptr; 169 return result; 170 } 171 172 DWARFDIE 173 DWARFDebugInfo::GetDIEForDIEOffset(DIERef::Section section, 174 dw_offset_t die_offset) { 175 DWARFUnit *cu = GetUnitContainingDIEOffset(section, die_offset); 176 if (cu) 177 return cu->GetDIE(die_offset); 178 return DWARFDIE(); 179 } 180 181 // GetDIE() 182 // 183 // Get the DIE (Debug Information Entry) with the specified offset. 184 DWARFDIE 185 DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 186 DWARFUnit *cu = GetUnit(die_ref); 187 if (cu) 188 return cu->GetDIE(die_ref.die_offset); 189 return DWARFDIE(); // Not found 190 } 191 192