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