Pavel Labath wrote in D73206: The internal representation of DebugNames and Apple indexes is fixed by the relevant (pseudo-)standards, so we can't really change it. The question is how to efficiently (and cleanly) convert from the internal representation to some common thing. The conversion from AppleIndex to DIERef is trivial (which is not surprising as it was the first and the overall design was optimized for that). With debug_names, the situation gets more tricky. The internal representation of debug_names uses CU-relative DIE offsets, but DIERef wants an absolute offset. That means the index has to do more work to produce the common representation. And it needs to do that for all results, even though a lot of the index users are really interested only in a single entry. With the switch to user_id_t, _all_ indexes would have to do some extra work to encode it, only for their users to have to immediately decode it back. Having a iterator/callback based api would allow us to minimize the impact of that, as it would only need to happen for the entries that are really used. And /I think/ we could make it interface returns DWARFDies directly, and each index converts to that using the most direct approach available. Jan Kratochvil: It also makes all the callers shorter as they no longer need to fetch DWARFDIE from DIERef (and handling if not found by ReportInvalidDIERef) but the callers are already served DWARFDIE which they need. In some cases the DWARFDIE had to be fetched both by callee (DWARFIndex implementation) and caller. Differential Revision: https://reviews.llvm.org/D77970
212 lines
7.6 KiB
C++
212 lines
7.6 KiB
C++
//===-- AppleDWARFIndex.cpp -----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
|
|
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
|
|
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
|
|
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
|
|
Module &module, DWARFDataExtractor apple_names,
|
|
DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
|
|
DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
|
|
auto apple_names_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
|
|
apple_names, debug_str, ".apple_names");
|
|
if (!apple_names_table_up->IsValid())
|
|
apple_names_table_up.reset();
|
|
|
|
auto apple_namespaces_table_up =
|
|
std::make_unique<DWARFMappedHash::MemoryTable>(
|
|
apple_namespaces, debug_str, ".apple_namespaces");
|
|
if (!apple_namespaces_table_up->IsValid())
|
|
apple_namespaces_table_up.reset();
|
|
|
|
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_objc_table_up = std::make_unique<DWARFMappedHash::MemoryTable>(
|
|
apple_objc, debug_str, ".apple_objc");
|
|
if (!apple_objc_table_up->IsValid())
|
|
apple_objc_table_up.reset();
|
|
|
|
if (apple_names_table_up || apple_names_table_up || apple_types_table_up ||
|
|
apple_objc_table_up)
|
|
return std::make_unique<AppleDWARFIndex>(
|
|
module, std::move(apple_names_table_up),
|
|
std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
|
|
std::move(apple_objc_table_up));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void AppleDWARFIndex::GetGlobalVariables(
|
|
ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_names_up)
|
|
return;
|
|
m_apple_names_up->FindByName(
|
|
basename.GetStringRef(),
|
|
DIERefCallback(callback, basename.GetStringRef()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetGlobalVariables(
|
|
const RegularExpression ®ex,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_names_up)
|
|
return;
|
|
|
|
DWARFMappedHash::DIEInfoArray hash_data;
|
|
m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data);
|
|
// This is not really the DIE name.
|
|
DWARFMappedHash::ExtractDIEArray(hash_data,
|
|
DIERefCallback(callback, regex.GetText()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetGlobalVariables(
|
|
const DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_names_up)
|
|
return;
|
|
|
|
DWARFMappedHash::DIEInfoArray hash_data;
|
|
m_apple_names_up->AppendAllDIEsInRange(cu.GetOffset(), cu.GetNextUnitOffset(),
|
|
hash_data);
|
|
DWARFMappedHash::ExtractDIEArray(hash_data, DIERefCallback(callback));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetObjCMethods(
|
|
ConstString class_name, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_objc_up)
|
|
return;
|
|
m_apple_objc_up->FindByName(
|
|
class_name.GetStringRef(),
|
|
DIERefCallback(callback, class_name.GetStringRef()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetCompleteObjCClass(
|
|
ConstString class_name, bool must_be_implementation,
|
|
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);
|
|
}
|
|
|
|
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()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetTypes(
|
|
const DWARFDeclContext &context,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_types_up)
|
|
return;
|
|
|
|
Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
|
|
DWARF_LOG_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);
|
|
if (log)
|
|
m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
|
|
m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
|
|
type_name.GetStringRef(), tag, qualified_name_hash,
|
|
DIERefCallback(callback, type_name.GetStringRef()));
|
|
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()));
|
|
return;
|
|
}
|
|
|
|
m_apple_types_up->FindByName(
|
|
type_name.GetStringRef(),
|
|
DIERefCallback(callback, type_name.GetStringRef()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetNamespaces(
|
|
ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_namespaces_up)
|
|
return;
|
|
m_apple_namespaces_up->FindByName(
|
|
name.GetStringRef(), DIERefCallback(callback, name.GetStringRef()));
|
|
}
|
|
|
|
void AppleDWARFIndex::GetFunctions(
|
|
ConstString name, SymbolFileDWARF &dwarf,
|
|
const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
m_apple_names_up->FindByName(name.GetStringRef(), [&](DIERef die_ref) {
|
|
return ProcessFunctionDIE(name.GetStringRef(), die_ref, dwarf,
|
|
parent_decl_ctx, name_type_mask, callback);
|
|
});
|
|
}
|
|
|
|
void AppleDWARFIndex::GetFunctions(
|
|
const RegularExpression ®ex,
|
|
llvm::function_ref<bool(DWARFDIE die)> callback) {
|
|
if (!m_apple_names_up)
|
|
return;
|
|
|
|
DWARFMappedHash::DIEInfoArray hash_data;
|
|
m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data);
|
|
DWARFMappedHash::ExtractDIEArray(hash_data,
|
|
DIERefCallback(callback, regex.GetText()));
|
|
}
|
|
|
|
void AppleDWARFIndex::Dump(Stream &s) {
|
|
if (m_apple_names_up)
|
|
s.PutCString(".apple_names index present\n");
|
|
if (m_apple_namespaces_up)
|
|
s.PutCString(".apple_namespaces index present\n");
|
|
if (m_apple_types_up)
|
|
s.PutCString(".apple_types index present\n");
|
|
if (m_apple_objc_up)
|
|
s.PutCString(".apple_objc index present\n");
|
|
// TODO: Dump index contents
|
|
}
|