Handle the case when a variable is only valid in part of the enclosing scope

DWARF stores this information in the DW_AT_start_scope attribute. This
CL add support for this attribute and also changes the functions
displaying frame variables to only display the variables currently in
scope.

Differential revision: http://reviews.llvm.org/D17449

llvm-svn: 261858
This commit is contained in:
Tamas Berghammer 2016-02-25 12:23:37 +00:00
parent 2e4c72977c
commit 72ac8a840f
10 changed files with 130 additions and 32 deletions

View File

@ -202,7 +202,13 @@ namespace lldb_private {
{
m_entries.push_back (entry);
}
void
Append (B base, S size)
{
m_entries.emplace_back(base, size);
}
bool
RemoveEntrtAtIndex (uint32_t idx)
{
@ -471,7 +477,13 @@ namespace lldb_private {
{
m_entries.push_back (entry);
}
void
Append (B base, S size)
{
m_entries.emplace_back(base, size);
}
bool
RemoveEntrtAtIndex (uint32_t idx)
{

View File

@ -310,8 +310,9 @@ public:
AppendBlockVariables (bool can_create,
bool get_child_block_variables,
bool stop_if_child_block_is_inlined_function,
const std::function<bool(Variable*)>& filter,
VariableList *variable_list);
//------------------------------------------------------------------
/// Appends the variables from this block, and optionally from all
/// parent blocks, to \a variable_list.
@ -341,9 +342,10 @@ public:
/// variable_list.
//------------------------------------------------------------------
uint32_t
AppendVariables (bool can_create,
bool get_parent_variables,
AppendVariables (bool can_create,
bool get_parent_variables,
bool stop_if_block_is_inlined_function,
const std::function<bool(Variable*)>& filter,
VariableList *variable_list);
//------------------------------------------------------------------

View File

@ -17,6 +17,7 @@
#include "lldb/lldb-private.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/UserID.h"
#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Symbol/Declaration.h"
@ -27,6 +28,8 @@ class Variable : public UserID,
public std::enable_shared_from_this<Variable>
{
public:
typedef RangeVector<lldb::addr_t, lldb::addr_t> RangeList;
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
@ -36,6 +39,7 @@ public:
const lldb::SymbolFileTypeSP &symfile_type_sp,
lldb::ValueType scope,
SymbolContextScope *owner_scope,
const RangeList& scope_range,
Declaration* decl,
const DWARFExpression& location,
bool external,
@ -178,12 +182,14 @@ public:
CompilerDecl
GetDecl ();
protected:
ConstString m_name; // The basename of the variable (no namespaces)
Mangled m_mangled; // The mangled name of the variable
lldb::SymbolFileTypeSP m_symfile_type_sp; // The type pointer of the variable (int, struct, class, etc)
lldb::ValueType m_scope; // global, parameter, local
SymbolContextScope *m_owner_scope; // The symbol file scope that this variable was defined in
RangeList m_scope_range; // The list of ranges inside the owner's scope where this variable is valid
Declaration m_declaration; // Declaration location for this item.
DWARFExpression m_location; // The location of this variable that can be fed to DWARFExpression::Evaluate()
uint8_t m_external:1, // Visible outside the containing compile unit?

View File

@ -131,7 +131,11 @@ SBBlock::AppendVariables (bool can_create, bool get_parent_variables, lldb_priva
if (IsValid())
{
bool show_inline = true;
m_opaque_ptr->AppendVariables (can_create, get_parent_variables, show_inline, var_list);
m_opaque_ptr->AppendVariables (can_create,
get_parent_variables,
show_inline,
[](Variable*) { return true; },
var_list);
}
}

View File

@ -789,9 +789,10 @@ SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
const bool get_parent_variables = true;
const bool stop_if_block_is_inlined_function = true;
if (sc.block->AppendVariables (can_create,
if (sc.block->AppendVariables (can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
[frame](Variable* v) { return v->IsInScope(frame); },
&variable_list))
{
var_sp = variable_list.FindVariable (ConstString(name));
@ -887,6 +888,7 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy
sc.block->AppendVariables(can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
[frame](Variable* v) { return v->IsInScope(frame); },
&variable_list);
if (value_type == eValueTypeVariableGlobal)
{

View File

@ -760,10 +760,11 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum
bool stop_if_block_is_inlined_function = false;
VariableList variable_list;
sc.block->AppendVariables (can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
get_parent_variables,
stop_if_block_is_inlined_function,
[](Variable*) { return true; },
&variable_list);
const size_t num_variables = variable_list.GetSize();
for (size_t var_idx = 0; var_idx < num_variables; ++var_idx)
{

View File

@ -4091,6 +4091,7 @@ SymbolFileDWARF::ParseVariableDIE
bool location_is_const_value_data = false;
bool has_explicit_location = false;
DWARFFormValue const_value;
Variable::RangeList scope_ranges;
//AccessType accessibility = eAccessNone;
for (i=0; i<num_attributes; ++i)
@ -4206,13 +4207,44 @@ SymbolFileDWARF::ParseVariableDIE
spec_die = debug_info->GetDIE(DIERef(form_value));
break;
}
case DW_AT_start_scope:
{
if (form_value.Form() == DW_FORM_sec_offset)
{
DWARFRangeList dwarf_scope_ranges;
const DWARFDebugRanges* debug_ranges = DebugRanges();
debug_ranges->FindRanges(form_value.Unsigned(), dwarf_scope_ranges);
// All DW_AT_start_scope are relative to the base address of the
// compile unit. We add the compile unit base address to make
// sure all the addresses are properly fixed up.
for (size_t i = 0, count = dwarf_scope_ranges.GetSize(); i < count; ++i)
{
const DWARFRangeList::Entry& range = dwarf_scope_ranges.GetEntryRef(i);
scope_ranges.Append(range.GetRangeBase() + die.GetCU()->GetBaseAddress(),
range.GetByteSize());
}
}
else
{
// TODO: Handle the case when DW_AT_start_scope have form constant. The
// dwarf spec is a bit ambiguous about what is the expected behavior in
// case the enclosing block have a non coninious address range and the
// DW_AT_start_scope entry have a form constant.
GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_start_scope has unsupported form type (0x%x)\n",
die.GetID(),
form_value.Form());
}
scope_ranges.Sort();
scope_ranges.CombineConsecutiveRanges();
}
case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
case DW_AT_declaration:
case DW_AT_description:
case DW_AT_endianity:
case DW_AT_segment:
case DW_AT_start_scope:
case DW_AT_visibility:
default:
case DW_AT_abstract_origin:
@ -4392,19 +4424,20 @@ SymbolFileDWARF::ParseVariableDIE
if (symbol_context_scope)
{
SymbolFileTypeSP type_sp(new SymbolFileType(*this, DIERef(type_die_form).GetUID()));
if (const_value.Form() && type_sp && type_sp->GetType())
location.CopyOpcodeData(const_value.Unsigned(), type_sp->GetType()->GetByteSize(), die.GetCU()->GetAddressByteSize());
var_sp.reset (new Variable (die.GetID(),
name,
name,
mangled,
type_sp,
scope,
symbol_context_scope,
&decl,
location,
is_external,
scope,
symbol_context_scope,
scope_ranges,
&decl,
location,
is_external,
is_artificial,
is_static_member));

View File

@ -486,16 +486,24 @@ uint32_t
Block::AppendBlockVariables (bool can_create,
bool get_child_block_variables,
bool stop_if_child_block_is_inlined_function,
const std::function<bool(Variable*)>& filter,
VariableList *variable_list)
{
uint32_t num_variables_added = 0;
VariableList *block_var_list = GetBlockVariableList (can_create).get();
if (block_var_list)
{
num_variables_added += block_var_list->GetSize();
variable_list->AddVariables (block_var_list);
for (size_t i = 0; i < block_var_list->GetSize(); ++i)
{
VariableSP variable = block_var_list->GetVariableAtIndex(i);
if (filter(variable.get()))
{
num_variables_added++;
variable_list->AddVariable(variable);
}
}
}
if (get_child_block_variables)
{
collection::const_iterator pos, end = m_children.end();
@ -508,6 +516,7 @@ Block::AppendBlockVariables (bool can_create,
num_variables_added += child_block->AppendBlockVariables (can_create,
get_child_block_variables,
stop_if_child_block_is_inlined_function,
filter,
variable_list);
}
}
@ -521,6 +530,7 @@ Block::AppendVariables
bool can_create,
bool get_parent_variables,
bool stop_if_block_is_inlined_function,
const std::function<bool(Variable*)>& filter,
VariableList *variable_list
)
{
@ -528,12 +538,19 @@ Block::AppendVariables
VariableListSP variable_list_sp(GetBlockVariableList(can_create));
bool is_inlined_function = GetInlinedFunctionInfo() != nullptr;
if (variable_list_sp.get())
if (variable_list_sp)
{
num_variables_added = variable_list_sp->GetSize();
variable_list->AddVariables(variable_list_sp.get());
for (size_t i = 0; i < variable_list_sp->GetSize(); ++i)
{
VariableSP variable = variable_list_sp->GetVariableAtIndex(i);
if (filter(variable.get()))
{
num_variables_added++;
variable_list->AddVariable(variable);
}
}
}
if (get_parent_variables)
{
if (stop_if_block_is_inlined_function && is_inlined_function)
@ -541,7 +558,11 @@ Block::AppendVariables
Block* parent_block = GetParent();
if (parent_block)
num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, variable_list);
num_variables_added += parent_block->AppendVariables(can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
filter,
variable_list);
}
return num_variables_added;
}

View File

@ -43,6 +43,7 @@ Variable::Variable (lldb::user_id_t uid,
const lldb::SymbolFileTypeSP &symfile_type_sp,
ValueType scope,
SymbolContextScope *context,
const RangeList& scope_range,
Declaration* decl_ptr,
const DWARFExpression& location,
bool external,
@ -54,6 +55,7 @@ Variable::Variable (lldb::user_id_t uid,
m_symfile_type_sp(symfile_type_sp),
m_scope(scope),
m_owner_scope(context),
m_scope_range(scope_range),
m_declaration(decl_ptr),
m_location(location),
m_external(external),
@ -356,14 +358,24 @@ Variable::IsInScope (StackFrame *frame)
{
SymbolContext variable_sc;
CalculateSymbolContext (&variable_sc);
// Check for static or global variable defined at the compile unit
// level that wasn't defined in a block
if (variable_sc.block == nullptr)
return true;
if (variable_sc.block == deepest_frame_block)
return true;
return variable_sc.block->Contains (deepest_frame_block);
// Check if the variable is valid in the current block
if (variable_sc.block != deepest_frame_block &&
!variable_sc.block->Contains(deepest_frame_block))
return false;
// If no scope range is specified then it means that the scope is the same as the
// scope of the enclosing lexical block.
if (m_scope_range.IsEmpty())
return true;
addr_t file_address = frame->GetFrameCodeAddress().GetFileAddress();
return m_scope_range.FindEntryThatContains(file_address) != nullptr;
}
}
break;

View File

@ -540,7 +540,11 @@ StackFrame::GetVariableList (bool get_file_globals)
const bool can_create = true;
const bool stop_if_child_block_is_inlined_function = true;
m_variable_list_sp.reset(new VariableList());
frame_block->AppendBlockVariables(can_create, get_child_variables, stop_if_child_block_is_inlined_function, m_variable_list_sp.get());
frame_block->AppendBlockVariables(can_create,
get_child_variables,
stop_if_child_block_is_inlined_function,
[this](Variable* v) { return v->IsInScope(this); },
m_variable_list_sp.get());
}
}
@ -584,6 +588,7 @@ StackFrame::GetInScopeVariableList (bool get_file_globals)
m_sc.block->AppendVariables (can_create,
get_parent_variables,
stop_if_block_is_inlined_function,
[this](Variable* v) { return v->IsInScope(this); },
var_list_sp.get());
}