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