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