Skip to content

Commit

Permalink
DebugNamesDWARFIndex: Implement GetFunctions method
Browse files Browse the repository at this point in the history
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
  • Loading branch information
labath committed Jun 8, 2018
1 parent 6dedf2b commit 257ff33
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 72 deletions.
16 changes: 16 additions & 0 deletions lldb/lit/SymbolFile/DWARF/find-basic-function.cpp
Expand Up @@ -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"
Expand Down
70 changes: 5 additions & 65 deletions lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
Expand Up @@ -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"

Expand Down Expand Up @@ -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);
}
DIEArray offsets;
m_apple_names_up->FindByName(name.GetStringRef(), offsets);
for (const DIERef &die_ref : offsets) {
ProcessFunctionDIE(name.GetStringRef(), die_ref, info, parent_decl_ctx,
name_type_mask, dies);
}
}

Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DIERef.h
Expand Up @@ -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;
};
Expand Down
51 changes: 51 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
Expand Up @@ -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);
}
}
10 changes: 10 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
Expand Up @@ -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;
Expand Down Expand Up @@ -53,6 +54,15 @@ class DWARFIndex {

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

Expand Down
32 changes: 29 additions & 3 deletions lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
Expand Up @@ -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"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);

Expand Down
10 changes: 6 additions & 4 deletions lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
Expand Up @@ -38,7 +38,7 @@ class DebugNamesDWARFIndex : public DWARFIndex {
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 {}

Expand All @@ -64,9 +64,11 @@ class DebugNamesDWARFIndex : public DWARFIndex {
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,
llvm::StringRef name);
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);
};
Expand Down

0 comments on commit 257ff33

Please sign in to comment.