Skip to content

Commit 44f41f5

Browse files
Reland "[LLDB][NativePDB] Find functions by basename" ( #152295) (#153160)
Relands #152295. Checking for the overloads did not account for them being out of order. For example, [the failed output](#152295 (comment)) contained the overloads, but out of order. The last commit here fixes that by using `-DAG`. --------- Co-authored-by: Jonas Devlieghere <[email protected]>
1 parent d99b043 commit 44f41f5

File tree

3 files changed

+224
-25
lines changed

3 files changed

+224
-25
lines changed

lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
4040
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
4141
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
42+
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
4243
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
4344
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
4445
#include "llvm/DebugInfo/PDB/PDB.h"
@@ -1641,6 +1642,94 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
16411642
clang->GetNativePDBParser()->Dump(s, filter);
16421643
}
16431644

1645+
void SymbolFileNativePDB::CacheFunctionNames() {
1646+
if (!m_func_full_names.IsEmpty())
1647+
return;
1648+
1649+
// (segment, code offset) -> gid
1650+
std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;
1651+
1652+
// First, find all function references in the globals table.
1653+
for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
1654+
CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
1655+
auto kind = ref_sym.kind();
1656+
if (kind != S_PROCREF && kind != S_LPROCREF)
1657+
continue;
1658+
1659+
ProcRefSym ref =
1660+
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
1661+
if (ref.Name.empty())
1662+
continue;
1663+
1664+
// Find the function this is referencing.
1665+
CompilandIndexItem &cci =
1666+
m_index->compilands().GetOrCreateCompiland(ref.modi());
1667+
auto iter = cci.m_debug_stream.getSymbolArray().at(ref.SymOffset);
1668+
if (iter == cci.m_debug_stream.getSymbolArray().end())
1669+
continue;
1670+
kind = iter->kind();
1671+
if (kind != S_GPROC32 && kind != S_LPROC32)
1672+
continue;
1673+
1674+
ProcSym proc =
1675+
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*iter));
1676+
if ((proc.Flags & ProcSymFlags::IsUnreachable) != ProcSymFlags::None)
1677+
continue;
1678+
if (proc.Name.empty())
1679+
continue;
1680+
1681+
// The function/procedure symbol only contains the demangled name.
1682+
// The mangled names are in the publics table. Save the address of this
1683+
// function to lookup the mangled name later.
1684+
addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
1685+
1686+
llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
1687+
if (basename.empty())
1688+
basename = proc.Name;
1689+
1690+
m_func_base_names.Append(ConstString(basename), gid);
1691+
m_func_full_names.Append(ConstString(proc.Name), gid);
1692+
1693+
// To see if this is a member function, check the type.
1694+
auto type = m_index->tpi().getType(proc.FunctionType);
1695+
if (type.kind() == LF_MFUNCTION) {
1696+
MemberFunctionRecord mfr;
1697+
llvm::cantFail(
1698+
TypeDeserializer::deserializeAs<MemberFunctionRecord>(type, mfr));
1699+
if (!mfr.getThisType().isNoneType())
1700+
m_func_method_names.Append(ConstString(basename), gid);
1701+
}
1702+
}
1703+
1704+
// The publics stream contains all mangled function names and their address.
1705+
for (auto pid : m_index->publics().getPublicsTable()) {
1706+
PdbGlobalSymId global{pid, true};
1707+
CVSymbol sym = m_index->ReadSymbolRecord(global);
1708+
auto kind = sym.kind();
1709+
if (kind != S_PUB32)
1710+
continue;
1711+
PublicSym32 pub =
1712+
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
1713+
// We only care about mangled names - if the name isn't mangled, it's
1714+
// already in the full name map.
1715+
if (!Mangled::IsMangledName(pub.Name))
1716+
continue;
1717+
1718+
// Check if this symbol is for one of our functions.
1719+
auto it = addr_ids.find({pub.Segment, pub.Offset});
1720+
if (it != addr_ids.end())
1721+
m_func_full_names.Append(ConstString(pub.Name), it->second);
1722+
}
1723+
1724+
// Sort them before value searching is working properly.
1725+
m_func_full_names.Sort();
1726+
m_func_full_names.SizeToFit();
1727+
m_func_method_names.Sort();
1728+
m_func_method_names.SizeToFit();
1729+
m_func_base_names.Sort();
1730+
m_func_base_names.SizeToFit();
1731+
}
1732+
16441733
void SymbolFileNativePDB::FindGlobalVariables(
16451734
ConstString name, const CompilerDeclContext &parent_decl_ctx,
16461735
uint32_t max_matches, VariableList &variables) {
@@ -1677,34 +1766,60 @@ void SymbolFileNativePDB::FindFunctions(
16771766
if (name_type_mask & eFunctionNameTypeFull)
16781767
name = lookup_info.GetName();
16791768

1680-
// For now we only support lookup by method name or full name.
16811769
if (!(name_type_mask & eFunctionNameTypeFull ||
1770+
name_type_mask & eFunctionNameTypeBase ||
16821771
name_type_mask & eFunctionNameTypeMethod))
16831772
return;
1773+
CacheFunctionNames();
16841774

1685-
using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
1775+
std::set<uint32_t> resolved_ids; // avoid duplicate lookups
1776+
auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {
1777+
std::vector<uint32_t> ids;
1778+
if (!Names.GetValues(name, ids))
1779+
return;
16861780

1687-
std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
1688-
name.GetStringRef(), m_index->symrecords());
1689-
for (const SymbolAndOffset &match : matches) {
1690-
if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
1691-
continue;
1692-
ProcRefSym proc(match.second.kind());
1693-
cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
1781+
for (uint32_t id : ids) {
1782+
if (!resolved_ids.insert(id).second)
1783+
continue;
16941784

1695-
if (!IsValidRecord(proc))
1696-
continue;
1785+
PdbGlobalSymId global{id, false};
1786+
if (parent_decl_ctx.IsValid() &&
1787+
GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
1788+
continue;
16971789

1698-
CompilandIndexItem &cci =
1699-
m_index->compilands().GetOrCreateCompiland(proc.modi());
1700-
SymbolContext sc;
1790+
CVSymbol sym = m_index->ReadSymbolRecord(global);
1791+
auto kind = sym.kind();
1792+
lldbassert(kind == S_PROCREF || kind == S_LPROCREF);
17011793

1702-
sc.comp_unit = GetOrCreateCompileUnit(cci).get();
1703-
PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
1704-
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
1794+
ProcRefSym proc =
1795+
cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));
17051796

1706-
sc_list.Append(sc);
1707-
}
1797+
if (!IsValidRecord(proc))
1798+
continue;
1799+
1800+
CompilandIndexItem &cci =
1801+
m_index->compilands().GetOrCreateCompiland(proc.modi());
1802+
SymbolContext sc;
1803+
1804+
sc.comp_unit = GetOrCreateCompileUnit(cci).get();
1805+
if (!sc.comp_unit)
1806+
continue;
1807+
1808+
PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
1809+
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
1810+
if (!sc.function)
1811+
continue;
1812+
1813+
sc_list.Append(sc);
1814+
}
1815+
};
1816+
1817+
if (name_type_mask & eFunctionNameTypeFull)
1818+
resolve_from(m_func_full_names);
1819+
if (name_type_mask & eFunctionNameTypeBase)
1820+
resolve_from(m_func_base_names);
1821+
if (name_type_mask & eFunctionNameTypeMethod)
1822+
resolve_from(m_func_method_names);
17081823
}
17091824

17101825
void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,

lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
260260

261261
std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
262262

263+
void CacheFunctionNames();
264+
263265
llvm::BumpPtrAllocator m_allocator;
264266

265267
lldb::addr_t m_obj_load_address = 0;
@@ -282,6 +284,13 @@ class SymbolFileNativePDB : public SymbolFileCommon {
282284
m_parent_types;
283285

284286
lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
287+
288+
/// mangled name/full function name -> Global ID(s)
289+
lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
290+
/// basename -> Global ID(s)
291+
lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
292+
/// method basename -> Global ID(s)
293+
lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
285294
};
286295

287296
} // namespace npdb

lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,52 @@
66

77
// RUN: lldb-test symbols --find=function --name=main --function-flags=full %t.exe \
88
// RUN: | FileCheck %s --check-prefix=FIND-MAIN
9+
// RUN: lldb-test symbols --find=function --name=main --function-flags=method %t.exe \
10+
// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
11+
// RUN: lldb-test symbols --find=function --name=main --function-flags=base %t.exe \
12+
// RUN: | FileCheck %s --check-prefix=FIND-MAIN
913

1014
// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=full %t.exe \
1115
// RUN: | FileCheck %s --check-prefix=FIND-STATIC
16+
// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=method %t.exe \
17+
// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
18+
// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=base %t.exe \
19+
// RUN: | FileCheck %s --check-prefix=FIND-STATIC
1220

1321
// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=full %t.exe \
1422
// RUN: | FileCheck %s --check-prefix=FIND-VAR
23+
// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=method %t.exe \
24+
// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
25+
// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=base %t.exe \
26+
// RUN: | FileCheck %s --check-prefix=FIND-VAR
1527

1628
// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=full %t.exe \
1729
// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
30+
// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=method %t.exe \
31+
// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
32+
// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=base %t.exe \
33+
// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
1834

1935
// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=full %t.exe \
2036
// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
37+
// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=method %t.exe \
38+
// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
39+
// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=base %t.exe \
40+
// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
2141

2242
// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=full %t.exe \
2343
// RUN: | FileCheck %s --check-prefix=FIND-STATIC-METHOD
44+
// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=method %t.exe \
45+
// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
46+
// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=base %t.exe \
47+
// RUN: | FileCheck %s --check-prefix=FIND-STATIC-METHOD
2448

2549
// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=full %t.exe \
26-
// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD
50+
// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD-FULL
51+
// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=method %t.exe \
52+
// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD-METHOD
53+
// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=base %t.exe \
54+
// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD-BASE
2755

2856
struct Struct {
2957
int simple_method() {
@@ -51,7 +79,28 @@ struct Struct {
5179
}
5280
};
5381

82+
class Class {
83+
public:
84+
bool overloaded_method() {
85+
return false;
86+
}
87+
bool overloaded_method(int i) {
88+
return i > 0;
89+
}
90+
static int overloaded_method(bool b) {
91+
return b ? 1 : 2;
92+
}
93+
};
94+
95+
char overloaded_method() {
96+
return 0;
97+
}
98+
char overloaded_method(int i) {
99+
return 0;
100+
}
101+
54102
Struct s;
103+
Class c;
55104

56105
static int static_fn() {
57106
return 42;
@@ -63,12 +112,16 @@ int varargs_fn(int x, int y, ...) {
63112

64113
int main(int argc, char **argv) {
65114
return static_fn() + varargs_fn(argc, argc) + s.simple_method() +
66-
Struct::static_method() + s.virtual_method() + s.overloaded_method();
115+
Struct::static_method() + s.virtual_method() + s.overloaded_method() +
116+
Class::overloaded_method(false) + c.overloaded_method(1) + c.overloaded_method()
117+
+ overloaded_method() + overloaded_method(1);
67118
}
68119

69120
// FIND-MAIN: Function: id = {{.*}}, name = "main"
70121
// FIND-MAIN-NEXT: FuncType: id = {{.*}}, compiler_type = "int (int, char **)"
71122

123+
// FIND-NO-FUNCTION: Found 0 functions
124+
72125
// FIND-STATIC: Function: id = {{.*}}, name = "{{.*}}static_fn{{.*}}"
73126
// FIND-STATIC-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)"
74127

@@ -84,7 +137,29 @@ int main(int argc, char **argv) {
84137
// FIND-STATIC-METHOD: Function: id = {{.*}}, name = "{{.*}}Struct::static_method{{.*}}"
85138
// FIND-STATIC-METHOD-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)"
86139

87-
// FIND-OVERLOAD: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
88-
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (void)"
89-
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char)"
90-
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
140+
// FIND-OVERLOAD-FULL-NOT: "Class::overloaded_method"
141+
// FIND-OVERLOAD-FULL-NOT: "overloaded_method"
142+
// FIND-OVERLOAD-FULL-DAG: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
143+
// FIND-OVERLOAD-FULL-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
144+
// FIND-OVERLOAD-FULL-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
145+
// FIND-OVERLOAD-FULL-DAG: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
146+
147+
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
148+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
149+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
150+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
151+
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
152+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
153+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"
154+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (_Bool)"
155+
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "overloaded_method"
156+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (void)"
157+
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (int)"
158+
159+
// FIND-OVERLOAD-METHOD-NOT: "overloaded_method"
160+
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
161+
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
162+
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
163+
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
164+
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
165+
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"

0 commit comments

Comments
 (0)