forked from OSchip/llvm-project
642 lines
15 KiB
C++
642 lines
15 KiB
C++
//===-- Block.cpp -----------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Symbol/Block.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Symbol/SymbolVendor.h"
|
|
#include "lldb/Symbol/VariableList.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
Block::Block(user_id_t uid, uint32_t depth, BlockList* blocks) :
|
|
UserID(uid),
|
|
m_block_list(blocks),
|
|
m_depth(depth),
|
|
m_ranges(),
|
|
m_inlineInfoSP(),
|
|
m_variables()
|
|
{
|
|
}
|
|
|
|
Block::Block(const Block& rhs) :
|
|
UserID(rhs),
|
|
m_block_list(rhs.m_block_list),
|
|
m_depth(rhs.m_depth),
|
|
m_ranges(rhs.m_ranges),
|
|
m_inlineInfoSP(rhs.m_inlineInfoSP),
|
|
m_variables(rhs.m_variables)
|
|
{
|
|
}
|
|
|
|
const Block&
|
|
Block::operator= (const Block& rhs)
|
|
{
|
|
if (this != &rhs)
|
|
{
|
|
UserID::operator= (rhs);
|
|
m_block_list = rhs.m_block_list;
|
|
m_depth = rhs.m_depth;
|
|
m_ranges = rhs.m_ranges;
|
|
m_inlineInfoSP = rhs.m_inlineInfoSP;
|
|
m_variables = rhs.m_variables;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Block::~Block ()
|
|
{
|
|
}
|
|
|
|
void
|
|
Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
|
|
{
|
|
if (depth < 0)
|
|
{
|
|
// We have a depth that is less than zero, print our parent blocks
|
|
// first
|
|
m_block_list->Dump(s, GetParentUID(), depth + 1, show_context);
|
|
}
|
|
|
|
s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
|
|
s->Indent();
|
|
*s << "Block" << ((const UserID&)*this);
|
|
user_id_t parentID = GetParentUID();
|
|
const Block* parent_block = NULL;
|
|
if (parentID != Block::InvalidID)
|
|
{
|
|
parent_block = m_block_list->GetBlockByID(parentID);
|
|
s->Printf(", parent = {0x%8.8x}", parentID);
|
|
}
|
|
if (m_inlineInfoSP.get() != NULL)
|
|
m_inlineInfoSP->Dump(s);
|
|
|
|
if (!m_ranges.empty())
|
|
{
|
|
*s << ", ranges =";
|
|
std::vector<VMRange>::const_iterator pos;
|
|
std::vector<VMRange>::const_iterator end = m_ranges.end();
|
|
for (pos = m_ranges.begin(); pos != end; ++pos)
|
|
{
|
|
if (parent_block != NULL && parent_block->Contains(*pos) == false)
|
|
*s << '!';
|
|
else
|
|
*s << ' ';
|
|
pos->Dump(s, base_addr);
|
|
}
|
|
}
|
|
s->EOL();
|
|
|
|
if (depth > 0)
|
|
{
|
|
s->IndentMore();
|
|
|
|
if (m_variables.get())
|
|
{
|
|
m_variables->Dump(s, show_context);
|
|
}
|
|
|
|
uint32_t blockID = m_block_list->GetFirstChild(GetID());
|
|
while (blockID != Block::InvalidID)
|
|
{
|
|
m_block_list->Dump(s, blockID, depth - 1, show_context);
|
|
|
|
blockID = m_block_list->GetSibling(blockID);
|
|
}
|
|
|
|
s->IndentLess();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void
|
|
Block::CalculateSymbolContext(SymbolContext* sc)
|
|
{
|
|
sc->block = this;
|
|
m_block_list->GetFunction()->CalculateSymbolContext(sc);
|
|
}
|
|
|
|
void
|
|
Block::DumpStopContext (Stream *s, const SymbolContext *sc)
|
|
{
|
|
user_id_t parentID = GetParentUID();
|
|
Block* parent_block = NULL;
|
|
if (parentID != Block::InvalidID)
|
|
parent_block = m_block_list->GetBlockByID(parentID);
|
|
|
|
InlineFunctionInfo* inline_info = InlinedFunctionInfo ();
|
|
if (inline_info)
|
|
{
|
|
const Declaration &call_site = inline_info->GetCallSite();
|
|
if (sc)
|
|
{
|
|
// First frame, dump the first inline call site
|
|
// if (call_site.IsValid())
|
|
// {
|
|
// s->PutCString(" at ");
|
|
// call_site.DumpStopContext (s);
|
|
// }
|
|
s->PutCString (" [inlined]");
|
|
}
|
|
s->EOL();
|
|
inline_info->DumpStopContext (s);
|
|
if (sc == NULL)
|
|
{
|
|
if (call_site.IsValid())
|
|
{
|
|
s->PutCString(" at ");
|
|
call_site.DumpStopContext (s);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sc)
|
|
{
|
|
// If we have any inlined functions, this will be the deepest most
|
|
// inlined location
|
|
if (sc->line_entry.IsValid())
|
|
{
|
|
s->PutCString(" at ");
|
|
sc->line_entry.DumpStopContext (s);
|
|
}
|
|
}
|
|
if (parent_block)
|
|
parent_block->Block::DumpStopContext (s, NULL);
|
|
}
|
|
|
|
|
|
void
|
|
Block::DumpSymbolContext(Stream *s)
|
|
{
|
|
m_block_list->GetFunction()->DumpSymbolContext(s);
|
|
s->Printf(", Block{0x%8.8x}", GetID());
|
|
}
|
|
|
|
bool
|
|
Block::Contains (addr_t range_offset) const
|
|
{
|
|
return VMRange::ContainsValue(m_ranges, range_offset);
|
|
}
|
|
|
|
bool
|
|
Block::Contains (const VMRange& range) const
|
|
{
|
|
return VMRange::ContainsRange(m_ranges, range);
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
BlockList::BlockContainsBlockWithID (const user_id_t block_id, const user_id_t find_block_id) const
|
|
{
|
|
if (block_id == Block::InvalidID)
|
|
return false;
|
|
|
|
if (block_id == find_block_id)
|
|
return true;
|
|
else
|
|
{
|
|
user_id_t child_block_id = GetFirstChild(block_id);
|
|
while (child_block_id != Block::InvalidID)
|
|
{
|
|
if (BlockContainsBlockWithID (child_block_id, find_block_id))
|
|
return true;
|
|
child_block_id = GetSibling(child_block_id);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Block::ContainsBlockWithID (user_id_t block_id) const
|
|
{
|
|
return m_block_list->BlockContainsBlockWithID (GetID(), block_id);
|
|
}
|
|
|
|
|
|
void
|
|
Block::AddRange(addr_t start_offset, addr_t end_offset)
|
|
{
|
|
m_ranges.resize(m_ranges.size()+1);
|
|
m_ranges.back().Reset(start_offset, end_offset);
|
|
}
|
|
|
|
InlineFunctionInfo*
|
|
Block::InlinedFunctionInfo ()
|
|
{
|
|
return m_inlineInfoSP.get();
|
|
}
|
|
|
|
const InlineFunctionInfo*
|
|
Block::InlinedFunctionInfo () const
|
|
{
|
|
return m_inlineInfoSP.get();
|
|
}
|
|
|
|
// Return the current number of bytes that this object occupies in memory
|
|
size_t
|
|
Block::MemorySize() const
|
|
{
|
|
size_t mem_size = sizeof(Block) + m_ranges.size() * sizeof(VMRange);
|
|
if (m_inlineInfoSP.get())
|
|
mem_size += m_inlineInfoSP->MemorySize();
|
|
if (m_variables.get())
|
|
mem_size += m_variables->MemorySize();
|
|
return mem_size;
|
|
|
|
}
|
|
|
|
user_id_t
|
|
Block::GetParentUID() const
|
|
{
|
|
return m_block_list->GetParent(GetID());
|
|
}
|
|
|
|
user_id_t
|
|
Block::GetSiblingUID() const
|
|
{
|
|
return m_block_list->GetSibling(GetID());
|
|
}
|
|
|
|
user_id_t
|
|
Block::GetFirstChildUID() const
|
|
{
|
|
return m_block_list->GetFirstChild(GetID());
|
|
}
|
|
|
|
user_id_t
|
|
Block::AddChild(user_id_t userID)
|
|
{
|
|
return m_block_list->AddChild(GetID(), userID);
|
|
}
|
|
|
|
void
|
|
Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
|
|
{
|
|
m_inlineInfoSP.reset(new InlineFunctionInfo(name, mangled, decl_ptr, call_decl_ptr));
|
|
}
|
|
|
|
BlockList::BlockList(Function *function, const AddressRange& range) :
|
|
m_function(function),
|
|
m_range(range),
|
|
m_blocks()
|
|
{
|
|
}
|
|
|
|
BlockList::~BlockList()
|
|
{
|
|
}
|
|
|
|
AddressRange &
|
|
BlockList::GetAddressRange()
|
|
{
|
|
return m_range;
|
|
}
|
|
|
|
const AddressRange &
|
|
BlockList::GetAddressRange() const
|
|
{
|
|
return m_range;
|
|
}
|
|
|
|
void
|
|
BlockList::Dump(Stream *s, user_id_t blockID, uint32_t depth, bool show_context) const
|
|
{
|
|
const Block* block = GetBlockByID(blockID);
|
|
if (block)
|
|
block->Dump(s, m_range.GetBaseAddress().GetFileAddress(), depth, show_context);
|
|
}
|
|
|
|
Function *
|
|
BlockList::GetFunction()
|
|
{
|
|
return m_function;
|
|
}
|
|
|
|
|
|
const Function *
|
|
BlockList::GetFunction() const
|
|
{
|
|
return m_function;
|
|
}
|
|
|
|
user_id_t
|
|
BlockList::GetParent(user_id_t blockID) const
|
|
{
|
|
collection::const_iterator end = m_blocks.end();
|
|
collection::const_iterator begin = m_blocks.begin();
|
|
collection::const_iterator pos = std::find_if(begin, end, UserID::IDMatches(blockID));
|
|
|
|
if (pos != end && pos != begin && pos->Depth() > 0)
|
|
{
|
|
const uint32_t parent_depth = pos->Depth() - 1;
|
|
|
|
while (--pos >= begin)
|
|
{
|
|
if (pos->Depth() == parent_depth)
|
|
return pos->GetID();
|
|
}
|
|
}
|
|
return Block::InvalidID;
|
|
}
|
|
|
|
user_id_t
|
|
BlockList::GetSibling(user_id_t blockID) const
|
|
{
|
|
collection::const_iterator end = m_blocks.end();
|
|
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
|
|
|
|
if (pos != end)
|
|
{
|
|
const uint32_t sibling_depth = pos->Depth();
|
|
while (++pos != end)
|
|
{
|
|
uint32_t depth = pos->Depth();
|
|
if (depth == sibling_depth)
|
|
return pos->GetID();
|
|
if (depth < sibling_depth)
|
|
break;
|
|
}
|
|
}
|
|
return Block::InvalidID;
|
|
}
|
|
|
|
user_id_t
|
|
BlockList::GetFirstChild(user_id_t blockID) const
|
|
{
|
|
if (!m_blocks.empty())
|
|
{
|
|
if (blockID == Block::RootID)
|
|
{
|
|
return m_blocks.front().GetID();
|
|
}
|
|
else
|
|
{
|
|
collection::const_iterator end = m_blocks.end();
|
|
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
|
|
|
|
if (pos != end)
|
|
{
|
|
collection::const_iterator child_pos = pos + 1;
|
|
if (child_pos != end)
|
|
{
|
|
if (child_pos->Depth() == pos->Depth() + 1)
|
|
return child_pos->GetID();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Block::InvalidID;
|
|
}
|
|
|
|
|
|
// Return the current number of bytes that this object occupies in memory
|
|
size_t
|
|
BlockList::MemorySize() const
|
|
{
|
|
size_t mem_size = sizeof(BlockList);
|
|
|
|
collection::const_iterator pos, end = m_blocks.end();
|
|
for (pos = m_blocks.begin(); pos != end; ++pos)
|
|
mem_size += pos->MemorySize(); // Each block can vary in size
|
|
|
|
return mem_size;
|
|
|
|
}
|
|
|
|
user_id_t
|
|
BlockList::AddChild (user_id_t parentID, user_id_t childID)
|
|
{
|
|
bool added = false;
|
|
if (parentID == Block::RootID)
|
|
{
|
|
assert(m_blocks.empty());
|
|
Block block(childID, 0, this);
|
|
m_blocks.push_back(block);
|
|
added = true;
|
|
}
|
|
else
|
|
{
|
|
collection::iterator end = m_blocks.end();
|
|
collection::iterator parent_pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(parentID));
|
|
assert(parent_pos != end);
|
|
if (parent_pos != end)
|
|
{
|
|
const uint32_t parent_sibling_depth = parent_pos->Depth();
|
|
|
|
collection::iterator insert_pos = parent_pos;
|
|
collection::iterator prev_sibling = end;
|
|
while (++insert_pos != end)
|
|
{
|
|
if (insert_pos->Depth() <= parent_sibling_depth)
|
|
break;
|
|
}
|
|
|
|
Block child_block(childID, parent_pos->Depth() + 1, this);
|
|
collection::iterator child_pos = m_blocks.insert(insert_pos, child_block);
|
|
added = true;
|
|
}
|
|
}
|
|
if (added)
|
|
return childID;
|
|
return Block::InvalidID;
|
|
}
|
|
|
|
const Block *
|
|
BlockList::GetBlockByID(user_id_t blockID) const
|
|
{
|
|
if (m_blocks.empty())
|
|
return NULL;
|
|
|
|
if (blockID == Block::RootID)
|
|
blockID = m_blocks.front().GetID();
|
|
|
|
collection::const_iterator end = m_blocks.end();
|
|
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
|
|
if (pos != end)
|
|
return &(*pos);
|
|
return NULL;
|
|
}
|
|
|
|
Block *
|
|
BlockList::GetBlockByID(user_id_t blockID)
|
|
{
|
|
if (m_blocks.empty())
|
|
return NULL;
|
|
|
|
if (blockID == Block::RootID)
|
|
blockID = m_blocks.front().GetID();
|
|
|
|
collection::iterator end = m_blocks.end();
|
|
collection::iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
|
|
if (pos != end)
|
|
return &(*pos);
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
BlockList::AddRange(user_id_t blockID, addr_t start_offset, addr_t end_offset)
|
|
{
|
|
Block *block = GetBlockByID(blockID);
|
|
|
|
if (block)
|
|
{
|
|
block->AddRange(start_offset, end_offset);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//
|
|
//const Block *
|
|
//BlockList::FindDeepestBlockForAddress (const Address &addr)
|
|
//{
|
|
// if (m_range.Contains(addr))
|
|
// {
|
|
// addr_t block_offset = addr.GetFileAddress() - m_range.GetBaseAddress().GetFileAddress();
|
|
// collection::const_iterator pos, end = m_blocks.end();
|
|
// collection::const_iterator deepest_match_pos = end;
|
|
// for (pos = m_blocks.begin(); pos != end; ++pos)
|
|
// {
|
|
// if (pos->Contains (block_offset))
|
|
// {
|
|
// if (deepest_match_pos == end || deepest_match_pos->Depth() < pos->Depth())
|
|
// deepest_match_pos = pos;
|
|
// }
|
|
// }
|
|
// if (deepest_match_pos != end)
|
|
// return &(*deepest_match_pos);
|
|
// }
|
|
// return NULL;
|
|
//}
|
|
//
|
|
bool
|
|
BlockList::SetInlinedFunctionInfo(user_id_t blockID, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
|
|
{
|
|
Block *block = GetBlockByID(blockID);
|
|
|
|
if (block)
|
|
{
|
|
block->SetInlinedFunctionInfo(name, mangled, decl_ptr, call_decl_ptr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
VariableListSP
|
|
BlockList::GetVariableList(user_id_t blockID, bool get_child_variables, bool can_create)
|
|
{
|
|
VariableListSP variable_list_sp;
|
|
Block *block = GetBlockByID(blockID);
|
|
if (block)
|
|
variable_list_sp = block->GetVariableList(get_child_variables, can_create);
|
|
return variable_list_sp;
|
|
}
|
|
|
|
bool
|
|
BlockList::IsEmpty() const
|
|
{
|
|
return m_blocks.empty();
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
BlockList::SetVariableList(user_id_t blockID, VariableListSP& variables)
|
|
{
|
|
Block *block = GetBlockByID(blockID);
|
|
if (block)
|
|
{
|
|
block->SetVariableList(variables);
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
VariableListSP
|
|
Block::GetVariableList (bool get_child_variables, bool can_create)
|
|
{
|
|
VariableListSP variable_list_sp;
|
|
if (m_variables.get() == NULL && can_create)
|
|
{
|
|
SymbolContext sc;
|
|
CalculateSymbolContext(&sc);
|
|
assert(sc.module_sp);
|
|
sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
|
|
}
|
|
|
|
if (m_variables.get())
|
|
{
|
|
variable_list_sp.reset(new VariableList());
|
|
if (variable_list_sp.get())
|
|
variable_list_sp->AddVariables(m_variables.get());
|
|
|
|
if (get_child_variables)
|
|
{
|
|
user_id_t block_id = GetFirstChildUID();
|
|
while (block_id != Block::InvalidID)
|
|
{
|
|
Block *child_block = m_block_list->GetBlockByID(block_id);
|
|
assert(child_block);
|
|
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());
|
|
|
|
block_id = child_block->GetSiblingUID();
|
|
}
|
|
}
|
|
}
|
|
|
|
return variable_list_sp;
|
|
}
|
|
|
|
uint32_t
|
|
Block::AppendVariables (bool can_create, bool get_parent_variables, VariableList *variable_list)
|
|
{
|
|
uint32_t num_variables_added = 0;
|
|
VariableListSP variable_list_sp(GetVariableList(false, can_create));
|
|
|
|
if (variable_list_sp.get())
|
|
{
|
|
num_variables_added = variable_list_sp->GetSize();
|
|
variable_list->AddVariables(variable_list_sp.get());
|
|
}
|
|
|
|
if (get_parent_variables)
|
|
{
|
|
user_id_t parentID = GetParentUID();
|
|
if (parentID != Block::InvalidID)
|
|
{
|
|
Block* parent_block = m_block_list->GetBlockByID(parentID);
|
|
if (parent_block)
|
|
num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, variable_list);
|
|
}
|
|
}
|
|
return num_variables_added;
|
|
}
|
|
|
|
|
|
void
|
|
Block::SetVariableList(VariableListSP& variables)
|
|
{
|
|
m_variables = variables;
|
|
}
|
|
|
|
uint32_t
|
|
Block::Depth () const
|
|
{
|
|
return m_depth;
|
|
}
|
|
|