Skip to content

Commit 5563ba0

Browse files
committed
[lldb] Lookup static const members in FindGlobalVariables
Static const members initialized inside a class definition might not have a corresponding DW_TAG_variable (DWARF 4 and earlier), so they're not indexed by ManualDWARFIndex. Add an additional lookup in FindGlobalVariables. Try looking up the enclosing type (e.g. foo::bar for foo::bar::A) and then searching for a static const member (A) within this type.
1 parent 545e059 commit 5563ba0

File tree

5 files changed

+191
-0
lines changed

5 files changed

+191
-0
lines changed

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,48 @@ void SymbolFileDWARF::FindGlobalVariables(
24392439
return variables.GetSize() - original_size < max_matches;
24402440
});
24412441

2442+
// If we don't have enough matches and the variable context is not empty, try
2443+
// to resolve the context as a type and look for static const members.
2444+
if (variables.GetSize() - original_size < max_matches && !context.empty()) {
2445+
llvm::StringRef type_name;
2446+
if (std::optional<Type::ParsedName> parsed_name =
2447+
Type::GetTypeScopeAndBasename(context))
2448+
type_name = parsed_name->basename;
2449+
else
2450+
type_name = context;
2451+
2452+
m_index->GetTypes(ConstString(type_name), [&](DWARFDIE parent) {
2453+
llvm::StringRef parent_type_name = parent.GetDWARFDeclContext()
2454+
.GetQualifiedNameAsConstString()
2455+
.GetStringRef();
2456+
2457+
// This type is from another scope, skip it.
2458+
if (!parent_type_name.ends_with(context))
2459+
return true;
2460+
2461+
auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(parent.GetCU());
2462+
if (!dwarf_cu)
2463+
return true;
2464+
2465+
sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);
2466+
2467+
for (DWARFDIE die = parent.GetFirstChild(); die.IsValid();
2468+
die = die.GetSibling()) {
2469+
// Try parsing the entry as a static const member.
2470+
if (auto var_sp = ParseStaticConstMemberDIE(sc, die)) {
2471+
if (var_sp->GetUnqualifiedName().GetStringRef() != basename)
2472+
continue;
2473+
2474+
// There can be only one member with a given name.
2475+
variables.AddVariableIfUnique(var_sp);
2476+
break;
2477+
}
2478+
}
2479+
2480+
return variables.GetSize() - original_size < max_matches;
2481+
});
2482+
}
2483+
24422484
// Return the number of variable that were appended to the list
24432485
const uint32_t num_matches = variables.GetSize() - original_size;
24442486
if (log && num_matches > 0) {
@@ -3371,6 +3413,93 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) {
33713413
return 0;
33723414
}
33733415

3416+
VariableSP SymbolFileDWARF::ParseStaticConstMemberDIE(
3417+
const lldb_private::SymbolContext &sc, const DWARFDIE &die) {
3418+
if (die.GetDWARF() != this)
3419+
return die.GetDWARF()->ParseStaticConstMemberDIE(sc, die);
3420+
3421+
// Look only for members, ignore all other types of entries.
3422+
if (die.Tag() != DW_TAG_member)
3423+
return nullptr;
3424+
3425+
if (VariableSP var_sp = GetDIEToVariable()[die.GetDIE()])
3426+
return var_sp; // Already been parsed!
3427+
3428+
const char *name = nullptr;
3429+
const char *mangled = nullptr;
3430+
Declaration decl;
3431+
DWARFExpression location;
3432+
DWARFFormValue type_die_form;
3433+
DWARFFormValue const_value_form;
3434+
3435+
DWARFAttributes attributes = die.GetAttributes();
3436+
const size_t num_attributes = attributes.Size();
3437+
3438+
for (size_t i = 0; i < num_attributes; ++i) {
3439+
dw_attr_t attr = attributes.AttributeAtIndex(i);
3440+
DWARFFormValue form_value;
3441+
3442+
if (!attributes.ExtractFormValueAtIndex(i, form_value))
3443+
continue;
3444+
3445+
switch (attr) {
3446+
case DW_AT_decl_file:
3447+
decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(
3448+
form_value.Unsigned()));
3449+
break;
3450+
case DW_AT_decl_line:
3451+
decl.SetLine(form_value.Unsigned());
3452+
break;
3453+
case DW_AT_decl_column:
3454+
decl.SetColumn(form_value.Unsigned());
3455+
break;
3456+
case DW_AT_name:
3457+
name = form_value.AsCString();
3458+
break;
3459+
case DW_AT_type:
3460+
type_die_form = form_value;
3461+
break;
3462+
case DW_AT_const_value:
3463+
const_value_form = form_value;
3464+
break;
3465+
default:
3466+
break;
3467+
}
3468+
}
3469+
3470+
// Look only for static const members with const values.
3471+
if (!DWARFFormValue::IsDataForm(const_value_form.Form()))
3472+
return nullptr;
3473+
3474+
SymbolFileTypeSP type_sp = std::make_shared<SymbolFileType>(
3475+
*this, type_die_form.Reference().GetID());
3476+
3477+
if (type_sp->GetType()) {
3478+
location.UpdateValue(const_value_form.Unsigned(),
3479+
type_sp->GetType()->GetByteSize(nullptr).value_or(0),
3480+
die.GetCU()->GetAddressByteSize());
3481+
}
3482+
3483+
if (Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU())))
3484+
mangled =
3485+
die.GetDWARFDeclContext().GetQualifiedNameAsConstString().GetCString();
3486+
3487+
ValueType scope = eValueTypeVariableGlobal;
3488+
Variable::RangeList scope_ranges;
3489+
3490+
DWARFExpressionList location_list(GetObjectFile()->GetModule(), location, die.GetCU());
3491+
VariableSP var_sp = std::make_shared<Variable>(
3492+
die.GetID(), name, mangled, type_sp, scope, sc.comp_unit, scope_ranges,
3493+
&decl, location_list, /*is_external*/ true, /*is_artificial*/ false,
3494+
/*is_static_member*/ true);
3495+
var_sp->SetLocationIsConstantValueData(true);
3496+
3497+
// Cache this variable, so we don't parse it over and over again.
3498+
GetDIEToVariable()[die.GetDIE()] = var_sp;
3499+
3500+
return var_sp;
3501+
}
3502+
33743503
VariableSP SymbolFileDWARF::ParseVariableDIECached(const SymbolContext &sc,
33753504
const DWARFDIE &die) {
33763505
if (!die)

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ class SymbolFileDWARF : public SymbolFileCommon {
408408
bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module,
409409
SupportFileList &support_files);
410410

411+
lldb::VariableSP
412+
ParseStaticConstMemberDIE(const SymbolContext &sc,
413+
const DWARFDIE &die);
414+
411415
lldb::VariableSP ParseVariableDIE(const SymbolContext &sc,
412416
const DWARFDIE &die,
413417
const lldb::addr_t func_low_pc);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CXX_SOURCES := main.cpp
2+
CXXFLAGS_EXTRAS := -gdwarf-4
3+
4+
include Makefile.rules
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
Test SBTarget::FindGlobalVariables API.
3+
"""
4+
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
8+
class TargetAPITestCase(TestBase):
9+
10+
mydir = TestBase.compute_mydir(__file__)
11+
12+
@add_test_categories(['pyapi'])
13+
def test_find_global_variables(self):
14+
"""Exercise SBTarget.FindGlobalVariables() API."""
15+
self.build()
16+
17+
# Don't need to launch a process, since we're only interested in
18+
# looking up global variables.
19+
target = self.dbg.CreateTarget(self.getBuildArtifact())
20+
21+
def test_global_var(query, name, type_name, value):
22+
value_list = target.FindGlobalVariables(query, 1)
23+
self.assertEqual(value_list.GetSize(), 1)
24+
var = value_list.GetValueAtIndex(0)
25+
self.DebugSBValue(var)
26+
self.assertTrue(var)
27+
self.assertEqual(var.GetName(), name)
28+
self.assertEqual(var.GetTypeName(), type_name)
29+
self.assertEqual(var.GetValue(), value)
30+
31+
test_global_var(
32+
"Vars::inline_static",
33+
"Vars::inline_static", "double", "1.5")
34+
test_global_var(
35+
"Vars::static_constexpr",
36+
"Vars::static_constexpr", "const int", "2")
37+
test_global_var(
38+
"Vars::static_const_out_out_class",
39+
"Vars::static_const_out_out_class", "const int", "3")
40+
test_global_var(
41+
"global_var_of_char_type",
42+
"::global_var_of_char_type", "char", "'X'")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Vars {
2+
public:
3+
inline static double inline_static = 1.5;
4+
static constexpr int static_constexpr = 2;
5+
static const int static_const_out_out_class;
6+
};
7+
8+
const int Vars::static_const_out_out_class = 3;
9+
10+
char global_var_of_char_type = 'X';
11+
12+
int main() {}

0 commit comments

Comments
 (0)