DebugNamesDWARFIndex: Implement GetFunctions method

Summary:
This patch implements the non-regex variant of GetFunctions. To share
more code with the Apple implementation, I've extracted the common
filtering code from that class into a utility function on the DWARFIndex
base class.

The new implementation also searching the accelerator table multiple
times -- previously it could happen that the apple table would return
the same die more than once if one specified multiple search flags in
name_type_mask. This way, I separate table iteration from filtering, and
so we can be sure each die is inserted at most once.

Reviewers: clayborg, JDevlieghere

Subscribers: aprantl, lldb-commits

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

llvm-svn: 334273
This commit is contained in:
Pavel Labath 2018-06-08 09:10:31 +00:00
parent 6dedf2b5d8
commit 257ff33989
7 changed files with 121 additions and 72 deletions

View File

@ -29,6 +29,22 @@
// RUN: lldb-test symbols --name=not_there --find=function %t | \
// RUN: FileCheck --check-prefix=EMPTY %s
// RUN: clang %s -g -c -emit-llvm -o - --target=x86_64-pc-linux | \
// RUN: llc -accel-tables=Dwarf -filetype=obj -o %t.o
// RUN: ld.lld %t.o -o %t
// RUN: lldb-test symbols --name=foo --find=function --function-flags=base %t | \
// RUN: FileCheck --check-prefix=BASE %s
// RUN: lldb-test symbols --name=foo --find=function --function-flags=method %t | \
// RUN: FileCheck --check-prefix=METHOD %s
// RUN: lldb-test symbols --name=foo --find=function --function-flags=full %t | \
// RUN: FileCheck --check-prefix=FULL %s
// RUN: lldb-test symbols --name=_Z3fooi --find=function --function-flags=full %t | \
// RUN: FileCheck --check-prefix=FULL-MANGLED %s
// RUN: lldb-test symbols --name=foo --context=context --find=function --function-flags=base %t | \
// RUN: FileCheck --check-prefix=CONTEXT %s
// RUN: lldb-test symbols --name=not_there --find=function %t | \
// RUN: FileCheck --check-prefix=EMPTY %s
// BASE: Found 4 functions:
// BASE-DAG: name = "foo()", mangled = "_Z3foov"
// BASE-DAG: name = "foo(int)", mangled = "_Z3fooi"

View File

@ -13,7 +13,6 @@
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"
@ -135,74 +134,15 @@ void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
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,
const CompilerDeclContext &parent_decl_ctx,
uint32_t name_type_mask,
std::vector<DWARFDIE> &dies) {
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.
DIEArray offsets;
m_apple_names_up->FindByName(name.GetStringRef(), offsets);
for (const DIERef &die_ref : offsets) {
DWARFDIE die = info.GetDIE(die_ref);
if (!die) {
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
continue;
}
if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die))
dies.push_back(die);
}
}
if (name_type_mask & eFunctionNameTypeSelector &&
!parent_decl_ctx.IsValid()) {
DIEArray offsets;
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 (const DIERef &die_ref: offsets) {
DWARFDIE die = info.GetDIE(die_ref);
if (!die) {
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
continue;
}
const char *die_name = die.GetName();
if (ObjCLanguage::IsPossibleObjCMethodName(die_name))
dies.push_back(die);
}
}
if (((name_type_mask & eFunctionNameTypeMethod) &&
!parent_decl_ctx.IsValid()) ||
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.
DIEArray offsets;
m_apple_names_up->FindByName(name.GetStringRef(), offsets);
for (const DIERef &die_ref: offsets) {
DWARFDIE die = info.GetDIE(die_ref);
if (!die) {
ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
continue;
}
if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die) &&
KeepFunctionDIE(die, name_type_mask))
dies.push_back(die);
}
ProcessFunctionDIE(name.GetStringRef(), die_ref, info, parent_decl_ctx,
name_type_mask, dies);
}
}

View File

@ -45,6 +45,10 @@ struct DIERef {
bool operator<(const DIERef &ref) { return die_offset < ref.die_offset; }
explicit operator bool() const {
return cu_offset != DW_INVALID_OFFSET || die_offset != DW_INVALID_OFFSET;
}
dw_offset_t cu_offset = DW_INVALID_OFFSET;
dw_offset_t die_offset = DW_INVALID_OFFSET;
};

View File

@ -11,7 +11,58 @@
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
using namespace lldb_private;
using namespace lldb;
DWARFIndex::~DWARFIndex() = default;
void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref,
DWARFDebugInfo &info,
const CompilerDeclContext &parent_decl_ctx,
uint32_t name_type_mask,
std::vector<DWARFDIE> &dies) {
DWARFDIE die = info.GetDIE(ref);
if (!die) {
ReportInvalidDIEOffset(ref.die_offset, name);
return;
}
// Exit early if we're searching exclusively for methods or selectors and
// we have a context specified (no methods in namespaces).
uint32_t looking_for_nonmethods =
name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector);
if (!looking_for_nonmethods && parent_decl_ctx.IsValid())
return;
// Otherwise, we need to also check that the context matches. If it does not
// match, we do nothing.
if (!SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die))
return;
// In case of a full match, we just insert everything we find.
if (name_type_mask & eFunctionNameTypeFull) {
dies.push_back(die);
return;
}
// If looking for ObjC selectors, we need to also check if the name is a
// possible selector.
if (name_type_mask & eFunctionNameTypeSelector &&
ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) {
dies.push_back(die);
return;
}
bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod;
bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase;
if (looking_for_methods || looking_for_functions) {
// If we're looking for either methods or functions, we definitely want this
// die. Otherwise, only keep it if the die type matches what we are
// searching for.
if ((looking_for_methods && looking_for_functions) ||
looking_for_methods == die.IsMethod())
dies.push_back(die);
}
}

View File

@ -11,6 +11,7 @@
#define LLDB_DWARFINDEX_H
#include "Plugins/SymbolFile/DWARF/DIERef.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/DWARFFormValue.h"
class DWARFDebugInfo;
@ -53,6 +54,15 @@ public:
protected:
Module &m_module;
/// Helper function implementing common logic for processing function dies. If
/// the function given by "ref" matches search criteria given by
/// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies"
/// vector.
void ProcessFunctionDIE(llvm::StringRef name, DIERef ref,
DWARFDebugInfo &info,
const CompilerDeclContext &parent_decl_ctx,
uint32_t name_type_mask, std::vector<DWARFDIE> &dies);
};
} // namespace lldb_private

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
@ -44,12 +45,18 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
return result;
}
void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
DIEArray &offsets) {
DIERef DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
llvm::Optional<uint64_t> die_offset = entry.getDIESectionOffset();
if (cu_offset && die_offset)
offsets.emplace_back(*cu_offset, *die_offset);
return DIERef(*cu_offset, *die_offset);
return DIERef();
}
void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
DIEArray &offsets) {
if (DIERef ref = ToDIERef(entry))
offsets.push_back(ref);
}
void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
@ -118,6 +125,25 @@ void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
}
}
void DebugNamesDWARFIndex::GetFunctions(
ConstString name, DWARFDebugInfo &info,
const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
std::vector<DWARFDIE> &dies) {
m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, dies);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(name.GetStringRef())) {
Tag tag = entry.tag();
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
continue;
if (DIERef ref = ToDIERef(entry))
ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx,
name_type_mask, dies);
}
}
void DebugNamesDWARFIndex::Dump(Stream &s) {
m_fallback.Dump(s);

View File

@ -38,7 +38,7 @@ public:
void GetFunctions(ConstString name, DWARFDebugInfo &info,
const CompilerDeclContext &parent_decl_ctx,
uint32_t name_type_mask,
std::vector<DWARFDIE> &dies) override {}
std::vector<DWARFDIE> &dies) override;
void GetFunctions(const RegularExpression &regex,
DIEArray &offsets) override {}
@ -64,8 +64,10 @@ private:
std::unique_ptr<DebugNames> m_debug_names_up;
ManualDWARFIndex m_fallback;
void Append(const DebugNames::Entry &entry, DIEArray &offsets);
void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni,
static DIERef ToDIERef(const DebugNames::Entry &entry);
static void Append(const DebugNames::Entry &entry, DIEArray &offsets);
static void MaybeLogLookupError(llvm::Error error,
const DebugNames::NameIndex &ni,
llvm::StringRef name);
static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names);