Fixed variable parsing to not parse block variables over and over due to an

issue in the way block variables are marked as parsed. In the DWARF parser we
always parse all blocks for a function at once, so we can mark all blocks as
having all variables parsed and avoid recursive function calls to try and
reparse things that have already been handled.

Fixed an issue with how variables get scoped into blocks. The DWARF parser can
now handle abtract class definitions that contain concrete static variables.
When the concrete instance of the class functions get instantiated, they will
track down the concrete block for the abtract block and add the variable to
each block.

llvm-svn: 133302
This commit is contained in:
Greg Clayton 2011-06-17 22:10:16 +00:00
parent c76b9d8c2f
commit c662ec8bd3
7 changed files with 264 additions and 126 deletions

View File

@ -281,10 +281,15 @@ public:
/// for this block.
//------------------------------------------------------------------
lldb::VariableListSP
GetVariableList (bool get_child_variables,
bool can_create);
GetBlockVariableList (bool can_create);
uint32_t
AppendBlockVariables (bool can_create,
bool get_child_block_variables,
bool stop_if_child_block_is_inlined_function,
VariableList *variable_list);
//------------------------------------------------------------------
/// Appends the variables from this block, and optionally from all
/// parent blocks, to \a variable_list.
@ -431,6 +436,9 @@ public:
bool
GetStartAddress (Address &addr);
void
SetDidParseVariables (bool b, bool set_children);
protected:
typedef std::vector<lldb::BlockSP> collection;
//------------------------------------------------------------------

View File

@ -263,6 +263,29 @@ DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
return NULL; // Not found in any compile units
}
DWARFDebugInfoEntry*
DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle)
{
assert (cu_handle);
DWARFDebugInfoEntry* die = NULL;
if (*cu_handle)
die = (*cu_handle)->GetDIEPtr(die_offset);
if (die == NULL)
{
DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset));
if (cu_sp.get())
{
*cu_handle = cu_sp.get();
die = cu_sp->GetDIEPtr(die_offset);
}
}
if (die == NULL)
*cu_handle = NULL;
return die;
}
const DWARFDebugInfoEntry*
DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
{

View File

@ -52,6 +52,8 @@ public:
DWARFCompileUnitSP GetCompileUnitContainingDIE(dw_offset_t die_offset);
DWARFDebugInfoEntry* GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
DWARFDebugInfoEntry* GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle);
const DWARFDebugInfoEntry* GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth);

View File

@ -3983,7 +3983,12 @@ SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc)
dw_addr_t func_lo_pc = function_die->GetAttributeValueAsUnsigned (this, dwarf_cu, DW_AT_low_pc, DW_INVALID_ADDRESS);
assert (func_lo_pc != DW_INVALID_ADDRESS);
return ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true);
const size_t num_variables = ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true);
// Let all blocks know they have parse all their variables
sc.function->GetBlock (false).SetDidParseVariables (true, true);
return num_variables;
}
else if (sc.comp_unit)
{
@ -4161,6 +4166,74 @@ SymbolFileDWARF::ParseVariableDIE
return var_sp;
}
const DWARFDebugInfoEntry *
SymbolFileDWARF::FindBlockContainingSpecification (dw_offset_t func_die_offset,
dw_offset_t spec_block_die_offset,
DWARFCompileUnit **result_die_cu_handle)
{
// Give the concrete function die specified by "func_die_offset", find the
// concrete block whose DW_AT_specification or DW_AT_abstract_origin points
// to "spec_block_die_offset"
DWARFDebugInfo* info = DebugInfo();
const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint(func_die_offset, result_die_cu_handle);
if (die)
{
assert (*result_die_cu_handle);
return FindBlockContainingSpecification (*result_die_cu_handle, die, spec_block_die_offset, result_die_cu_handle);
}
return NULL;
}
const DWARFDebugInfoEntry *
SymbolFileDWARF::FindBlockContainingSpecification(DWARFCompileUnit* dwarf_cu,
const DWARFDebugInfoEntry *die,
dw_offset_t spec_block_die_offset,
DWARFCompileUnit **result_die_cu_handle)
{
if (die)
{
switch (die->Tag())
{
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
{
if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset)
{
*result_die_cu_handle = dwarf_cu;
return die;
}
if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET) == spec_block_die_offset)
{
*result_die_cu_handle = dwarf_cu;
return die;
}
}
break;
}
// Give the concrete function die specified by "func_die_offset", find the
// concrete block whose DW_AT_specification or DW_AT_abstract_origin points
// to "spec_block_die_offset"
for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); child_die != NULL; child_die = child_die->GetSibling())
{
const DWARFDebugInfoEntry *result_die = FindBlockContainingSpecification (dwarf_cu,
child_die,
spec_block_die_offset,
result_die_cu_handle);
if (result_die)
return result_die;
}
}
*result_die_cu_handle = NULL;
return NULL;
}
size_t
SymbolFileDWARF::ParseVariables
(
@ -4176,126 +4249,125 @@ SymbolFileDWARF::ParseVariables
if (orig_die == NULL)
return 0;
VariableListSP variable_list_sp;
size_t vars_added = 0;
const DWARFDebugInfoEntry *die = orig_die;
const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
VariableListSP variables;
switch (parent_tag)
while (die != NULL)
{
case DW_TAG_compile_unit:
if (sc.comp_unit != NULL)
dw_tag_t tag = die->Tag();
// Check to see if we have already parsed this variable or constant?
if (m_die_to_variable_sp[die])
{
variables = sc.comp_unit->GetVariableList(false);
if (variables.get() == NULL)
{
variables.reset(new VariableList());
sc.comp_unit->SetVariableList(variables);
}
if (cc_variable_list)
cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]);
}
else
{
fprintf (stderr,
"error: parent 0x%8.8x %s with no valid compile unit in symbol context for 0x%8.8x %s.\n",
sc_parent_die->GetOffset(),
DW_TAG_value_to_name (parent_tag),
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
}
break;
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
if (sc.function != NULL)
{
// Check to see if we already have parsed the variables for the given scope
Block *block = sc.function->GetBlock(true).FindBlockByID(sc_parent_die->GetOffset());
if (block != NULL)
// We haven't already parsed it, lets do that now.
if ((tag == DW_TAG_variable) ||
(tag == DW_TAG_constant) ||
(tag == DW_TAG_formal_parameter && sc.function))
{
variables = block->GetVariableList(false, false);
if (variables.get() == NULL)
if (variable_list_sp.get() == NULL)
{
variables.reset(new VariableList());
block->SetVariableList(variables);
const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
switch (parent_tag)
{
case DW_TAG_compile_unit:
if (sc.comp_unit != NULL)
{
variable_list_sp = sc.comp_unit->GetVariableList(false);
if (variable_list_sp.get() == NULL)
{
variable_list_sp.reset(new VariableList());
sc.comp_unit->SetVariableList(variable_list_sp);
}
}
else
{
fprintf (stderr,
"error: parent 0x%8.8x %s with no valid compile unit in symbol context for 0x%8.8x %s.\n",
sc_parent_die->GetOffset(),
DW_TAG_value_to_name (parent_tag),
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
}
break;
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
if (sc.function != NULL)
{
// Check to see if we already have parsed the variables for the given scope
Block *block = sc.function->GetBlock(true).FindBlockByID(sc_parent_die->GetOffset());
if (block == NULL)
{
// This must be a specification or abstract origin with
// a concrete block couterpart in the current function. We need
// to find the concrete block so we can correctly add the
// variable to it
DWARFCompileUnit *concrete_block_die_cu = dwarf_cu;
const DWARFDebugInfoEntry *concrete_block_die = FindBlockContainingSpecification (sc.function->GetID(),
sc_parent_die->GetOffset(),
&concrete_block_die_cu);
if (concrete_block_die)
block = sc.function->GetBlock(true).FindBlockByID(concrete_block_die->GetOffset());
}
if (block != NULL)
{
const bool can_create = false;
variable_list_sp = block->GetBlockVariableList (can_create);
if (variable_list_sp.get() == NULL)
{
variable_list_sp.reset(new VariableList());
block->SetVariableList(variable_list_sp);
}
}
}
break;
default:
fprintf (stderr,
"error: didn't find appropriate parent DIE for variable list for 0x%8.8x %s.\n",
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
break;
}
}
}
else
{
fprintf (stderr,
"error: NULL block for 0x%8.8x %s for variable at 0x%8.8x %s\n",
sc_parent_die->GetOffset(),
DW_TAG_value_to_name (parent_tag),
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
}
}
else
{
fprintf (stderr,
"error: parent 0x%8.8x %s with no valid function in symbol context for 0x%8.8x %s.\n",
sc_parent_die->GetOffset(),
DW_TAG_value_to_name (parent_tag),
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
}
break;
default:
fprintf (stderr,
"error: didn't find appropriate parent DIE for variable list for 0x%8.8x %s.\n",
orig_die->GetOffset(),
DW_TAG_value_to_name (orig_die->Tag()));
break;
}
// We need to have a variable list at this point that we can add variables to
if (variables.get())
{
size_t vars_added = 0;
while (die != NULL)
{
dw_tag_t tag = die->Tag();
// Check to see if we have already parsed this variable or constant?
if (m_die_to_variable_sp[die])
{
if (cc_variable_list)
cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]);
}
else
{
// We haven't already parsed it, lets do that now.
if ((tag == DW_TAG_variable) ||
(tag == DW_TAG_constant) ||
(tag == DW_TAG_formal_parameter && sc.function))
if (variable_list_sp)
{
VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, func_low_pc));
if (var_sp)
{
variables->AddVariableIfUnique (var_sp);
variable_list_sp->AddVariableIfUnique (var_sp);
if (cc_variable_list)
cc_variable_list->AddVariableIfUnique (var_sp);
++vars_added;
}
}
}
bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
if (!skip_children && parse_children && die->HasChildren())
{
vars_added += ParseVariables(sc, dwarf_cu, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list);
}
if (parse_siblings)
die = die->GetSibling();
else
die = NULL;
}
return vars_added;
bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
if (!skip_children && parse_children && die->HasChildren())
{
vars_added += ParseVariables(sc, dwarf_cu, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list);
}
if (parse_siblings)
die = die->GetSibling();
else
die = NULL;
}
return 0;
return vars_added;
}
//------------------------------------------------------------------

View File

@ -311,6 +311,17 @@ protected:
m_debug_map_symfile = debug_map_symfile;
}
const DWARFDebugInfoEntry *
FindBlockContainingSpecification (dw_offset_t func_die_offset,
dw_offset_t spec_block_die_offset,
DWARFCompileUnit **dwarf_cu_handle);
const DWARFDebugInfoEntry *
FindBlockContainingSpecification (DWARFCompileUnit* dwarf_cu,
const DWARFDebugInfoEntry *die,
dw_offset_t spec_block_die_offset,
DWARFCompileUnit **dwarf_cu_handle);
clang::NamespaceDecl *
ResolveNamespaceDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die);

View File

@ -455,9 +455,8 @@ Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Decla
VariableListSP
Block::GetVariableList (bool get_child_variables, bool can_create)
Block::GetBlockVariableList (bool can_create)
{
VariableListSP variable_list_sp;
if (m_parsed_block_variables == false)
{
if (m_variable_list_sp.get() == NULL && can_create)
@ -469,31 +468,40 @@ Block::GetVariableList (bool get_child_variables, bool can_create)
sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
}
}
return m_variable_list_sp;
}
if (m_variable_list_sp.get())
uint32_t
Block::AppendBlockVariables (bool can_create,
bool get_child_block_variables,
bool stop_if_child_block_is_inlined_function,
VariableList *variable_list)
{
uint32_t num_variables_added = 0;
VariableList *block_var_list = GetBlockVariableList (can_create).get();
if (block_var_list)
{
variable_list_sp.reset(new VariableList());
if (variable_list_sp.get())
variable_list_sp->AddVariables(m_variable_list_sp.get());
if (get_child_variables)
{
for (Block *child_block = GetFirstChild();
child_block != NULL;
child_block = child_block->GetSibling())
{
if (child_block->GetInlinedFunctionInfo() == NULL)
{
VariableListSP child_block_variable_list(child_block->GetVariableList(get_child_variables, can_create));
if (child_block_variable_list.get())
variable_list_sp->AddVariables(child_block_variable_list.get());
}
num_variables_added += block_var_list->GetSize();
variable_list->AddVariables (block_var_list);
}
if (get_child_block_variables)
{
for (Block *child_block = GetFirstChild();
child_block != NULL;
child_block = child_block->GetSibling())
{
if (stop_if_child_block_is_inlined_function == false ||
child_block->GetInlinedFunctionInfo() == NULL)
{
num_variables_added += child_block->AppendBlockVariables (can_create,
get_child_block_variables,
stop_if_child_block_is_inlined_function,
variable_list);
}
}
}
return variable_list_sp;
return num_variables_added;
}
uint32_t
@ -506,7 +514,7 @@ Block::AppendVariables
)
{
uint32_t num_variables_added = 0;
VariableListSP variable_list_sp(GetVariableList(false, can_create));
VariableListSP variable_list_sp(GetBlockVariableList(can_create));
bool is_inlined_function = GetInlinedFunctionInfo() != NULL;
if (variable_list_sp.get())
@ -538,3 +546,15 @@ Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
child_block->SetBlockInfoHasBeenParsed (b, true);
}
}
void
Block::SetDidParseVariables (bool b, bool set_children)
{
m_parsed_block_variables = b;
if (set_children)
{
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
child_block->SetDidParseVariables (b, true);
}
}

View File

@ -460,7 +460,9 @@ StackFrame::GetVariableList (bool get_file_globals)
{
const bool get_child_variables = true;
const bool can_create = true;
m_variable_list_sp = frame_block->GetVariableList (get_child_variables, can_create);
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());
}
}