| //===-- 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/lldb-private-log.h" |
| |
| #include "lldb/Core/Log.h" |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/Section.h" |
| #include "lldb/Symbol/Function.h" |
| #include "lldb/Symbol/SymbolFile.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_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, Target *target) const |
| { |
| *s << "id = " << ((const UserID&)*this); |
| |
| size_t num_ranges = m_ranges.GetSize(); |
| if (num_ranges > 0) |
| { |
| |
| addr_t base_addr = LLDB_INVALID_ADDRESS; |
| if (target) |
| base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(target); |
| if (base_addr == LLDB_INVALID_ADDRESS) |
| base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress(); |
| |
| s->Printf(", range%s = ", num_ranges > 1 ? "s" : ""); |
| for (size_t i=0; i<num_ranges; ++i) |
| { |
| const Range &range = m_ranges.GetEntryRef(i); |
| s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4); |
| } |
| } |
| |
| if (m_inlineInfoSP.get() != NULL) |
| { |
| bool show_fullpaths = (level == eDescriptionLevelVerbose); |
| m_inlineInfoSP->Dump(s, show_fullpaths); |
| } |
| } |
| |
| 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: ", this); |
| s->Indent(); |
| *s << "Block" << ((const UserID&)*this); |
| const Block* parent_block = GetParent(); |
| if (parent_block) |
| { |
| s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID()); |
| } |
| if (m_inlineInfoSP.get() != NULL) |
| { |
| bool show_fullpaths = false; |
| m_inlineInfoSP->Dump(s, show_fullpaths); |
| } |
| |
| if (!m_ranges.IsEmpty()) |
| { |
| *s << ", ranges ="; |
| |
| size_t num_ranges = m_ranges.GetSize(); |
| for (size_t i=0; i<num_ranges; ++i) |
| { |
| const Range &range = m_ranges.GetEntryRef(i); |
| if (parent_block != NULL && parent_block->Contains(range) == false) |
| *s << '!'; |
| else |
| *s << ' '; |
| s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4); |
| } |
| } |
| s->EOL(); |
| |
| if (depth > 0) |
| { |
| s->IndentMore(); |
| |
| if (m_variable_list_sp.get()) |
| { |
| m_variable_list_sp->Dump(s, show_context); |
| } |
| |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| (*pos)->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; |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| { |
| matching_block = (*pos)->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; |
| } |
| |
| lldb::ModuleSP |
| Block::CalculateSymbolContextModule () |
| { |
| if (m_parent_scope) |
| return m_parent_scope->CalculateSymbolContextModule (); |
| return lldb::ModuleSP(); |
| } |
| |
| CompileUnit * |
| Block::CalculateSymbolContextCompileUnit () |
| { |
| if (m_parent_scope) |
| return m_parent_scope->CalculateSymbolContextCompileUnit (); |
| return NULL; |
| } |
| |
| Function * |
| Block::CalculateSymbolContextFunction () |
| { |
| if (m_parent_scope) |
| return m_parent_scope->CalculateSymbolContextFunction (); |
| return NULL; |
| } |
| |
| Block * |
| Block::CalculateSymbolContextBlock () |
| { |
| return this; |
| } |
| |
| void |
| Block::DumpSymbolContext(Stream *s) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| function->DumpSymbolContext(s); |
| s->Printf(", Block{0x%8.8" PRIx64 "}", GetID()); |
| } |
| |
| void |
| Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr) |
| { |
| if (!m_ranges.IsEmpty()) |
| { |
| size_t num_ranges = m_ranges.GetSize(); |
| for (size_t i=0; i<num_ranges; ++i) |
| { |
| const Range &range = m_ranges.GetEntryRef(i); |
| s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4); |
| } |
| } |
| } |
| |
| bool |
| Block::Contains (addr_t range_offset) const |
| { |
| return m_ranges.FindEntryThatContains(range_offset) != NULL; |
| } |
| |
| bool |
| Block::Contains (const Block *block) const |
| { |
| if (this == block) |
| return false; // This block doesn't contain itself... |
| |
| // Walk the parent chain for "block" and see if any if them match this block |
| const Block *block_parent; |
| for (block_parent = block->GetParent(); |
| block_parent != NULL; |
| block_parent = block_parent->GetParent()) |
| { |
| if (this == block_parent) |
| return true; // One of the parents of "block" is this object! |
| } |
| return false; |
| } |
| |
| bool |
| Block::Contains (const Range& range) const |
| { |
| return m_ranges.FindEntryThatContains (range) != NULL; |
| } |
| |
| Block * |
| Block::GetParent () const |
| { |
| if (m_parent_scope) |
| return m_parent_scope->CalculateSymbolContextBlock(); |
| return NULL; |
| } |
| |
| Block * |
| Block::GetContainingInlinedBlock () |
| { |
| if (GetInlinedFunctionInfo()) |
| return this; |
| return GetInlinedParent (); |
| } |
| |
| Block * |
| Block::GetInlinedParent () |
| { |
| Block *parent_block = GetParent (); |
| if (parent_block) |
| { |
| if (parent_block->GetInlinedFunctionInfo()) |
| return parent_block; |
| else |
| return parent_block->GetInlinedParent(); |
| } |
| return NULL; |
| } |
| |
| |
| bool |
| Block::GetRangeContainingOffset (const addr_t offset, Range &range) |
| { |
| const Range *range_ptr = m_ranges.FindEntryThatContains (offset); |
| if (range_ptr) |
| { |
| range = *range_ptr; |
| return true; |
| } |
| range.Clear(); |
| return false; |
| } |
| |
| |
| bool |
| Block::GetRangeContainingAddress (const Address& addr, AddressRange &range) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| const AddressRange &func_range = 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; |
| |
| const Range *range_ptr = m_ranges.FindEntryThatContains (offset); |
| |
| if (range_ptr) |
| { |
| range.GetBaseAddress() = func_range.GetBaseAddress(); |
| range.GetBaseAddress().SetOffset(func_offset + range_ptr->GetRangeBase()); |
| range.SetByteSize(range_ptr->GetByteSize()); |
| return true; |
| } |
| } |
| } |
| } |
| range.Clear(); |
| return false; |
| } |
| |
| bool |
| Block::GetRangeContainingLoadAddress (lldb::addr_t load_addr, Target &target, AddressRange &range) |
| { |
| Address load_address; |
| load_address.SetLoadAddress(load_addr, &target); |
| AddressRange containing_range; |
| return GetRangeContainingAddress(load_address, containing_range); |
| } |
| |
| |
| uint32_t |
| Block::GetRangeIndexContainingAddress (const Address& addr) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| const AddressRange &func_range = 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; |
| return m_ranges.FindEntryIndexThatContains (offset); |
| } |
| } |
| } |
| return UINT32_MAX; |
| } |
| |
| bool |
| Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range) |
| { |
| if (range_idx < m_ranges.GetSize()) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| const Range &vm_range = m_ranges.GetEntryRef(range_idx); |
| range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); |
| range.GetBaseAddress().Slide(vm_range.GetRangeBase ()); |
| range.SetByteSize (vm_range.GetByteSize()); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Block::GetStartAddress (Address &addr) |
| { |
| if (m_ranges.IsEmpty()) |
| return false; |
| |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| addr = function->GetAddressRange().GetBaseAddress(); |
| addr.Slide(m_ranges.GetEntryRef(0).GetRangeBase ()); |
| return true; |
| } |
| return false; |
| } |
| |
| void |
| Block::FinalizeRanges () |
| { |
| m_ranges.Sort(); |
| m_ranges.CombineConsecutiveRanges (); |
| } |
| |
| void |
| Block::AddRange (const Range& range) |
| { |
| Block *parent_block = GetParent (); |
| if (parent_block && !parent_block->Contains(range)) |
| { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); |
| if (log) |
| { |
| ModuleSP module_sp (m_parent_scope->CalculateSymbolContextModule()); |
| Function *function = m_parent_scope->CalculateSymbolContextFunction(); |
| const addr_t function_file_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress(); |
| const addr_t block_start_addr = function_file_addr + range.GetRangeBase (); |
| const addr_t block_end_addr = function_file_addr + range.GetRangeEnd (); |
| Type *func_type = function->GetType(); |
| |
| const Declaration &func_decl = func_type->GetDeclaration(); |
| if (func_decl.GetLine()) |
| { |
| log->Printf ("warning: %s:%u block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s", |
| func_decl.GetFile().GetPath().c_str(), |
| func_decl.GetLine(), |
| GetID(), |
| (uint32_t)m_ranges.GetSize(), |
| block_start_addr, |
| block_end_addr, |
| parent_block->GetID(), |
| function->GetID(), |
| module_sp->GetFileSpec().GetPath().c_str()); |
| } |
| else |
| { |
| log->Printf ("warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s", |
| GetID(), |
| (uint32_t)m_ranges.GetSize(), |
| block_start_addr, |
| block_end_addr, |
| parent_block->GetID(), |
| function->GetID(), |
| module_sp->GetFileSpec().GetPath().c_str()); |
| } |
| } |
| parent_block->AddRange (range); |
| } |
| m_ranges.Append(range); |
| } |
| |
| // 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.GetSize() * sizeof(Range); |
| 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) |
| { |
| child_block_sp->SetParentScope (this); |
| m_children.push_back (child_block_sp); |
| } |
| } |
| |
| 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::GetBlockVariableList (bool can_create) |
| { |
| 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); |
| } |
| } |
| return m_variable_list_sp; |
| } |
| |
| 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) |
| { |
| num_variables_added += block_var_list->GetSize(); |
| variable_list->AddVariables (block_var_list); |
| } |
| |
| if (get_child_block_variables) |
| { |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| { |
| Block *child_block = pos->get(); |
| 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 num_variables_added; |
| } |
| |
| 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(GetBlockVariableList(can_create)); |
| |
| bool is_inlined_function = GetInlinedFunctionInfo() != 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; |
| } |
| |
| clang::DeclContext * |
| Block::GetClangDeclContext() |
| { |
| SymbolContext sc; |
| |
| CalculateSymbolContext (&sc); |
| |
| if (!sc.module_sp) |
| return NULL; |
| |
| SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor(); |
| |
| if (!sym_vendor) |
| return NULL; |
| |
| SymbolFile *sym_file = sym_vendor->GetSymbolFile(); |
| |
| if (!sym_file) |
| return NULL; |
| |
| return sym_file->GetClangDeclContextForTypeUID (sc, m_uid); |
| } |
| |
| void |
| Block::SetBlockInfoHasBeenParsed (bool b, bool set_children) |
| { |
| m_parsed_block_info = b; |
| if (set_children) |
| { |
| m_parsed_child_blocks = true; |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| (*pos)->SetBlockInfoHasBeenParsed (b, true); |
| } |
| } |
| |
| void |
| Block::SetDidParseVariables (bool b, bool set_children) |
| { |
| m_parsed_block_variables = b; |
| if (set_children) |
| { |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| (*pos)->SetDidParseVariables (b, true); |
| } |
| } |
| |
| |
| Block * |
| Block::GetSibling() const |
| { |
| if (m_parent_scope) |
| { |
| Block *parent_block = GetParent(); |
| if (parent_block) |
| return parent_block->GetSiblingForChild (this); |
| } |
| return NULL; |
| } |
| // A parent of child blocks can be asked to find a sibling block given |
| // one of its child blocks |
| Block * |
| Block::GetSiblingForChild (const Block *child_block) const |
| { |
| if (!m_children.empty()) |
| { |
| collection::const_iterator pos, end = m_children.end(); |
| for (pos = m_children.begin(); pos != end; ++pos) |
| { |
| if (pos->get() == child_block) |
| { |
| if (++pos != end) |
| return pos->get(); |
| break; |
| } |
| } |
| } |
| return NULL; |
| } |
| |