Skip to content

Commit bdb9283

Browse files
authored
[LLDB][NativePDB] Find global variables in namespaces (#156736)
To find global variables, `SymbolFileNativePDB` used to search the globals stream for the name passed to `FindGlobalVariables`. However, the symbols in the globals stream contain the fully qualified name and `FindGlobalVariables` only gets the basename. The approach here is similar to the one for types and functions. As we already search the globals stream for functions, we can cache the basenames for global variables there as well. This makes the `expressions.test` from the DIA PDB plugin pass with the native one (#114906).
1 parent 31a6fed commit bdb9283

File tree

3 files changed

+81
-30
lines changed

3 files changed

+81
-30
lines changed

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

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,22 +1655,62 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
16551655
clang->GetNativePDBParser()->Dump(s, filter);
16561656
}
16571657

1658-
void SymbolFileNativePDB::CacheFunctionNames() {
1659-
if (!m_func_full_names.IsEmpty())
1658+
void SymbolFileNativePDB::CacheGlobalBaseNames() {
1659+
if (!m_func_full_names.IsEmpty() || !m_global_variable_base_names.IsEmpty())
16601660
return;
16611661

16621662
// (segment, code offset) -> gid
1663-
std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;
1663+
std::map<std::pair<uint16_t, uint32_t>, uint32_t> func_addr_ids;
16641664

1665-
// First, find all function references in the globals table.
1665+
// First, look through all items in the globals table.
16661666
for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
1667-
CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
1668-
auto kind = ref_sym.kind();
1667+
CVSymbol sym = m_index->symrecords().readRecord(gid);
1668+
auto kind = sym.kind();
1669+
1670+
// If this is a global variable, we only need to look at the name
1671+
llvm::StringRef name;
1672+
switch (kind) {
1673+
case SymbolKind::S_GDATA32:
1674+
case SymbolKind::S_LDATA32: {
1675+
DataSym data =
1676+
llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym));
1677+
name = data.Name;
1678+
break;
1679+
}
1680+
case SymbolKind::S_GTHREAD32:
1681+
case SymbolKind::S_LTHREAD32: {
1682+
ThreadLocalDataSym data = llvm::cantFail(
1683+
SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym));
1684+
name = data.Name;
1685+
break;
1686+
}
1687+
case SymbolKind::S_CONSTANT: {
1688+
ConstantSym data =
1689+
llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym));
1690+
name = data.Name;
1691+
break;
1692+
}
1693+
default:
1694+
break;
1695+
}
1696+
1697+
if (!name.empty()) {
1698+
llvm::StringRef base = MSVCUndecoratedNameParser::DropScope(name);
1699+
if (base.empty())
1700+
base = name;
1701+
1702+
m_global_variable_base_names.Append(ConstString(base), gid);
1703+
continue;
1704+
}
1705+
16691706
if (kind != S_PROCREF && kind != S_LPROCREF)
16701707
continue;
16711708

1709+
// For functions, we need to follow the reference to the procedure and look
1710+
// at the type
1711+
16721712
ProcRefSym ref =
1673-
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
1713+
llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));
16741714
if (ref.Name.empty())
16751715
continue;
16761716

@@ -1694,7 +1734,7 @@ void SymbolFileNativePDB::CacheFunctionNames() {
16941734
// The function/procedure symbol only contains the demangled name.
16951735
// The mangled names are in the publics table. Save the address of this
16961736
// function to lookup the mangled name later.
1697-
addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
1737+
func_addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
16981738

16991739
llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
17001740
if (basename.empty())
@@ -1729,8 +1769,8 @@ void SymbolFileNativePDB::CacheFunctionNames() {
17291769
continue;
17301770

17311771
// Check if this symbol is for one of our functions.
1732-
auto it = addr_ids.find({pub.Segment, pub.Offset});
1733-
if (it != addr_ids.end())
1772+
auto it = func_addr_ids.find({pub.Segment, pub.Offset});
1773+
if (it != func_addr_ids.end())
17341774
m_func_full_names.Append(ConstString(pub.Name), it->second);
17351775
}
17361776

@@ -1741,31 +1781,35 @@ void SymbolFileNativePDB::CacheFunctionNames() {
17411781
m_func_method_names.SizeToFit();
17421782
m_func_base_names.Sort(std::less<uint32_t>());
17431783
m_func_base_names.SizeToFit();
1784+
m_global_variable_base_names.Sort(std::less<uint32_t>());
1785+
m_global_variable_base_names.SizeToFit();
17441786
}
17451787

17461788
void SymbolFileNativePDB::FindGlobalVariables(
17471789
ConstString name, const CompilerDeclContext &parent_decl_ctx,
17481790
uint32_t max_matches, VariableList &variables) {
17491791
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
1750-
using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
17511792

1752-
std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(
1753-
name.GetStringRef(), m_index->symrecords());
1754-
for (const SymbolAndOffset &result : results) {
1755-
switch (result.second.kind()) {
1756-
case SymbolKind::S_GDATA32:
1757-
case SymbolKind::S_LDATA32:
1758-
case SymbolKind::S_GTHREAD32:
1759-
case SymbolKind::S_LTHREAD32:
1760-
case SymbolKind::S_CONSTANT: {
1761-
PdbGlobalSymId global(result.first, false);
1762-
if (VariableSP var = GetOrCreateGlobalVariable(global))
1763-
variables.AddVariable(var);
1764-
break;
1765-
}
1766-
default:
1793+
CacheGlobalBaseNames();
1794+
1795+
std::vector<uint32_t> results;
1796+
m_global_variable_base_names.GetValues(name, results);
1797+
1798+
size_t n_matches = 0;
1799+
for (uint32_t gid : results) {
1800+
PdbGlobalSymId global(gid, false);
1801+
1802+
if (parent_decl_ctx.IsValid() &&
1803+
GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
17671804
continue;
1768-
}
1805+
1806+
VariableSP var = GetOrCreateGlobalVariable(global);
1807+
if (!var)
1808+
continue;
1809+
variables.AddVariable(var);
1810+
1811+
if (++n_matches >= max_matches)
1812+
break;
17691813
}
17701814
}
17711815

@@ -1783,7 +1827,7 @@ void SymbolFileNativePDB::FindFunctions(
17831827
name_type_mask & eFunctionNameTypeBase ||
17841828
name_type_mask & eFunctionNameTypeMethod))
17851829
return;
1786-
CacheFunctionNames();
1830+
CacheGlobalBaseNames();
17871831

17881832
std::set<uint32_t> resolved_ids; // avoid duplicate lookups
17891833
auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,10 @@ class SymbolFileNativePDB : public SymbolFileCommon {
260260

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

263-
void CacheFunctionNames();
263+
/// Caches the basenames of symbols found in the globals stream.
264+
///
265+
/// This includes functions and global variables
266+
void CacheGlobalBaseNames();
264267

265268
void CacheUdtDeclarations();
266269
llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);
@@ -306,6 +309,9 @@ class SymbolFileNativePDB : public SymbolFileCommon {
306309
lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
307310
/// method basename -> Global ID(s)
308311
lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
312+
313+
/// global variable basename -> Global ID(s)
314+
lldb_private::UniqueCStringMap<uint32_t> m_global_variable_base_names;
309315
};
310316

311317
} // namespace npdb

lldb/test/Shell/SymbolFile/PDB/expressions.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
REQUIRES: target-windows, msvc
22
RUN: %build --compiler=msvc --nodefaultlib --output=%t.exe %S/Inputs/ExpressionsTest.cpp
3-
RUN: not %lldb -b -s %S/Inputs/ExpressionsTest0.script -s %S/Inputs/ExpressionsTest1.script -s %S/Inputs/ExpressionsTest2.script -- %t.exe 2>&1 | FileCheck %s
3+
RUN: env LLDB_USE_NATIVE_PDB_READER=0 not %lldb -b -s %S/Inputs/ExpressionsTest0.script -s %S/Inputs/ExpressionsTest1.script -s %S/Inputs/ExpressionsTest2.script -- %t.exe 2>&1 | FileCheck %s
4+
RUN: env LLDB_USE_NATIVE_PDB_READER=1 not %lldb -b -s %S/Inputs/ExpressionsTest0.script -s %S/Inputs/ExpressionsTest1.script -s %S/Inputs/ExpressionsTest2.script -- %t.exe 2>&1 | FileCheck %s
45

56
// Check the variable value through `expression`
67
CHECK: (lldb) expression result

0 commit comments

Comments
 (0)