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 26 using namespace lldb; 27 using namespace lldb_private; 28 using namespace std; 29 30 // Constructor 31 DWARFDebugInfo::DWARFDebugInfo(lldb_private::DWARFContext &context) 32 : m_dwarf2Data(NULL), m_context(context), m_compile_units(), 33 m_cu_aranges_up() {} 34 35 // SetDwarfData 36 void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) { 37 m_dwarf2Data = dwarf2Data; 38 m_compile_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 (debug_aranges_data) { 51 llvm::Error error = m_cu_aranges_up->extract(*debug_aranges_data); 52 if (error) 53 return std::move(error); 54 } 55 56 // Make a list of all CUs represented by the arange data in the file. 57 std::set<dw_offset_t> cus_with_data; 58 for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) { 59 dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n); 60 if (offset != DW_INVALID_OFFSET) 61 cus_with_data.insert(offset); 62 } 63 64 // Manually build arange data for everything that wasn't in the 65 // .debug_aranges table. 66 const size_t num_compile_units = GetNumCompileUnits(); 67 for (size_t idx = 0; idx < num_compile_units; ++idx) { 68 DWARFUnit *cu = GetCompileUnitAtIndex(idx); 69 70 dw_offset_t offset = cu->GetOffset(); 71 if (cus_with_data.find(offset) == cus_with_data.end()) 72 cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_up.get()); 73 } 74 75 const bool minimize = true; 76 m_cu_aranges_up->Sort(minimize); 77 return *m_cu_aranges_up; 78 } 79 80 void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { 81 if (!m_compile_units.empty()) 82 return; 83 if (!m_dwarf2Data) 84 return; 85 86 lldb::offset_t offset = 0; 87 const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); 88 89 while (debug_info_data.ValidOffset(offset)) { 90 llvm::Expected<DWARFUnitSP> cu_sp = 91 DWARFCompileUnit::extract(m_dwarf2Data, debug_info_data, &offset); 92 93 if (!cu_sp) { 94 // FIXME: Propagate this error up. 95 llvm::consumeError(cu_sp.takeError()); 96 return; 97 } 98 99 // If it didn't return an error, then it should be returning a valid 100 // CompileUnit. 101 assert(*cu_sp); 102 103 m_compile_units.push_back(*cu_sp); 104 105 offset = (*cu_sp)->GetNextCompileUnitOffset(); 106 } 107 } 108 109 size_t DWARFDebugInfo::GetNumCompileUnits() { 110 ParseCompileUnitHeadersIfNeeded(); 111 return m_compile_units.size(); 112 } 113 114 DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { 115 DWARFUnit *cu = NULL; 116 if (idx < GetNumCompileUnits()) 117 cu = m_compile_units[idx].get(); 118 return cu; 119 } 120 121 bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( 122 dw_offset_t offset, const DWARFUnitSP &cu_sp) { 123 return offset < cu_sp->GetOffset(); 124 } 125 126 DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, 127 uint32_t *idx_ptr) { 128 DWARFUnitSP cu_sp; 129 uint32_t cu_idx = DW_INVALID_INDEX; 130 if (cu_offset != DW_INVALID_OFFSET) { 131 ParseCompileUnitHeadersIfNeeded(); 132 133 // Watch out for single compile unit executable as they are pretty common 134 const size_t num_cus = m_compile_units.size(); 135 if (num_cus == 1) { 136 if (m_compile_units[0]->GetOffset() == cu_offset) { 137 cu_sp = m_compile_units[0]; 138 cu_idx = 0; 139 } 140 } else if (num_cus) { 141 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 142 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 143 CompileUnitColl::const_iterator pos = std::upper_bound( 144 begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset); 145 if (pos != begin_pos) { 146 --pos; 147 if ((*pos)->GetOffset() == cu_offset) { 148 cu_sp = *pos; 149 cu_idx = std::distance(begin_pos, pos); 150 } 151 } 152 } 153 } 154 if (idx_ptr) 155 *idx_ptr = cu_idx; 156 return cu_sp.get(); 157 } 158 159 DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { 160 if (die_ref.cu_offset == DW_INVALID_OFFSET) 161 return GetCompileUnitContainingDIEOffset(die_ref.die_offset); 162 else 163 return GetCompileUnit(die_ref.cu_offset); 164 } 165 166 DWARFUnit * 167 DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { 168 ParseCompileUnitHeadersIfNeeded(); 169 170 DWARFUnitSP cu_sp; 171 172 // Watch out for single compile unit executable as they are pretty common 173 const size_t num_cus = m_compile_units.size(); 174 if (num_cus == 1) { 175 if (m_compile_units[0]->ContainsDIEOffset(die_offset)) 176 return m_compile_units[0].get(); 177 } else if (num_cus) { 178 CompileUnitColl::const_iterator end_pos = m_compile_units.end(); 179 CompileUnitColl::const_iterator begin_pos = m_compile_units.begin(); 180 CompileUnitColl::const_iterator pos = std::upper_bound( 181 begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset); 182 if (pos != begin_pos) { 183 --pos; 184 if ((*pos)->ContainsDIEOffset(die_offset)) 185 return (*pos).get(); 186 } 187 } 188 189 return nullptr; 190 } 191 192 DWARFDIE 193 DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { 194 DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); 195 if (cu) 196 return cu->GetDIE(die_offset); 197 return DWARFDIE(); 198 } 199 200 // GetDIE() 201 // 202 // Get the DIE (Debug Information Entry) with the specified offset. 203 DWARFDIE 204 DWARFDebugInfo::GetDIE(const DIERef &die_ref) { 205 DWARFUnit *cu = GetCompileUnit(die_ref); 206 if (cu) 207 return cu->GetDIE(die_ref.die_offset); 208 return DWARFDIE(); // Not found 209 } 210 211