1 //===-- DebugNamesDWARFIndex.cpp ------------------------------------------===// 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 "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h" 10 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" 11 #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" 12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" 13 #include "lldb/Utility/RegularExpression.h" 14 #include "lldb/Utility/Stream.h" 15 16 using namespace lldb_private; 17 using namespace lldb; 18 19 llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> 20 DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, 21 DWARFDataExtractor debug_str, 22 SymbolFileDWARF &dwarf) { 23 auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVM(), 24 debug_str.GetAsLLVM()); 25 if (llvm::Error E = index_up->extract()) 26 return std::move(E); 27 28 return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( 29 module, std::move(index_up), debug_names, debug_str, dwarf)); 30 } 31 32 llvm::DenseSet<dw_offset_t> 33 DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { 34 llvm::DenseSet<dw_offset_t> result; 35 for (const DebugNames::NameIndex &ni : debug_names) { 36 for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu) 37 result.insert(ni.getCUOffset(cu)); 38 } 39 return result; 40 } 41 42 llvm::Optional<DIERef> 43 DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { 44 llvm::Optional<uint64_t> cu_offset = entry.getCUOffset(); 45 if (!cu_offset) 46 return llvm::None; 47 48 DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); 49 if (!cu) 50 return llvm::None; 51 52 cu = &cu->GetNonSkeletonUnit(); 53 if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset()) 54 return DIERef(cu->GetSymbolFileDWARF().GetDwoNum(), 55 DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset); 56 57 return llvm::None; 58 } 59 60 void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, 61 DIEArray &offsets) { 62 if (llvm::Optional<DIERef> ref = ToDIERef(entry)) 63 offsets.push_back(*ref); 64 } 65 66 void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, 67 const DebugNames::NameIndex &ni, 68 llvm::StringRef name) { 69 // Ignore SentinelErrors, log everything else. 70 LLDB_LOG_ERROR( 71 LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS), 72 handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}), 73 "Failed to parse index entries for index at {1:x}, name {2}: {0}", 74 ni.getUnitOffset(), name); 75 } 76 77 void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename, 78 DIEArray &offsets) { 79 m_fallback.GetGlobalVariables(basename, offsets); 80 81 for (const DebugNames::Entry &entry : 82 m_debug_names_up->equal_range(basename.GetStringRef())) { 83 if (entry.tag() != DW_TAG_variable) 84 continue; 85 86 Append(entry, offsets); 87 } 88 } 89 90 void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, 91 DIEArray &offsets) { 92 m_fallback.GetGlobalVariables(regex, offsets); 93 94 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 95 for (DebugNames::NameTableEntry nte: ni) { 96 if (!regex.Execute(nte.getString())) 97 continue; 98 99 uint64_t entry_offset = nte.getEntryOffset(); 100 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 101 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 102 if (entry_or->tag() != DW_TAG_variable) 103 continue; 104 105 Append(*entry_or, offsets); 106 } 107 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 108 } 109 } 110 } 111 112 void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, 113 DIEArray &offsets) { 114 m_fallback.GetGlobalVariables(cu, offsets); 115 116 uint64_t cu_offset = cu.GetOffset(); 117 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 118 for (DebugNames::NameTableEntry nte: ni) { 119 uint64_t entry_offset = nte.getEntryOffset(); 120 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 121 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 122 if (entry_or->tag() != DW_TAG_variable) 123 continue; 124 if (entry_or->getCUOffset() != cu_offset) 125 continue; 126 127 Append(*entry_or, offsets); 128 } 129 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 130 } 131 } 132 } 133 134 void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name, 135 bool must_be_implementation, 136 DIEArray &offsets) { 137 m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets); 138 139 // Keep a list of incomplete types as fallback for when we don't find the 140 // complete type. 141 DIEArray incomplete_types; 142 143 for (const DebugNames::Entry &entry : 144 m_debug_names_up->equal_range(class_name.GetStringRef())) { 145 if (entry.tag() != DW_TAG_structure_type && 146 entry.tag() != DW_TAG_class_type) 147 continue; 148 149 llvm::Optional<DIERef> ref = ToDIERef(entry); 150 if (!ref) 151 continue; 152 153 DWARFUnit *cu = m_debug_info.GetUnit(*ref); 154 if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { 155 incomplete_types.push_back(*ref); 156 continue; 157 } 158 159 // FIXME: We should return DWARFDIEs so we don't have to resolve it twice. 160 DWARFDIE die = m_debug_info.GetDIE(*ref); 161 if (!die) 162 continue; 163 164 if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) { 165 // If we find the complete version we're done. 166 offsets.push_back(*ref); 167 return; 168 } else { 169 incomplete_types.push_back(*ref); 170 } 171 } 172 173 offsets.insert(offsets.end(), incomplete_types.begin(), 174 incomplete_types.end()); 175 } 176 177 void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { 178 m_fallback.GetTypes(name, offsets); 179 180 for (const DebugNames::Entry &entry : 181 m_debug_names_up->equal_range(name.GetStringRef())) { 182 if (isType(entry.tag())) 183 Append(entry, offsets); 184 } 185 } 186 187 void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context, 188 DIEArray &offsets) { 189 m_fallback.GetTypes(context, offsets); 190 191 for (const DebugNames::Entry &entry : 192 m_debug_names_up->equal_range(context[0].name)) { 193 if (entry.tag() == context[0].tag) 194 Append(entry, offsets); 195 } 196 } 197 198 void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { 199 m_fallback.GetNamespaces(name, offsets); 200 201 for (const DebugNames::Entry &entry : 202 m_debug_names_up->equal_range(name.GetStringRef())) { 203 if (entry.tag() == DW_TAG_namespace) 204 Append(entry, offsets); 205 } 206 } 207 208 void DebugNamesDWARFIndex::GetFunctions( 209 ConstString name, SymbolFileDWARF &dwarf, 210 const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, 211 std::vector<DWARFDIE> &dies) { 212 213 std::vector<DWARFDIE> v; 214 m_fallback.GetFunctions(name, dwarf, parent_decl_ctx, name_type_mask, v); 215 216 for (const DebugNames::Entry &entry : 217 m_debug_names_up->equal_range(name.GetStringRef())) { 218 Tag tag = entry.tag(); 219 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) 220 continue; 221 222 if (llvm::Optional<DIERef> ref = ToDIERef(entry)) 223 ProcessFunctionDIE(name.GetStringRef(), *ref, dwarf, parent_decl_ctx, 224 name_type_mask, v); 225 } 226 227 std::set<DWARFDebugInfoEntry *> seen; 228 for (DWARFDIE die : v) 229 if (seen.insert(die.GetDIE()).second) 230 dies.push_back(die); 231 } 232 233 void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, 234 DIEArray &offsets) { 235 m_fallback.GetFunctions(regex, offsets); 236 237 for (const DebugNames::NameIndex &ni: *m_debug_names_up) { 238 for (DebugNames::NameTableEntry nte: ni) { 239 if (!regex.Execute(nte.getString())) 240 continue; 241 242 uint64_t entry_offset = nte.getEntryOffset(); 243 llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); 244 for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { 245 Tag tag = entry_or->tag(); 246 if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) 247 continue; 248 249 Append(*entry_or, offsets); 250 } 251 MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); 252 } 253 } 254 } 255 256 void DebugNamesDWARFIndex::Dump(Stream &s) { 257 m_fallback.Dump(s); 258 259 std::string data; 260 llvm::raw_string_ostream os(data); 261 m_debug_names_up->dump(os); 262 s.PutCString(os.str()); 263 } 264