might dump file paths that allows the dumping of full paths or just the basenames. Switched the stack frame dumping code to use just the basenames for the files instead of the full path. Modified the StackID class to no rely on needing the start PC for the current function/symbol since we can use the SymbolContextScope to uniquely identify that, unless there is no symbol context scope. In that case we can rely upon the current PC value. This saves the StackID from having to calculate the start PC when the StackFrame::GetStackID() accessor is called. Also improved the StackID less than operator to correctly handle inlined stack frames in the same stack. llvm-svn: 112867
440 lines
12 KiB
C++
440 lines
12 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(lldb::user_id_t uid) :
|
|
UserID(uid),
|
|
m_parent_scope (NULL),
|
|
m_sibling (NULL),
|
|
m_children (),
|
|
m_ranges (),
|
|
m_inlineInfoSP (),
|
|
m_variable_list_sp (),
|
|
m_parsed_block_info (false),
|
|
m_parsed_block_variables (false),
|
|
m_parsed_child_blocks (false)
|
|
{
|
|
}
|
|
|
|
Block::~Block ()
|
|
{
|
|
}
|
|
|
|
void
|
|
Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Process *process) const
|
|
{
|
|
size_t num_ranges = m_ranges.size();
|
|
if (num_ranges)
|
|
{
|
|
|
|
addr_t base_addr = LLDB_INVALID_ADDRESS;
|
|
if (process)
|
|
base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(process);
|
|
if (base_addr == LLDB_INVALID_ADDRESS)
|
|
base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
|
|
|
|
s->Printf("range%s = ", num_ranges > 1 ? "s" : "");
|
|
std::vector<VMRange>::const_iterator pos, end = m_ranges.end();
|
|
for (pos = m_ranges.begin(); pos != end; ++pos)
|
|
pos->Dump(s, base_addr, 4);
|
|
}
|
|
*s << ", id = " << ((const UserID&)*this);
|
|
|
|
if (m_inlineInfoSP.get() != NULL)
|
|
m_inlineInfoSP->Dump(s);
|
|
}
|
|
|
|
void
|
|
Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
|
|
{
|
|
if (depth < 0)
|
|
{
|
|
Block *parent = GetParent();
|
|
if (parent)
|
|
{
|
|
// We have a depth that is less than zero, print our parent blocks
|
|
// first
|
|
parent->Dump(s, base_addr, depth + 1, show_context);
|
|
}
|
|
}
|
|
|
|
s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
|
|
s->Indent();
|
|
*s << "Block" << ((const UserID&)*this);
|
|
const Block* parent_block = GetParent();
|
|
if (parent_block)
|
|
{
|
|
s->Printf(", parent = {0x%8.8x}", parent_block->GetID());
|
|
}
|
|
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_variable_list_sp.get())
|
|
{
|
|
m_variable_list_sp->Dump(s, show_context);
|
|
}
|
|
|
|
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
|
|
{
|
|
child_block->Dump(s, base_addr, depth - 1, show_context);
|
|
}
|
|
|
|
s->IndentLess();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Block *
|
|
Block::FindBlockByID (user_id_t block_id)
|
|
{
|
|
if (block_id == GetID())
|
|
return this;
|
|
|
|
Block *matching_block = NULL;
|
|
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
|
|
{
|
|
matching_block = child_block->FindBlockByID (block_id);
|
|
if (matching_block)
|
|
break;
|
|
}
|
|
return matching_block;
|
|
}
|
|
|
|
void
|
|
Block::CalculateSymbolContext (SymbolContext* sc)
|
|
{
|
|
if (m_parent_scope)
|
|
m_parent_scope->CalculateSymbolContext(sc);
|
|
sc->block = this;
|
|
}
|
|
|
|
void
|
|
Block::DumpStopContext (Stream *s, const SymbolContext *sc, bool show_fullpaths)
|
|
{
|
|
Block* parent_block = GetParent();
|
|
|
|
const 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, show_fullpaths);
|
|
}
|
|
}
|
|
}
|
|
|
|
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, show_fullpaths);
|
|
}
|
|
}
|
|
if (parent_block)
|
|
parent_block->Block::DumpStopContext (s, NULL, show_fullpaths);
|
|
}
|
|
|
|
|
|
void
|
|
Block::DumpSymbolContext(Stream *s)
|
|
{
|
|
SymbolContext sc;
|
|
CalculateSymbolContext(&sc);
|
|
if (sc.function)
|
|
sc.function->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 Block *block) const
|
|
{
|
|
// Block objects can't contain themselves...
|
|
if (this == block)
|
|
return false;
|
|
|
|
const Block *block_parent;
|
|
for (block_parent = block->GetParent();
|
|
block_parent != NULL;
|
|
block_parent = block_parent->GetParent())
|
|
{
|
|
if (block_parent == block)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
Block::Contains (const VMRange& range) const
|
|
{
|
|
return VMRange::ContainsRange(m_ranges, range);
|
|
}
|
|
|
|
Block *
|
|
Block::GetParent () const
|
|
{
|
|
if (m_parent_scope)
|
|
{
|
|
SymbolContext sc;
|
|
m_parent_scope->CalculateSymbolContext(&sc);
|
|
if (sc.block)
|
|
return sc.block;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Block *
|
|
Block::GetContainingInlinedBlock ()
|
|
{
|
|
if (InlinedFunctionInfo())
|
|
return this;
|
|
return GetInlinedParent ();
|
|
}
|
|
|
|
Block *
|
|
Block::GetInlinedParent ()
|
|
{
|
|
Block *parent_block = GetParent ();
|
|
if (parent_block)
|
|
{
|
|
if (parent_block->InlinedFunctionInfo())
|
|
return parent_block;
|
|
else
|
|
return parent_block->GetInlinedParent();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
bool
|
|
Block::GetRangeContainingOffset (const addr_t offset, VMRange &range)
|
|
{
|
|
uint32_t range_idx = VMRange::FindRangeIndexThatContainsValue (m_ranges, offset);
|
|
if (range_idx < m_ranges.size())
|
|
{
|
|
range = m_ranges[range_idx];
|
|
return true;
|
|
}
|
|
range.Clear();
|
|
return false;
|
|
}
|
|
|
|
|
|
bool
|
|
Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
|
|
{
|
|
SymbolContext sc;
|
|
CalculateSymbolContext(&sc);
|
|
if (sc.function)
|
|
{
|
|
const AddressRange &func_range = sc.function->GetAddressRange();
|
|
if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
|
|
{
|
|
const addr_t addr_offset = addr.GetOffset();
|
|
const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
|
|
if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
|
|
{
|
|
addr_t offset = addr_offset - func_offset;
|
|
|
|
uint32_t range_idx = VMRange::FindRangeIndexThatContainsValue (m_ranges, offset);
|
|
if (range_idx < m_ranges.size())
|
|
{
|
|
range.GetBaseAddress() = func_range.GetBaseAddress();
|
|
range.GetBaseAddress().SetOffset(func_offset + m_ranges[range_idx].GetBaseAddress());
|
|
range.SetByteSize(m_ranges[range_idx].GetByteSize());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
range.Clear();
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// 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_variable_list_sp.get())
|
|
mem_size += m_variable_list_sp->MemorySize();
|
|
return mem_size;
|
|
|
|
}
|
|
|
|
void
|
|
Block::AddChild(const BlockSP &child_block_sp)
|
|
{
|
|
if (child_block_sp)
|
|
{
|
|
Block *block_needs_sibling = NULL;
|
|
|
|
if (!m_children.empty())
|
|
block_needs_sibling = m_children.back().get();
|
|
|
|
child_block_sp->SetParentScope (this);
|
|
m_children.push_back (child_block_sp);
|
|
|
|
if (block_needs_sibling)
|
|
block_needs_sibling->SetSibling (child_block_sp.get());
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
|
|
|
|
VariableListSP
|
|
Block::GetVariableList (bool get_child_variables, bool can_create)
|
|
{
|
|
VariableListSP variable_list_sp;
|
|
if (m_parsed_block_variables == false)
|
|
{
|
|
if (m_variable_list_sp.get() == NULL && can_create)
|
|
{
|
|
m_parsed_block_variables = true;
|
|
SymbolContext sc;
|
|
CalculateSymbolContext(&sc);
|
|
assert(sc.module_sp);
|
|
sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
|
|
}
|
|
}
|
|
|
|
if (m_variable_list_sp.get())
|
|
{
|
|
variable_list_sp.reset(new VariableList());
|
|
if (variable_list_sp.get())
|
|
variable_list_sp->AddVariables(m_variable_list_sp.get());
|
|
|
|
if (get_child_variables)
|
|
{
|
|
Block *child_block = GetFirstChild();
|
|
while (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());
|
|
child_block = child_block->GetSibling();
|
|
}
|
|
}
|
|
}
|
|
|
|
return variable_list_sp;
|
|
}
|
|
|
|
uint32_t
|
|
Block::AppendVariables
|
|
(
|
|
bool can_create,
|
|
bool get_parent_variables,
|
|
bool stop_if_block_is_inlined_function,
|
|
VariableList *variable_list
|
|
)
|
|
{
|
|
uint32_t num_variables_added = 0;
|
|
VariableListSP variable_list_sp(GetVariableList(false, can_create));
|
|
|
|
bool is_inlined_function = InlinedFunctionInfo() != NULL;
|
|
if (variable_list_sp.get())
|
|
{
|
|
num_variables_added = variable_list_sp->GetSize();
|
|
variable_list->AddVariables(variable_list_sp.get());
|
|
}
|
|
|
|
if (get_parent_variables)
|
|
{
|
|
if (stop_if_block_is_inlined_function && is_inlined_function)
|
|
return num_variables_added;
|
|
|
|
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);
|
|
}
|
|
return num_variables_added;
|
|
}
|
|
|
|
void
|
|
Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
|
|
{
|
|
m_parsed_block_info = b;
|
|
if (set_children)
|
|
{
|
|
m_parsed_child_blocks = true;
|
|
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
|
|
child_block->SetBlockInfoHasBeenParsed (b, true);
|
|
}
|
|
}
|