[lldb] Fix lookup for global constants in namespaces

LLDB uses mangled name to construct a fully qualified name for global
variables. Sometimes DW_TAG_linkage_name attribute is missing from
debug info, so LLDB has to rely on parent entries to construct the
fully qualified name.

Currently, the fallback is handled when the parent DW_TAG is either
DW_TAG_compiled_unit or DW_TAG_partial_unit, which may not work well
for global constants in namespaces. For example:

  namespace ns {
    const int x = 10;
  }

may produce the following debug info:

  <1><2a>: Abbrev Number: 2 (DW_TAG_namespace)
     <2b>   DW_AT_name        : (indirect string, offset: 0x5e): ns
  <2><2f>: Abbrev Number: 3 (DW_TAG_variable)
     <30>   DW_AT_name        : (indirect string, offset: 0x61): x
     <34>   DW_AT_type        : <0x3c>
     <38>   DW_AT_decl_file   : 1
     <39>   DW_AT_decl_line   : 2
     <3a>   DW_AT_const_value : 10

Since the fallback didn't handle the case when parent tag is
DW_TAG_namespace, LLDB wasn't able to match the variable by its fully
qualified name "ns::x". This change fixes this by additional check
if the parent is a DW_TAG_namespace.

Reviewed By: werat, clayborg

Differential Revision: https://reviews.llvm.org/D112147
This commit is contained in:
Tonko Sabolčec 2021-11-23 12:43:46 +01:00 committed by Andy Yankovsky
parent 5ee625bf6b
commit f66b69a392
3 changed files with 36 additions and 7 deletions

View file

@ -3271,15 +3271,14 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
}
const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die);
const dw_tag_t parent_tag = die.GetParent().Tag();
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
const dw_tag_t parent_tag = sc_parent_die.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);
ValueType scope = eValueTypeInvalid;
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
SymbolContextScope *symbol_context_scope = nullptr;
bool has_explicit_mangled = mangled != nullptr;

View file

@ -15,12 +15,11 @@ class GlobalVariablesCppTestCase(TestBase):
TestBase.setUp(self)
self.source = lldb.SBFileSpec('main.cpp')
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
def test(self):
self.build()
(target, _, _, _) = lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", self.source)
# Check that we can access g_file_global_int by its name
self.expect("target variable g_file_global_int", VARIABLES_DISPLAYED_CORRECTLY,
substrs=['42'])
@ -29,6 +28,30 @@ class GlobalVariablesCppTestCase(TestBase):
self.expect("target variable xyz::g_file_global_int", VARIABLES_DISPLAYED_CORRECTLY,
error=True, substrs=['can\'t find global variable'])
# Check that we can access g_file_global_const_int by its name
self.expect("target variable g_file_global_const_int", VARIABLES_DISPLAYED_CORRECTLY,
substrs=['1337'])
self.expect("target variable abc::g_file_global_const_int", VARIABLES_DISPLAYED_CORRECTLY,
substrs=['1337'])
self.expect("target variable xyz::g_file_global_const_int", VARIABLES_DISPLAYED_CORRECTLY,
error=True, substrs=['can\'t find global variable'])
# Try accessing a global variable in anonymous namespace.
self.expect("target variable g_anon_namespace_const_int", VARIABLES_DISPLAYED_CORRECTLY,
substrs=['100'])
self.expect("target variable abc::g_anon_namespace_const_int", VARIABLES_DISPLAYED_CORRECTLY,
error=True, substrs=['can\'t find global variable'])
var = target.FindFirstGlobalVariable("abc::(anonymous namespace)::g_anon_namespace_const_int")
self.assertTrue(var.IsValid())
self.assertEqual(var.GetName(), "abc::(anonymous namespace)::g_anon_namespace_const_int")
self.assertEqual(var.GetValue(), "100")
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24764")
def test_access_by_mangled_name(self):
self.build()
(target, _, _, _) = lldbutil.run_to_source_breakpoint(self, "// Set break point at this line.", self.source)
# Check that we can access g_file_global_int by its mangled name
addr = target.EvaluateExpression("&abc::g_file_global_int").GetValueAsUnsigned()
self.assertNotEqual(addr, 0)

View file

@ -1,10 +1,17 @@
#include <stdio.h>
namespace abc {
int g_file_global_int = 42;
int g_file_global_int = 42;
const int g_file_global_const_int = 1337;
namespace {
const int g_anon_namespace_const_int = 100;
}
}
int main (int argc, char const *argv[])
{
return abc::g_file_global_int; // Set break point at this line.
int unused = abc::g_file_global_const_int;
int unused2 = abc::g_anon_namespace_const_int;
return abc::g_file_global_int; // Set break point at this line.
}