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