//===-- 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; }