std::make_unique<llvm::AppleAcceleratorTable>(
apple_namespaces.GetAsLLVMDWARF(), llvm_debug_str);
- auto apple_types_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
- apple_types, debug_str, ".apple_types");
- if (!apple_types_table_up->IsValid())
- apple_types_table_up.reset();
+ auto apple_types_table_up = std::make_unique<llvm::AppleAcceleratorTable>(
+ apple_types.GetAsLLVMDWARF(), llvm_debug_str);
auto apple_objc_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
apple_objc, debug_str, ".apple_objc");
extract_and_check(apple_names_table_up);
extract_and_check(apple_namespaces_table_up);
+ extract_and_check(apple_types_table_up);
if (apple_names_table_up || apple_namespaces_table_up ||
apple_types_table_up || apple_objc_table_up)
return nullptr;
}
+/// Returns true if `tag` is a class_type of structure_type tag.
+static bool IsClassOrStruct(dw_tag_t tag) {
+ return tag == DW_TAG_class_type || tag == DW_TAG_structure_type;
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_qual_name_hash and it
+/// matches `expected_hash`.
+static bool
+EntryHasMatchingQualhash(const llvm::AppleAcceleratorTable::Entry &entry,
+ uint32_t expected_hash) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_qual_name_hash);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> hash = form_value->getAsUnsignedConstant();
+ return hash && (*hash == expected_hash);
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_die_tag and it matches
+/// `expected_tag`. We also consider it a match if the tags are different but
+/// in the set of {TAG_class_type, TAG_struct_type}.
+static bool EntryHasMatchingTag(const llvm::AppleAcceleratorTable::Entry &entry,
+ dw_tag_t expected_tag) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_die_tag);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> maybe_tag = form_value->getAsUnsignedConstant();
+ if (!maybe_tag)
+ return false;
+ auto tag = static_cast<dw_tag_t>(*maybe_tag);
+ return tag == expected_tag ||
+ (IsClassOrStruct(tag) && IsClassOrStruct(expected_tag));
+}
+
+/// Returns true if `entry` has an extractable DW_ATOM_type_flags and the flag
+/// "DW_FLAG_type_implementation" is set.
+static bool
+HasImplementationFlag(const llvm::AppleAcceleratorTable::Entry &entry) {
+ std::optional<llvm::DWARFFormValue> form_value =
+ entry.lookup(dwarf::DW_ATOM_type_flags);
+ if (!form_value)
+ return false;
+ std::optional<uint64_t> Flags = form_value->getAsUnsignedConstant();
+ return Flags &&
+ (*Flags & llvm::dwarf::AcceleratorTable::DW_FLAG_type_implementation);
+}
+
void AppleDWARFIndex::SearchFor(const llvm::AppleAcceleratorTable &table,
llvm::StringRef name,
llvm::function_ref<bool(DWARFDIE die)> callback,
std::optional<dw_tag_t> search_for_tag,
std::optional<uint32_t> search_for_qualhash) {
- assert(!search_for_tag && !search_for_qualhash && "not yet implemented");
auto converted_cb = DIERefCallback(callback, name);
- for (const auto &entry : table.equal_range(name))
+ for (const auto &entry : table.equal_range(name)) {
+ if (search_for_qualhash &&
+ !EntryHasMatchingQualhash(entry, *search_for_qualhash))
+ continue;
+ if (search_for_tag && !EntryHasMatchingTag(entry, *search_for_tag))
+ continue;
if (!converted_cb(entry))
break;
+ }
}
void AppleDWARFIndex::GetGlobalVariables(
llvm::function_ref<bool(DWARFDIE die)> callback) {
if (!m_apple_types_up)
return;
- m_apple_types_up->FindCompleteObjCClassByName(
- class_name.GetStringRef(),
- DIERefCallback(callback, class_name.GetStringRef()),
- must_be_implementation);
+
+ llvm::SmallVector<DIERef> decl_dies;
+ auto converted_cb = DIERefCallback(callback, class_name);
+
+ for (const auto &entry : m_apple_types_up->equal_range(class_name)) {
+ if (HasImplementationFlag(entry)) {
+ converted_cb(entry);
+ return;
+ }
+
+ decl_dies.emplace_back(std::nullopt, DIERef::Section::DebugInfo,
+ *entry.getDIESectionOffset());
+ }
+
+ if (must_be_implementation)
+ return;
+ for (DIERef ref : decl_dies)
+ if (!converted_cb(ref))
+ return;
}
void AppleDWARFIndex::GetTypes(
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
if (!m_apple_types_up)
return;
- m_apple_types_up->FindByName(name.GetStringRef(),
- DIERefCallback(callback, name.GetStringRef()));
+ SearchFor(*m_apple_types_up, name, callback);
}
void AppleDWARFIndex::GetTypes(
return;
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
- const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom(
- DWARFMappedHash::eAtomTypeTag);
- const bool has_qualified_name_hash =
- m_apple_types_up->GetHeader().header_data.ContainsAtom(
- DWARFMappedHash::eAtomTypeQualNameHash);
-
- const ConstString type_name(context[0].name);
- const dw_tag_t tag = context[0].tag;
- if (has_tag && has_qualified_name_hash) {
- const char *qualified_name = context.GetQualifiedName();
- const uint32_t qualified_name_hash = llvm::djbHash(qualified_name);
+ const bool entries_have_tag =
+ m_apple_types_up->containsAtomType(DW_ATOM_die_tag);
+ const bool entries_have_qual_hash =
+ m_apple_types_up->containsAtomType(DW_ATOM_qual_name_hash);
+
+ llvm::StringRef expected_name = context[0].name;
+
+ if (entries_have_tag && entries_have_qual_hash) {
+ const dw_tag_t expected_tag = context[0].tag;
+ const uint32_t expected_qualname_hash =
+ llvm::djbHash(context.GetQualifiedName());
if (log)
m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
- m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
- type_name.GetStringRef(), tag, qualified_name_hash,
- DIERefCallback(callback, type_name.GetStringRef()));
+ SearchFor(*m_apple_types_up, expected_name, callback, expected_tag,
+ expected_qualname_hash);
return;
}
- if (has_tag) {
- // When searching for a scoped type (for example,
- // "std::vector<int>::const_iterator") searching for the innermost
- // name alone ("const_iterator") could yield many false
- // positives. By searching for the parent type ("vector<int>")
- // first we can avoid extracting type DIEs from object files that
- // would fail the filter anyway.
- if (!has_qualified_name_hash && (context.GetSize() > 1) &&
- (context[1].tag == DW_TAG_class_type ||
- context[1].tag == DW_TAG_structure_type)) {
- if (m_apple_types_up->FindByName(context[1].name,
- [&](DIERef ref) { return false; }))
- return;
- }
-
- if (log)
- m_module.LogMessage(log, "FindByNameAndTag()");
- m_apple_types_up->FindByNameAndTag(
- type_name.GetStringRef(), tag,
- DIERefCallback(callback, type_name.GetStringRef()));
+ // Historically, if there are no tags, we also ignore qual_hash (why?)
+ if (!entries_have_tag) {
+ SearchFor(*m_apple_names_up, expected_name, callback);
return;
}
- m_apple_types_up->FindByName(
- type_name.GetStringRef(),
- DIERefCallback(callback, type_name.GetStringRef()));
+ // We have a tag but no qual hash.
+
+ // When searching for a scoped type (for example,
+ // "std::vector<int>::const_iterator") searching for the innermost
+ // name alone ("const_iterator") could yield many false
+ // positives. By searching for the parent type ("vector<int>")
+ // first we can avoid extracting type DIEs from object files that
+ // would fail the filter anyway.
+ if ((context.GetSize() > 1) && IsClassOrStruct(context[1].tag))
+ if (m_apple_types_up->equal_range(context[1].name).empty())
+ return;
+
+ if (log)
+ m_module.LogMessage(log, "FindByNameAndTag()");
+ const dw_tag_t expected_tag = context[0].tag;
+ SearchFor(*m_apple_types_up, expected_name, callback, expected_tag);
+ return;
}
void AppleDWARFIndex::GetNamespaces(
return true;
}
-void DWARFMappedHash::ExtractDIEArray(
- const DIEInfoArray &die_info_array, const dw_tag_t tag,
- llvm::function_ref<bool(DIERef ref)> callback) {
- if (tag == 0) {
- ExtractDIEArray(die_info_array, callback);
- return;
- }
-
- const size_t count = die_info_array.size();
- for (size_t i = 0; i < count; ++i) {
- const dw_tag_t die_tag = die_info_array[i].tag;
- bool tag_matches = die_tag == 0 || tag == die_tag;
- if (!tag_matches) {
- if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
- tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
- }
- if (tag_matches) {
- if (!callback(DIERef(die_info_array[i])))
- return;
- }
- }
-}
-
-void DWARFMappedHash::ExtractDIEArray(
- const DIEInfoArray &die_info_array, const dw_tag_t tag,
- const uint32_t qualified_name_hash,
- llvm::function_ref<bool(DIERef ref)> callback) {
- if (tag == 0) {
- ExtractDIEArray(die_info_array, callback);
- return;
- }
-
- const size_t count = die_info_array.size();
- for (size_t i = 0; i < count; ++i) {
- if (qualified_name_hash != die_info_array[i].qualified_name_hash)
- continue;
- const dw_tag_t die_tag = die_info_array[i].tag;
- bool tag_matches = die_tag == 0 || tag == die_tag;
- if (!tag_matches) {
- if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
- tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
- }
- if (tag_matches) {
- if (!callback(DIERef(die_info_array[i])))
- return;
- }
- }
-}
-
-void DWARFMappedHash::ExtractClassOrStructDIEArray(
- const DIEInfoArray &die_info_array,
- bool return_implementation_only_if_available,
- llvm::function_ref<bool(DIERef ref)> callback) {
- const size_t count = die_info_array.size();
- for (size_t i = 0; i < count; ++i) {
- const dw_tag_t die_tag = die_info_array[i].tag;
- if (!(die_tag == 0 || die_tag == DW_TAG_class_type ||
- die_tag == DW_TAG_structure_type))
- continue;
- bool is_implementation =
- (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) != 0;
- if (is_implementation != return_implementation_only_if_available)
- continue;
- if (return_implementation_only_if_available) {
- // We found the one true definition for this class, so only return
- // that
- callback(DIERef(die_info_array[i]));
- return;
- }
- if (!callback(DIERef(die_info_array[i])))
- return;
- }
-}
-
-void DWARFMappedHash::ExtractTypesFromDIEArray(
- const DIEInfoArray &die_info_array, uint32_t type_flag_mask,
- uint32_t type_flag_value, llvm::function_ref<bool(DIERef ref)> callback) {
- const size_t count = die_info_array.size();
- for (size_t i = 0; i < count; ++i) {
- if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value) {
- if (!callback(DIERef(die_info_array[i])))
- return;
- }
- }
-}
-
const char *DWARFMappedHash::GetAtomTypeName(uint16_t atom) {
switch (atom) {
case eAtomTypeNULL:
return DWARFMappedHash::ExtractDIEArray(die_info_array, callback);
}
-void DWARFMappedHash::MemoryTable::FindByNameAndTag(
- llvm::StringRef name, const dw_tag_t tag,
- llvm::function_ref<bool(DIERef ref)> callback) {
- DIEInfoArray die_info_array;
- FindByName(name, die_info_array);
- DWARFMappedHash::ExtractDIEArray(die_info_array, tag, callback);
-}
-
-void DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash(
- llvm::StringRef name, const dw_tag_t tag,
- const uint32_t qualified_name_hash,
- llvm::function_ref<bool(DIERef ref)> callback) {
- DIEInfoArray die_info_array;
- FindByName(name, die_info_array);
- DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash,
- callback);
-}
-
-void DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName(
- llvm::StringRef name, llvm::function_ref<bool(DIERef ref)> callback,
- bool must_be_implementation) {
- DIEInfoArray die_info_array;
- FindByName(name, die_info_array);
- if (must_be_implementation &&
- GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) {
- // If we have two atoms, then we have the DIE offset and the type flags
- // so we can find the objective C class efficiently.
- DWARFMappedHash::ExtractTypesFromDIEArray(
- die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, callback);
- return;
- }
- // We don't only want the one true definition, so try and see what we can
- // find, and only return class or struct DIEs. If we do have the full
- // implementation, then return it alone, else return all possible
- // matches.
- bool found_implementation = false;
- DWARFMappedHash::ExtractClassOrStructDIEArray(
- die_info_array, true /*return_implementation_only_if_available*/,
- [&](DIERef ref) {
- found_implementation = true;
- // Here the return value does not matter as we are called at most once.
- return callback(ref);
- });
- if (found_implementation)
- return;
- DWARFMappedHash::ExtractClassOrStructDIEArray(
- die_info_array, false /*return_implementation_only_if_available*/,
- callback);
-}
-
void DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name,
DIEInfoArray &die_info_array) {
if (name.empty())