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