| //===-- 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.size(); |
| if (num_ranges) |
| { |
| |
| 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" : ""); |
| std::vector<VMRange>::const_iterator pos, end = m_ranges.end(); |
| for (pos = m_ranges.begin(); pos != end; ++pos) |
| pos->Dump(s, base_addr, 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.8x}", parent_block->GetID()); |
| } |
| if (m_inlineInfoSP.get() != NULL) |
| { |
| bool show_fullpaths = false; |
| m_inlineInfoSP->Dump(s, show_fullpaths); |
| } |
| |
| 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); |
| } |
| |
| 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; |
| } |
| |
| Module * |
| Block::CalculateSymbolContextModule () |
| { |
| if (m_parent_scope) |
| return m_parent_scope->CalculateSymbolContextModule (); |
| return NULL; |
| } |
| |
| 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::DumpStopContext |
| ( |
| Stream *s, |
| const SymbolContext *sc_ptr, |
| const Declaration *child_inline_call_site, |
| bool show_fullpaths, |
| bool show_inline_blocks) |
| { |
| const InlineFunctionInfo* inline_info = NULL; |
| Block* inlined_block; |
| if (sc_ptr) |
| inlined_block = GetContainingInlinedBlock (); |
| else |
| inlined_block = GetInlinedParent(); |
| |
| if (inlined_block) |
| inline_info = inlined_block->GetInlinedFunctionInfo(); |
| const Declaration *inline_call_site = child_inline_call_site; |
| if (inline_info) |
| { |
| inline_call_site = &inline_info->GetCallSite(); |
| if (sc_ptr) |
| { |
| // First frame in a frame with inlined functions |
| s->PutCString (" [inlined]"); |
| } |
| if (show_inline_blocks && child_inline_call_site) |
| s->EOL(); |
| else |
| s->PutChar(' '); |
| |
| if (sc_ptr == NULL) |
| s->Indent(); |
| |
| s->PutCString(inline_info->GetName ().AsCString()); |
| |
| if (child_inline_call_site && child_inline_call_site->IsValid()) |
| { |
| s->PutCString(" at "); |
| child_inline_call_site->DumpStopContext (s, show_fullpaths); |
| } |
| } |
| |
| // The first call to this function from something that has a symbol |
| // context will pass in a valid sc_ptr. Subsequent calls to this function |
| // from this function for inline purposes will NULL out sc_ptr. So on the |
| // first time through we dump the line table entry (which is always at the |
| // deepest inline code block). And subsequent calls to this function we |
| // will use hte inline call site information to print line numbers. |
| if (sc_ptr) |
| { |
| // If we have any inlined functions, this will be the deepest most |
| // inlined location |
| if (sc_ptr->line_entry.IsValid()) |
| { |
| s->PutCString(" at "); |
| sc_ptr->line_entry.DumpStopContext (s, show_fullpaths); |
| } |
| } |
| |
| if (show_inline_blocks) |
| { |
| if (inlined_block) |
| { |
| inlined_block->Block::DumpStopContext (s, |
| NULL, |
| inline_call_site, |
| show_fullpaths, |
| show_inline_blocks); |
| } |
| else if (child_inline_call_site) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| s->EOL(); |
| s->Indent (function->GetMangled().GetName().AsCString()); |
| if (child_inline_call_site && child_inline_call_site->IsValid()) |
| { |
| s->PutCString(" at "); |
| child_inline_call_site->DumpStopContext (s, show_fullpaths); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| void |
| Block::DumpSymbolContext(Stream *s) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| function->DumpSymbolContext(s); |
| s->Printf(", Block{0x%8.8x}", GetID()); |
| } |
| |
| void |
| Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr) |
| { |
| if (!m_ranges.empty()) |
| { |
| std::vector<VMRange>::const_iterator pos, end = m_ranges.end(); |
| for (pos = m_ranges.begin(); pos != end; ++pos) |
| pos->Dump (s, base_addr); |
| } |
| } |
| |
| bool |
| Block::Contains (addr_t range_offset) const |
| { |
| return VMRange::ContainsValue(m_ranges, range_offset); |
| } |
| |
| 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 VMRange& range) const |
| { |
| return VMRange::ContainsRange(m_ranges, range); |
| } |
| |
| 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, 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, uint32_t *range_idx_ptr) |
| { |
| 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; |
| |
| 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()); |
| if (range_idx_ptr) |
| *range_idx_ptr = range_idx; |
| return true; |
| } |
| } |
| } |
| } |
| if (range_idx_ptr) |
| *range_idx_ptr = UINT32_MAX; |
| range.Clear(); |
| return false; |
| } |
| |
| bool |
| Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range) |
| { |
| if (range_idx < m_ranges.size()) |
| { |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); |
| range.GetBaseAddress().Slide(m_ranges[range_idx].GetBaseAddress ()); |
| range.SetByteSize (m_ranges[range_idx].GetByteSize()); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Block::GetStartAddress (Address &addr) |
| { |
| if (m_ranges.empty()) |
| return false; |
| |
| Function *function = CalculateSymbolContextFunction(); |
| if (function) |
| { |
| addr = function->GetAddressRange().GetBaseAddress(); |
| addr.Slide(m_ranges.front().GetBaseAddress ()); |
| return true; |
| } |
| return false; |
| } |
| |
| void |
| Block::AddRange (const VMRange& new_range) |
| { |
| Block *parent_block = GetParent (); |
| if (parent_block && !parent_block->Contains(new_range)) |
| { |
| LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); |
| if (log) |
| { |
| Module *module = 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 + new_range.GetBaseAddress (); |
| const addr_t block_end_addr = function_file_addr + new_range.GetEndAddress (); |
| Type *func_type = function->GetType(); |
| |
| const Declaration &func_decl = func_type->GetDeclaration(); |
| if (func_decl.GetLine()) |
| { |
| log->Printf ("warning: %s/%s:%u block {0x%8.8x} has range[%u] [0x%llx - 0x%llx) which is not contained in parent block {0x%8.8x} in function {0x%8.8x} from %s/%s", |
| func_decl.GetFile().GetDirectory().GetCString(), |
| func_decl.GetFile().GetFilename().GetCString(), |
| func_decl.GetLine(), |
| GetID(), |
| (uint32_t)m_ranges.size(), |
| block_start_addr, |
| block_end_addr, |
| parent_block->GetID(), |
| function->GetID(), |
| module->GetFileSpec().GetDirectory().GetCString(), |
| module->GetFileSpec().GetFilename().GetCString()); |
| } |
| else |
| { |
| log->Printf ("warning: block {0x%8.8x} has range[%u] [0x%llx - 0x%llx) which is not contained in parent block {0x%8.8x} in function {0x%8.8x} from %s/%s", |
| GetID(), |
| (uint32_t)m_ranges.size(), |
| block_start_addr, |
| block_end_addr, |
| parent_block->GetID(), |
| function->GetID(), |
| module->GetFileSpec().GetDirectory().GetCString(), |
| module->GetFileSpec().GetFilename().GetCString()); |
| } |
| } |
| parent_block->AddRange (new_range); |
| } |
| m_ranges.push_back(new_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.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) |
| { |
| 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::GetClangDeclContextForInlinedFunction() |
| { |
| 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; |
| } |
| |