diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -152,6 +152,7 @@ case DW_TAG_constant: case DW_TAG_enumeration_type: case DW_TAG_inlined_subroutine: + case DW_TAG_member: case DW_TAG_namespace: case DW_TAG_string_type: case DW_TAG_structure_type: @@ -303,8 +304,10 @@ set.namespaces.Insert(ConstString(name), ref); break; + case DW_TAG_member: case DW_TAG_variable: - if (name && has_location_or_const_value && is_global_or_static_variable) { + if (name && has_location_or_const_value && + (is_global_or_static_variable || tag == DW_TAG_member)) { set.globals.Insert(ConstString(name), ref); // Be sure to include variables by their mangled and demangled names if // they have any since a variable can have a basename "i", a mangled diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2120,7 +2120,8 @@ sc.module_sp = m_objfile_sp->GetModule(); assert(sc.module_sp); - if (die.Tag() != DW_TAG_variable) + // Look only for variables and members with static const data. + if (die.Tag() != DW_TAG_variable && die.Tag() != DW_TAG_member) return true; auto *dwarf_cu = llvm::dyn_cast(die.GetCU()); @@ -3103,7 +3104,7 @@ ModuleSP module = GetObjectFile()->GetModule(); if (tag != DW_TAG_variable && tag != DW_TAG_constant && - (tag != DW_TAG_formal_parameter || !sc.function)) + tag != DW_TAG_member && (tag != DW_TAG_formal_parameter || !sc.function)) return nullptr; DWARFAttributes attributes; @@ -3177,6 +3178,12 @@ } } + if (tag == DW_TAG_member && !const_value_form.IsValid()) { + // Allows only members with DW_AT_const_value attribute, i.e. static const + // or static constexr. + return nullptr; + } + // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g. // for static constexpr member variables -- DW_AT_const_value will be // present in the class declaration and DW_AT_location in the DIE defining @@ -3236,10 +3243,11 @@ const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); const dw_tag_t parent_tag = die.GetParent().Tag(); - bool is_static_member = (parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && - (parent_context_die.Tag() == DW_TAG_class_type || - parent_context_die.Tag() == DW_TAG_structure_type); + bool is_static_member = + (parent_tag == DW_TAG_compile_unit || parent_tag == DW_TAG_partial_unit || + tag == DW_TAG_member) && + (parent_context_die.Tag() == DW_TAG_class_type || + parent_context_die.Tag() == DW_TAG_structure_type); ValueType scope = eValueTypeInvalid; @@ -3259,7 +3267,7 @@ // able to generate a fully qualified name from the // declaration context. if ((parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && + parent_tag == DW_TAG_partial_unit || tag == DW_TAG_member) && Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) mangled = GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString(); @@ -3367,7 +3375,8 @@ } } else { if (location_is_const_value_data && - die.GetDIE()->IsGlobalOrStaticScopeVariable()) + (die.GetDIE()->IsGlobalOrStaticScopeVariable() || + tag == DW_TAG_member)) scope = eValueTypeVariableStatic; else { scope = eValueTypeVariableLocal; @@ -3506,6 +3515,7 @@ } else { // We haven't already parsed it, lets do that now. if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) || + (tag == DW_TAG_member) || (tag == DW_TAG_formal_parameter && sc.function)) { if (variable_list_sp.get() == nullptr) { DWARFDIE sc_parent_die = GetParentSymbolContextDIE(orig_die); diff --git a/lldb/test/API/python_api/target/globals/Makefile b/lldb/test/API/python_api/target/globals/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/python_api/target/globals/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/python_api/target/globals/TestTargetGlobals.py b/lldb/test/API/python_api/target/globals/TestTargetGlobals.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/python_api/target/globals/TestTargetGlobals.py @@ -0,0 +1,49 @@ +""" +Test SBTarget::FindGlobalVariables API. +""" + +import unittest2 +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TargetAPITestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + @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( + "Foo::static_constexpr_int", + "Foo::static_constexpr_int", "const int", "1") + test_global_var( + "Foo::static_constexpr_uint", + "Foo::static_constexpr_uint", "const unsigned int", "2") + test_global_var( + "Foo::static_const_out_out_class", + "Foo::static_const_out_out_class", "const int", "3") + test_global_var( + "global_var_of_char_type", + "::global_var_of_char_type", "char", "'X'") diff --git a/lldb/test/API/python_api/target/globals/main.cpp b/lldb/test/API/python_api/target/globals/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/python_api/target/globals/main.cpp @@ -0,0 +1,15 @@ +struct Foo { + static constexpr int static_constexpr_int = 1; + static constexpr unsigned int static_constexpr_uint = + static_constexpr_int + 1; + static const int static_const_out_out_class; +}; + +const int Foo::static_const_out_out_class = 3; + +char global_var_of_char_type = 'X'; + +int main() { + // Set a break at entry to main. + return 0; +}