Improve detection of global vs local variables

Summary:
Improve detection of global vs local variables.

Currently when a global variable is optimized out or otherwise has an unknown
location (DW_AT_location is empty) it gets reported as local.

I added two new heuristics:
 - if a mangled name is present, the variable is global (or static)
 - if DW_AT_location is present but invalid, the variable is global (or static)

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D26908

llvm-svn: 287636
This commit is contained in:
Sam McCall 2016-11-22 11:40:25 +00:00
parent 72e43570b7
commit 30621391bc
1 changed files with 16 additions and 12 deletions

View File

@ -3873,6 +3873,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die); const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
SymbolContextScope *symbol_context_scope = NULL; SymbolContextScope *symbol_context_scope = NULL;
bool has_explicit_mangled = mangled != nullptr;
if (!mangled) { if (!mangled) {
// LLDB relies on the mangled name (DW_TAG_linkage_name or // LLDB relies on the mangled name (DW_TAG_linkage_name or
// DW_AT_MIPS_linkage_name) to // DW_AT_MIPS_linkage_name) to
@ -3894,23 +3895,24 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
} }
} }
// DWARF doesn't specify if a DW_TAG_variable is a local, global
// or static variable, so we have to do a little digging by
// looking at the location of a variable to see if it contains
// a DW_OP_addr opcode _somewhere_ in the definition. I say
// somewhere because clang likes to combine small global variables
// into the same symbol and have locations like:
// DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
// So if we don't have a DW_TAG_formal_parameter, we can look at
// the location to see if it contains a DW_OP_addr opcode, and
// then we can correctly classify our variables.
if (tag == DW_TAG_formal_parameter) if (tag == DW_TAG_formal_parameter)
scope = eValueTypeVariableArgument; scope = eValueTypeVariableArgument;
else { else {
bool op_error = false; // DWARF doesn't specify if a DW_TAG_variable is a local, global
// or static variable, so we have to do a little digging:
// 1) DW_AT_linkage_name implies static lifetime (but may be missing)
// 2) An empty DW_AT_location is an (optimized-out) static lifetime var.
// 3) DW_AT_location containing a DW_OP_addr implies static lifetime.
// Clang likes to combine small global variables into the same symbol
// with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
// so we need to look through the whole expression.
bool is_static_lifetime =
has_explicit_mangled ||
(has_explicit_location && !location.IsValid());
// Check if the location has a DW_OP_addr with any address value... // Check if the location has a DW_OP_addr with any address value...
lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
if (!location_is_const_value_data) { if (!location_is_const_value_data) {
bool op_error = false;
location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error); location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error);
if (op_error) { if (op_error) {
StreamString strm; StreamString strm;
@ -3920,10 +3922,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
"0x%8.8x: %s has an invalid location: %s", die.GetOffset(), "0x%8.8x: %s has an invalid location: %s", die.GetOffset(),
die.GetTagAsCString(), strm.GetData()); die.GetTagAsCString(), strm.GetData());
} }
if (location_DW_OP_addr != LLDB_INVALID_ADDRESS)
is_static_lifetime = true;
} }
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) { if (is_static_lifetime) {
if (is_external) if (is_external)
scope = eValueTypeVariableGlobal; scope = eValueTypeVariableGlobal;
else else