https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/111859
>From 4c394ec162b58b3cde3af924a5e9be1de8250a07 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Tue, 30 Jul 2024 17:02:10 +0500 Subject: [PATCH] [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. --- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 130 ++++++++++++++++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 3 + .../API/python_api/frame/globals/Makefile | 4 + .../frame/globals/TestTargetGlobals.py | 43 ++++++ .../API/python_api/frame/globals/main.cpp | 12 ++ 5 files changed, 192 insertions(+) create mode 100644 lldb/test/API/python_api/frame/globals/Makefile create mode 100644 lldb/test/API/python_api/frame/globals/TestTargetGlobals.py create mode 100644 lldb/test/API/python_api/frame/globals/main.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 9287d4baf19e9c..d53da79c1efcee 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -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) { @@ -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) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 4967b37d753a09..380b5d4a289300 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -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); + lldb::VariableSP ParseVariableDIE(const SymbolContext &sc, const DWARFDIE &die, const lldb::addr_t func_low_pc); diff --git a/lldb/test/API/python_api/frame/globals/Makefile b/lldb/test/API/python_api/frame/globals/Makefile new file mode 100644 index 00000000000000..c24259ec8c9d93 --- /dev/null +++ b/lldb/test/API/python_api/frame/globals/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -gdwarf-4 + +include Makefile.rules diff --git a/lldb/test/API/python_api/frame/globals/TestTargetGlobals.py b/lldb/test/API/python_api/frame/globals/TestTargetGlobals.py new file mode 100644 index 00000000000000..54d2cd89560a1a --- /dev/null +++ b/lldb/test/API/python_api/frame/globals/TestTargetGlobals.py @@ -0,0 +1,43 @@ +""" +Test SBTarget::FindGlobalVariables API. +""" + +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'" + ) \ No newline at end of file diff --git a/lldb/test/API/python_api/frame/globals/main.cpp b/lldb/test/API/python_api/frame/globals/main.cpp new file mode 100644 index 00000000000000..e2095e80082677 --- /dev/null +++ b/lldb/test/API/python_api/frame/globals/main.cpp @@ -0,0 +1,12 @@ +class Vars { +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() {} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits