Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,48 @@ void SymbolFileDWARF::FindGlobalVariables(
return variables.GetSize() - original_size < max_matches;
});

// If we don't have enough matches and the variable context is not empty, try
// to resolve the context as a type and look for static const members.
if (variables.GetSize() - original_size < max_matches && !context.empty()) {
llvm::StringRef type_name;
if (std::optional<Type::ParsedName> parsed_name =
Type::GetTypeScopeAndBasename(context))
type_name = parsed_name->basename;
else
type_name = context;

m_index->GetTypes(ConstString(type_name), [&](DWARFDIE parent) {
llvm::StringRef parent_type_name = parent.GetDWARFDeclContext()
.GetQualifiedNameAsConstString()
.GetStringRef();

// This type is from another scope, skip it.
if (!parent_type_name.ends_with(context))
return true;

auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(parent.GetCU());
if (!dwarf_cu)
return true;

sc.comp_unit = GetCompUnitForDWARFCompUnit(*dwarf_cu);

for (DWARFDIE die = parent.GetFirstChild(); die.IsValid();
die = die.GetSibling()) {
// Try parsing the entry as a static const member.
if (auto var_sp = ParseStaticConstMemberDIE(sc, die)) {
if (var_sp->GetUnqualifiedName().GetStringRef() != basename)
continue;

// There can be only one member with a given name.
variables.AddVariableIfUnique(var_sp);
break;
}
}

return variables.GetSize() - original_size < max_matches;
});
}

// Return the number of variable that were appended to the list
const uint32_t num_matches = variables.GetSize() - original_size;
if (log && num_matches > 0) {
Expand Down Expand Up @@ -3371,6 +3413,94 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) {
return 0;
}

VariableSP SymbolFileDWARF::ParseStaticConstMemberDIE(
const lldb_private::SymbolContext &sc, const DWARFDIE &die) {
if (die.GetDWARF() != this)
return die.GetDWARF()->ParseStaticConstMemberDIE(sc, die);

// Look only for members, ignore all other types of entries.
if (die.Tag() != DW_TAG_member)
return nullptr;

if (VariableSP var_sp = GetDIEToVariable()[die.GetDIE()])
return var_sp; // Already been parsed!

const char *name = nullptr;
const char *mangled = nullptr;
Declaration decl;
DWARFExpression location;
DWARFFormValue type_die_form;
DWARFFormValue const_value_form;

DWARFAttributes attributes = die.GetAttributes();
const size_t num_attributes = attributes.Size();

for (size_t i = 0; i < num_attributes; ++i) {
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;

if (!attributes.ExtractFormValueAtIndex(i, form_value))
continue;

switch (attr) {
case DW_AT_decl_file:
decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(
form_value.Unsigned()));
break;
case DW_AT_decl_line:
decl.SetLine(form_value.Unsigned());
break;
case DW_AT_decl_column:
decl.SetColumn(form_value.Unsigned());
break;
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_type:
type_die_form = form_value;
break;
case DW_AT_const_value:
const_value_form = form_value;
break;
default:
break;
}
}

// Look only for static const members with const values.
if (!DWARFFormValue::IsDataForm(const_value_form.Form()))
return nullptr;

SymbolFileTypeSP type_sp = std::make_shared<SymbolFileType>(
*this, type_die_form.Reference().GetID());

if (type_sp->GetType()) {
location.UpdateValue(const_value_form.Unsigned(),
type_sp->GetType()->GetByteSize(nullptr).value_or(0),
die.GetCU()->GetAddressByteSize());
}

if (Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU())))
mangled =
die.GetDWARFDeclContext().GetQualifiedNameAsConstString().GetCString();

ValueType scope = eValueTypeVariableGlobal;
Variable::RangeList scope_ranges;

DWARFExpressionList location_list(GetObjectFile()->GetModule(), location,
die.GetCU());
VariableSP var_sp = std::make_shared<Variable>(
die.GetID(), name, mangled, type_sp, scope, sc.comp_unit, scope_ranges,
&decl, location_list, /*is_external*/ true, /*is_artificial*/ false,
/*is_static_member*/ true);
var_sp->SetLocationIsConstantValueData(true);

// Cache this variable, so we don't parse it over and over again.
GetDIEToVariable()[die.GetDIE()] = var_sp;

return var_sp;
}

VariableSP SymbolFileDWARF::ParseVariableDIECached(const SymbolContext &sc,
const DWARFDIE &die) {
if (!die)
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
bool ParseSupportFiles(DWARFUnit &dwarf_cu, const lldb::ModuleSP &module,
SupportFileList &support_files);

lldb::VariableSP ParseStaticConstMemberDIE(const SymbolContext &sc,
const DWARFDIE &die);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused


lldb::VariableSP ParseVariableDIE(const SymbolContext &sc,
const DWARFDIE &die,
const lldb::addr_t func_low_pc);
Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/python_api/frame/globals/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CXX_SOURCES := main.cpp
CXXFLAGS_EXTRAS := -gdwarf-4

include Makefile.rules
43 changes: 43 additions & 0 deletions lldb/test/API/python_api/frame/globals/TestTargetGlobals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
Test SBTarget::FindGlobalVariables API.
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we re-use TestConstStaticIntegralMember.py? Surprised it doesn't already have the tests added here XFAILed


from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *


class TargetAPITestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)

@add_test_categories(["pyapi"])
def test_find_global_variables(self):
"""Exercise SBTarget.FindGlobalVariables() API."""
self.build()

# Don't need to launch a process, since we're only interested in
# looking up global variables.
target = self.dbg.CreateTarget(self.getBuildArtifact())

def test_global_var(query, name, type_name, value):
value_list = target.FindGlobalVariables(query, 1)
self.assertEqual(value_list.GetSize(), 1)
var = value_list.GetValueAtIndex(0)
self.DebugSBValue(var)
self.assertTrue(var)
self.assertEqual(var.GetName(), name)
self.assertEqual(var.GetTypeName(), type_name)
self.assertEqual(var.GetValue(), value)

test_global_var("Vars::inline_static", "Vars::inline_static", "double", "1.5")
test_global_var(
"Vars::static_constexpr", "Vars::static_constexpr", "const int", "2"
)
test_global_var(
"Vars::static_const_out_out_class",
"Vars::static_const_out_out_class",
"const int",
"3",
)
test_global_var(
"global_var_of_char_type", "::global_var_of_char_type", "char", "'X'"
)
12 changes: 12 additions & 0 deletions lldb/test/API/python_api/frame/globals/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Vars {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets remove this new test given we adjusted the existing ones

public:
inline static double inline_static = 1.5;
static constexpr int static_constexpr = 2;
static const int static_const_out_out_class;
};

const int Vars::static_const_out_out_class = 3;

char global_var_of_char_type = 'X';

int main() {}
Loading