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