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:
parent
6dedf2b5d8
commit
257ff33989
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ®ex,
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue