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