Pavel Labath 3ca31ba75a AppleDWARFIndex: Get function method-ness directly from debug info
Summary:
When searching for methods only, we need to do extra work to make sure
the functions we get from the apple tables are indeed methods.
Previously we were resolving the DIE into a SymbolContext and then
checked whether the enclosing CompilerDeclContext is a
class (or struct, or union).

This patch changes that to operate on the debug info directly. This
should be:
- simpler
- faster
- more consistent with the ManualDWARFIndex (which does the same check,
  only at indexing time).

What we lose this ways is for the language plugin to have a say in what
it considers to be a "class", but that's probably more flexibility than
we need (and if we really wanted to do that in the future, we could
implement a more direct way to consult the plugin about this).

This also fixes the find-method-local-struct test, which was failing
because we were not able to construct a CompilerDeclContext for a local
struct correctly.

As a drive-by, I rename the DWARFDIE's IsStructClassOrUnion method to
match the name on the CompilerDeclContext class.

Reviewers: clayborg, JDevlieghere

Subscribers: aprantl, lldb-commits

Differential Revision: https://reviews.llvm.org/D47470

llvm-svn: 333878
2018-06-04 09:05:27 +00:00

283 lines
11 KiB
C++

//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.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 = llvm::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 =
llvm::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 = llvm::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 = llvm::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 llvm::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 name, DIEArray &offsets) {
if (!m_apple_names_up)
return;
const char *name_cstr = name.GetCString();
llvm::StringRef basename;
llvm::StringRef context;
if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context,
basename))
basename = name_cstr;
m_apple_names_up->FindByName(basename, offsets);
}
void AppleDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
DIEArray &offsets) {
if (!m_apple_names_up)
return;
DWARFMappedHash::DIEInfoArray hash_data;
if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data))
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
}
void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
DIEArray &offsets) {
if (!m_apple_names_up)
return;
DWARFMappedHash::DIEInfoArray hash_data;
if (m_apple_names_up->AppendAllDIEsInRange(
cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data))
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
}
void AppleDWARFIndex::GetObjCMethods(ConstString class_name,
DIEArray &offsets) {
if (m_apple_objc_up)
m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets);
}
void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name,
bool must_be_implementation,
DIEArray &offsets) {
if (m_apple_types_up) {
m_apple_types_up->FindCompleteObjCClassByName(
class_name.GetStringRef(), offsets, must_be_implementation);
}
}
void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
if (m_apple_types_up)
m_apple_types_up->FindByName(name.GetStringRef(), offsets);
}
void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
DIEArray &offsets) {
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, offsets);
} else if (has_tag) {
if (log)
m_module.LogMessage(log, "FindByNameAndTag()");
m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
} else
m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
}
void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
if (m_apple_namespaces_up)
m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets);
}
static bool KeepFunctionDIE(DWARFDIE die, uint32_t name_type_mask) {
bool looking_for_methods = name_type_mask & eFunctionNameTypeMethod;
bool looking_for_functions = name_type_mask & eFunctionNameTypeBase;
if (looking_for_methods && looking_for_functions)
return true;
return looking_for_methods == die.IsMethod();
}
void AppleDWARFIndex::GetFunctions(
ConstString name, DWARFDebugInfo &info,
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
lldb_private::SymbolContextList &sc_list)>
resolve_function,
llvm::function_ref<CompilerDeclContext(lldb::user_id_t type_uid)>
get_decl_context_containing_uid,
const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask,
bool include_inlines, SymbolContextList &sc_list) {
if (!m_apple_names_up)
return;
std::set<const DWARFDebugInfoEntry *> resolved_dies;
DIEArray offsets;
uint32_t num_matches = 0;
if (name_type_mask & eFunctionNameTypeFull) {
// If they asked for the full name, match what they typed. At some
// point we may want to canonicalize this (strip double spaces, etc.
// For now, we just add all the dies that we find by exact match.
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = offsets[i];
DWARFDIE die = info.GetDIE(die_ref);
if (die) {
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (resolve_function(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
} else
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
}
}
if (name_type_mask & eFunctionNameTypeSelector) {
if (parent_decl_ctx && parent_decl_ctx->IsValid())
return; // no selectors in namespaces
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
// Now make sure these are actually ObjC methods. In this case we can
// simply look up the name, and if it is an ObjC method name, we're
// good.
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = offsets[i];
DWARFDIE die = info.GetDIE(die_ref);
if (die) {
const char *die_name = die.GetName();
if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) {
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (resolve_function(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
}
} else
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
}
offsets.clear();
}
if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) ||
name_type_mask & eFunctionNameTypeBase) {
// The apple_names table stores just the "base name" of C++ methods in
// the table. So we have to extract the base name, look that up, and
// if there is any other information in the name we were passed in we
// have to post-filter based on that.
// FIXME: Arrange the logic above so that we don't calculate the base
// name twice:
num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = offsets[i];
DWARFDIE die = info.GetDIE(die_ref);
if (die) {
if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
if (!KeepFunctionDIE(die, name_type_mask))
continue;
if (resolved_dies.find(die.GetDIE()) != resolved_dies.end())
continue;
// If we get to here, the die is good, and we should add it:
if (resolve_function(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
} else
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
}
offsets.clear();
}
}
void AppleDWARFIndex::GetFunctions(
const RegularExpression &regex, DWARFDebugInfo &info,
llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
lldb_private::SymbolContextList &sc_list)>
resolve_function,
bool include_inlines, SymbolContextList &sc_list) {
if (!m_apple_names_up)
return;
DIEArray offsets;
DWARFMappedHash::DIEInfoArray hash_data;
if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) {
DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
ParseFunctions(offsets, info, resolve_function, include_inlines, sc_list);
}
}
void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset,
llvm::StringRef name) {
m_module.ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (accelerator table had "
"bad die 0x%8.8x for '%s')\n",
offset, name.str().c_str());
}
void AppleDWARFIndex::Dump(Stream &s) {
// TODO: Implement dumping.
}