Skip to content

Commit a3d165a

Browse files
committed
[lldb][DWARFASTParserClang] Fetch constant value from variable definition if available
1 parent 19c0c0b commit a3d165a

File tree

5 files changed

+112
-6
lines changed

5 files changed

+112
-6
lines changed

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

+62-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "DWARFASTParser.h"
1212
#include "DWARFASTParserClang.h"
13+
#include "DWARFCompileUnit.h"
1314
#include "DWARFDebugInfo.h"
1415
#include "DWARFDeclContext.h"
1516
#include "DWARFDefines.h"
@@ -26,11 +27,13 @@
2627
#include "lldb/Core/Value.h"
2728
#include "lldb/Host/Host.h"
2829
#include "lldb/Symbol/CompileUnit.h"
30+
#include "lldb/Symbol/CompilerDeclContext.h"
2931
#include "lldb/Symbol/Function.h"
3032
#include "lldb/Symbol/ObjectFile.h"
3133
#include "lldb/Symbol/SymbolFile.h"
3234
#include "lldb/Symbol/TypeList.h"
3335
#include "lldb/Symbol/TypeMap.h"
36+
#include "lldb/Symbol/VariableList.h"
3437
#include "lldb/Target/Language.h"
3538
#include "lldb/Utility/LLDBAssert.h"
3639
#include "lldb/Utility/Log.h"
@@ -133,6 +136,52 @@ static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) {
133136
return lldb::ModuleSP();
134137
}
135138

139+
std::optional<DWARFFormValue>
140+
DWARFASTParserClang::FindConstantOnVariableDefinition(DWARFDIE die) {
141+
auto *dwarf = die.GetDWARF();
142+
if (!dwarf)
143+
return {};
144+
145+
ConstString name{die.GetName()};
146+
if (!name)
147+
return {};
148+
149+
auto *CU = die.GetCU();
150+
if (!CU)
151+
return {};
152+
153+
DWARFASTParser *dwarf_ast = dwarf->GetDWARFParser(*CU);
154+
auto parent_decl_ctx = dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
155+
156+
// Make sure we populate the GetDieToVariable cache.
157+
VariableList variables;
158+
dwarf->FindGlobalVariables(name, parent_decl_ctx, UINT_MAX, variables);
159+
160+
// The cache contains the variable definition whose DW_AT_specification
161+
// points to our declaration DIE. Look up that definition using our
162+
// declaration.
163+
auto const &die_to_var = dwarf->GetDIEToVariable();
164+
auto it = die_to_var.find(die.GetDIE());
165+
if (it == die_to_var.end())
166+
return {};
167+
168+
auto var_sp = it->getSecond();
169+
assert(var_sp != nullptr);
170+
171+
if (!var_sp->GetLocationIsConstantValueData())
172+
return {};
173+
174+
auto def = dwarf->GetDIE(var_sp->GetID());
175+
auto def_attrs = def.GetAttributes();
176+
DWARFFormValue form_value;
177+
if (!def_attrs.ExtractFormValueAtIndex(
178+
def_attrs.FindAttributeIndex(llvm::dwarf::DW_AT_const_value),
179+
form_value))
180+
return {};
181+
182+
return form_value;
183+
}
184+
136185
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
137186
const DWARFDIE &die,
138187
Log *log) {
@@ -2906,9 +2955,21 @@ void DWARFASTParserClang::ParseSingleMember(
29062955

29072956
bool unused;
29082957
// TODO: Support float/double static members as well.
2909-
if (!attrs.const_value_form || !ct.IsIntegerOrEnumerationType(unused))
2958+
if (!ct.IsIntegerOrEnumerationType(unused))
29102959
return;
29112960

2961+
// Newer versions of Clang don't emit the DW_AT_const_value
2962+
// on the declaration of a inline static data member. Instead
2963+
// it's attached to the definition DIE. If that's the case,
2964+
// try and fetch it.
2965+
if (!attrs.const_value_form) {
2966+
auto maybe_form_value = FindConstantOnVariableDefinition(die);
2967+
if (!maybe_form_value)
2968+
return;
2969+
2970+
attrs.const_value_form = *maybe_form_value;
2971+
}
2972+
29122973
llvm::Expected<llvm::APInt> const_value_or_err =
29132974
ExtractIntFromFormValue(ct, *attrs.const_value_form);
29142975
if (!const_value_or_err) {

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

+3
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
373373
lldb_private::CompilerType &class_clang_type,
374374
const lldb::AccessType default_accesibility,
375375
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
376+
377+
std::optional<lldb_private::plugin::dwarf::DWARFFormValue>
378+
FindConstantOnVariableDefinition(lldb_private::plugin::dwarf::DWARFDIE die);
376379
};
377380

378381
/// Parsed form of all attributes that are relevant for type reconstruction.

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,11 @@ class SymbolFileDWARF : public SymbolFileCommon {
342342
return m_forward_decl_compiler_type_to_die;
343343
}
344344

345+
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
346+
DIEToVariableSP;
347+
348+
virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; }
349+
345350
virtual UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap();
346351

347352
bool ClassOrStructIsVirtual(const DWARFDIE &die);
@@ -361,9 +366,6 @@ class SymbolFileDWARF : public SymbolFileCommon {
361366
Type *ResolveTypeUID(const DIERef &die_ref);
362367

363368
protected:
364-
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
365-
DIEToVariableSP;
366-
367369
SymbolFileDWARF(const SymbolFileDWARF &) = delete;
368370
const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete;
369371

@@ -487,8 +489,6 @@ class SymbolFileDWARF : public SymbolFileCommon {
487489

488490
void UpdateExternalModuleListIfNeeded();
489491

490-
virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; }
491-
492492
void BuildCuTranslationTable();
493493
std::optional<uint32_t> GetDWARFUnitIndex(uint32_t cu_idx);
494494

lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py

+21
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,24 @@ def test_class_with_only_constexpr_static(self):
138138
self.expect_expr(
139139
"ClassWithEnumAlias::enum_alias_alias", result_value="scoped_enum_case1"
140140
)
141+
142+
def test_shadowed_static_inline_members(self):
143+
"""Tests that the expression evaluator and SBAPI can both
144+
correctly determine the requested inline static variable
145+
in the presence of multiple variables of the same name."""
146+
147+
self.build()
148+
lldbutil.run_to_name_breakpoint(self, "bar")
149+
150+
self.check_global_var("ns::Foo::mem", "const int", "10")
151+
152+
self.expect_expr("mem", result_value="10")
153+
self.expect_expr("Foo::mem", result_value="10")
154+
self.expect_expr("ns::Foo::mem", result_value="10")
155+
self.expect_expr("::Foo::mem", result_value="-29")
156+
157+
@expectedFailureAll(bugnumber="target var doesn't honour global namespace")
158+
def test_shadowed_static_inline_members_xfail(self):
159+
self.build()
160+
lldbutil.run_to_name_breakpoint(self, "bar")
161+
self.check_global_var("::Foo::mem", "const int", "-29")

lldb/test/API/lang/cpp/const_static_integral_member/main.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <cstdio>
12
#include <limits>
23

34
enum Enum {
@@ -89,6 +90,25 @@ struct ClassWithEnumAlias {
8990
ScopedEnum::scoped_enum_case1;
9091
};
9192

93+
namespace ns {
94+
struct Foo {
95+
constexpr static int mem = 10;
96+
97+
void bar() { return; }
98+
};
99+
} // namespace ns
100+
101+
struct Foo {
102+
constexpr static int mem = -29;
103+
};
104+
105+
int func() {
106+
Foo f1;
107+
ns::Foo f2;
108+
f2.bar();
109+
return ns::Foo::mem + Foo::mem;
110+
}
111+
92112
int main() {
93113
A a;
94114

@@ -124,6 +144,7 @@ int main() {
124144

125145
auto enum_alias_val = ClassWithEnumAlias::enum_alias;
126146
auto enum_alias_alias_val = ClassWithEnumAlias::enum_alias_alias;
147+
auto ret = func();
127148

128149
return 0; // break here
129150
}

0 commit comments

Comments
 (0)