|
| 1 | +//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// The LLVM Compiler Infrastructure |
| 4 | +// |
| 5 | +// This file is distributed under the University of Illinois Open Source |
| 6 | +// License. See LICENSE.TXT for details. |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | + |
| 10 | +#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h" |
| 11 | +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" |
| 12 | +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" |
| 13 | +#include "Plugins/SymbolFile/DWARF/DWARFUnit.h" |
| 14 | +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" |
| 15 | + |
| 16 | +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" |
| 17 | +#include "Plugins/Language/ObjC/ObjCLanguage.h" |
| 18 | +#include "lldb/Core/Module.h" |
| 19 | +#include "lldb/Symbol/Function.h" |
| 20 | + |
| 21 | +using namespace lldb_private; |
| 22 | +using namespace lldb; |
| 23 | + |
| 24 | +std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( |
| 25 | + Module &module, DWARFDataExtractor apple_names, |
| 26 | + DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, |
| 27 | + DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) { |
| 28 | + auto apple_names_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( |
| 29 | + apple_names, debug_str, ".apple_names"); |
| 30 | + if (!apple_names_table_up->IsValid()) |
| 31 | + apple_names_table_up.reset(); |
| 32 | + |
| 33 | + auto apple_namespaces_table_up = |
| 34 | + llvm::make_unique<DWARFMappedHash::MemoryTable>( |
| 35 | + apple_namespaces, debug_str, ".apple_namespaces"); |
| 36 | + if (!apple_namespaces_table_up->IsValid()) |
| 37 | + apple_namespaces_table_up.reset(); |
| 38 | + |
| 39 | + auto apple_types_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( |
| 40 | + apple_types, debug_str, ".apple_types"); |
| 41 | + if (!apple_types_table_up->IsValid()) |
| 42 | + apple_types_table_up.reset(); |
| 43 | + |
| 44 | + auto apple_objc_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( |
| 45 | + apple_objc, debug_str, ".apple_objc"); |
| 46 | + if (!apple_objc_table_up->IsValid()) |
| 47 | + apple_objc_table_up.reset(); |
| 48 | + |
| 49 | + if (apple_names_table_up || apple_names_table_up || apple_types_table_up || |
| 50 | + apple_objc_table_up) |
| 51 | + return llvm::make_unique<AppleDWARFIndex>( |
| 52 | + module, std::move(apple_names_table_up), |
| 53 | + std::move(apple_namespaces_table_up), std::move(apple_types_table_up), |
| 54 | + std::move(apple_objc_table_up)); |
| 55 | + |
| 56 | + return nullptr; |
| 57 | +} |
| 58 | + |
| 59 | +void AppleDWARFIndex::GetGlobalVariables(ConstString name, DIEArray &offsets) { |
| 60 | + if (!m_apple_names_up) |
| 61 | + return; |
| 62 | + |
| 63 | + const char *name_cstr = name.GetCString(); |
| 64 | + llvm::StringRef basename; |
| 65 | + llvm::StringRef context; |
| 66 | + |
| 67 | + if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, |
| 68 | + basename)) |
| 69 | + basename = name_cstr; |
| 70 | + |
| 71 | + m_apple_names_up->FindByName(basename, offsets); |
| 72 | +} |
| 73 | + |
| 74 | +void AppleDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, |
| 75 | + DIEArray &offsets) { |
| 76 | + if (!m_apple_names_up) |
| 77 | + return; |
| 78 | + |
| 79 | + DWARFMappedHash::DIEInfoArray hash_data; |
| 80 | + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) |
| 81 | + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); |
| 82 | +} |
| 83 | + |
| 84 | +void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, |
| 85 | + DIEArray &offsets) { |
| 86 | + if (!m_apple_names_up) |
| 87 | + return; |
| 88 | + |
| 89 | + DWARFMappedHash::DIEInfoArray hash_data; |
| 90 | + if (m_apple_names_up->AppendAllDIEsInRange( |
| 91 | + cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data)) |
| 92 | + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); |
| 93 | +} |
| 94 | + |
| 95 | +void AppleDWARFIndex::GetObjCMethods(ConstString class_name, |
| 96 | + DIEArray &offsets) { |
| 97 | + if (m_apple_objc_up) |
| 98 | + m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets); |
| 99 | +} |
| 100 | + |
| 101 | +void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name, |
| 102 | + bool must_be_implementation, |
| 103 | + DIEArray &offsets) { |
| 104 | + if (m_apple_types_up) { |
| 105 | + m_apple_types_up->FindCompleteObjCClassByName( |
| 106 | + class_name.GetStringRef(), offsets, must_be_implementation); |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { |
| 111 | + if (m_apple_types_up) |
| 112 | + m_apple_types_up->FindByName(name.GetStringRef(), offsets); |
| 113 | +} |
| 114 | + |
| 115 | +void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, |
| 116 | + DIEArray &offsets) { |
| 117 | + if (!m_apple_types_up) |
| 118 | + return; |
| 119 | + |
| 120 | + Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | |
| 121 | + DWARF_LOG_LOOKUPS); |
| 122 | + const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom( |
| 123 | + DWARFMappedHash::eAtomTypeTag); |
| 124 | + const bool has_qualified_name_hash = |
| 125 | + m_apple_types_up->GetHeader().header_data.ContainsAtom( |
| 126 | + DWARFMappedHash::eAtomTypeQualNameHash); |
| 127 | + const ConstString type_name(context[0].name); |
| 128 | + const dw_tag_t tag = context[0].tag; |
| 129 | + if (has_tag && has_qualified_name_hash) { |
| 130 | + const char *qualified_name = context.GetQualifiedName(); |
| 131 | + const uint32_t qualified_name_hash = llvm::djbHash(qualified_name); |
| 132 | + if (log) |
| 133 | + m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); |
| 134 | + m_apple_types_up->FindByNameAndTagAndQualifiedNameHash( |
| 135 | + type_name.GetStringRef(), tag, qualified_name_hash, offsets); |
| 136 | + } else if (has_tag) { |
| 137 | + if (log) |
| 138 | + m_module.LogMessage(log, "FindByNameAndTag()"); |
| 139 | + m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets); |
| 140 | + } else |
| 141 | + m_apple_types_up->FindByName(type_name.GetStringRef(), offsets); |
| 142 | +} |
| 143 | + |
| 144 | +void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { |
| 145 | + if (m_apple_namespaces_up) |
| 146 | + m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); |
| 147 | +} |
| 148 | + |
| 149 | +void AppleDWARFIndex::GetFunctions( |
| 150 | + ConstString name, DWARFDebugInfo &info, |
| 151 | + llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines, |
| 152 | + lldb_private::SymbolContextList &sc_list)> |
| 153 | + resolve_function, |
| 154 | + llvm::function_ref<CompilerDeclContext(lldb::user_id_t type_uid)> |
| 155 | + get_decl_context_containing_uid, |
| 156 | + const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, |
| 157 | + bool include_inlines, SymbolContextList &sc_list) { |
| 158 | + if (!m_apple_names_up) |
| 159 | + return; |
| 160 | + |
| 161 | + std::set<const DWARFDebugInfoEntry *> resolved_dies; |
| 162 | + DIEArray offsets; |
| 163 | + |
| 164 | + uint32_t num_matches = 0; |
| 165 | + |
| 166 | + if (name_type_mask & eFunctionNameTypeFull) { |
| 167 | + // If they asked for the full name, match what they typed. At some |
| 168 | + // point we may want to canonicalize this (strip double spaces, etc. |
| 169 | + // For now, we just add all the dies that we find by exact match. |
| 170 | + num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); |
| 171 | + for (uint32_t i = 0; i < num_matches; i++) { |
| 172 | + const DIERef &die_ref = offsets[i]; |
| 173 | + DWARFDIE die = info.GetDIE(die_ref); |
| 174 | + if (die) { |
| 175 | + if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) |
| 176 | + continue; // The containing decl contexts don't match |
| 177 | + |
| 178 | + if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { |
| 179 | + if (resolve_function(die, include_inlines, sc_list)) |
| 180 | + resolved_dies.insert(die.GetDIE()); |
| 181 | + } |
| 182 | + } else |
| 183 | + ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); |
| 184 | + } |
| 185 | + } |
| 186 | + |
| 187 | + if (name_type_mask & eFunctionNameTypeSelector) { |
| 188 | + if (parent_decl_ctx && parent_decl_ctx->IsValid()) |
| 189 | + return; // no selectors in namespaces |
| 190 | + |
| 191 | + num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); |
| 192 | + // Now make sure these are actually ObjC methods. In this case we can |
| 193 | + // simply look up the name, and if it is an ObjC method name, we're |
| 194 | + // good. |
| 195 | + |
| 196 | + for (uint32_t i = 0; i < num_matches; i++) { |
| 197 | + const DIERef &die_ref = offsets[i]; |
| 198 | + DWARFDIE die = info.GetDIE(die_ref); |
| 199 | + if (die) { |
| 200 | + const char *die_name = die.GetName(); |
| 201 | + if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) { |
| 202 | + if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { |
| 203 | + if (resolve_function(die, include_inlines, sc_list)) |
| 204 | + resolved_dies.insert(die.GetDIE()); |
| 205 | + } |
| 206 | + } |
| 207 | + } else |
| 208 | + ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); |
| 209 | + } |
| 210 | + offsets.clear(); |
| 211 | + } |
| 212 | + |
| 213 | + if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) || |
| 214 | + name_type_mask & eFunctionNameTypeBase) { |
| 215 | + // The apple_names table stores just the "base name" of C++ methods in |
| 216 | + // the table. So we have to extract the base name, look that up, and |
| 217 | + // if there is any other information in the name we were passed in we |
| 218 | + // have to post-filter based on that. |
| 219 | + |
| 220 | + // FIXME: Arrange the logic above so that we don't calculate the base |
| 221 | + // name twice: |
| 222 | + num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets); |
| 223 | + |
| 224 | + for (uint32_t i = 0; i < num_matches; i++) { |
| 225 | + const DIERef &die_ref = offsets[i]; |
| 226 | + DWARFDIE die = info.GetDIE(die_ref); |
| 227 | + if (die) { |
| 228 | + if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die)) |
| 229 | + continue; // The containing decl contexts don't match |
| 230 | + |
| 231 | + // If we get to here, the die is good, and we should add it: |
| 232 | + if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() && |
| 233 | + resolve_function(die, include_inlines, sc_list)) { |
| 234 | + bool keep_die = true; |
| 235 | + if ((name_type_mask & |
| 236 | + (eFunctionNameTypeBase | eFunctionNameTypeMethod)) != |
| 237 | + (eFunctionNameTypeBase | eFunctionNameTypeMethod)) { |
| 238 | + // We are looking for either basenames or methods, so we need |
| 239 | + // to trim out the ones we won't want by looking at the type |
| 240 | + SymbolContext sc; |
| 241 | + if (sc_list.GetLastContext(sc)) { |
| 242 | + if (sc.block) { |
| 243 | + // We have an inlined function |
| 244 | + } else if (sc.function) { |
| 245 | + Type *type = sc.function->GetType(); |
| 246 | + |
| 247 | + if (type) { |
| 248 | + CompilerDeclContext decl_ctx = |
| 249 | + get_decl_context_containing_uid(type->GetID()); |
| 250 | + if (decl_ctx.IsStructUnionOrClass()) { |
| 251 | + if (name_type_mask & eFunctionNameTypeBase) { |
| 252 | + sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); |
| 253 | + keep_die = false; |
| 254 | + } |
| 255 | + } else { |
| 256 | + if (name_type_mask & eFunctionNameTypeMethod) { |
| 257 | + sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); |
| 258 | + keep_die = false; |
| 259 | + } |
| 260 | + } |
| 261 | + } else { |
| 262 | + m_module.ReportWarning( |
| 263 | + "function at die offset 0x%8.8x had no function type", |
| 264 | + die_ref.die_offset); |
| 265 | + } |
| 266 | + } |
| 267 | + } |
| 268 | + } |
| 269 | + if (keep_die) |
| 270 | + resolved_dies.insert(die.GetDIE()); |
| 271 | + } |
| 272 | + } else |
| 273 | + ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef()); |
| 274 | + } |
| 275 | + offsets.clear(); |
| 276 | + } |
| 277 | +} |
| 278 | + |
| 279 | +void AppleDWARFIndex::GetFunctions( |
| 280 | + const RegularExpression ®ex, DWARFDebugInfo &info, |
| 281 | + llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines, |
| 282 | + lldb_private::SymbolContextList &sc_list)> |
| 283 | + resolve_function, |
| 284 | + bool include_inlines, SymbolContextList &sc_list) { |
| 285 | + if (!m_apple_names_up) |
| 286 | + return; |
| 287 | + |
| 288 | + DIEArray offsets; |
| 289 | + DWARFMappedHash::DIEInfoArray hash_data; |
| 290 | + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) { |
| 291 | + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); |
| 292 | + ParseFunctions(offsets, info, resolve_function, include_inlines, sc_list); |
| 293 | + } |
| 294 | +} |
| 295 | + |
| 296 | +void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset, |
| 297 | + llvm::StringRef name) { |
| 298 | + m_module.ReportErrorIfModifyDetected( |
| 299 | + "the DWARF debug information has been modified (accelerator table had " |
| 300 | + "bad die 0x%8.8x for '%s')\n", |
| 301 | + offset, name.str().c_str()); |
| 302 | +} |
| 303 | + |
| 304 | +void AppleDWARFIndex::Dump(Stream &s) { |
| 305 | + // TODO: Implement dumping. |
| 306 | +} |
0 commit comments