//===-- Block.cpp ---------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Symbol/Block.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Utility/Log.h" #include using namespace lldb; using namespace lldb_private; Block::Block(lldb::user_id_t uid) : UserID(uid), m_parent_scope(nullptr), 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); DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4); } } if (m_inlineInfoSP.get() != nullptr) { 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: ", static_cast(this)); s->Indent(); *s << "Block" << static_cast(*this); const Block *parent_block = GetParent(); if (parent_block) { s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID()); } if (m_inlineInfoSP.get() != nullptr) { 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 != nullptr && !parent_block->Contains(range)) *s << '!'; else *s << ' '; DumpAddressRange(s->AsRawOstream(), 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 = nullptr; 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 nullptr; } Function *Block::CalculateSymbolContextFunction() { if (m_parent_scope) return m_parent_scope->CalculateSymbolContextFunction(); return nullptr; } 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); DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4); } } } bool Block::Contains(addr_t range_offset) const { return m_ranges.FindEntryThatContains(range_offset) != nullptr; } 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 != nullptr; 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) != nullptr; } Block *Block::GetParent() const { if (m_parent_scope) return m_parent_scope->CalculateSymbolContextBlock(); return nullptr; } 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 nullptr; } Block *Block::GetContainingInlinedBlockWithCallSite( const Declaration &find_call_site) { Block *inlined_block = GetContainingInlinedBlock(); while (inlined_block) { const auto *function_info = inlined_block->GetInlinedFunctionInfo(); if (function_info && function_info->GetCallSite().FileAndLineEqual(find_call_site)) return inlined_block; inlined_block = inlined_block->GetInlinedParent(); } return nullptr; } 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()) { LLDB_LOGF(log, "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 { LLDB_LOGF(log, "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 = std::make_shared(name, mangled, decl_ptr, call_decl_ptr); } VariableListSP Block::GetBlockVariableList(bool can_create) { if (!m_parsed_block_variables) { if (m_variable_list_sp.get() == nullptr && can_create) { m_parsed_block_variables = true; SymbolContext sc; CalculateSymbolContext(&sc); assert(sc.module_sp); sc.module_sp->GetSymbolFile()->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, const std::function &filter, VariableList *variable_list) { uint32_t num_variables_added = 0; VariableList *block_var_list = GetBlockVariableList(can_create).get(); if (block_var_list) { for (const VariableSP &var_sp : *block_var_list) { if (filter(var_sp.get())) { num_variables_added++; variable_list->AddVariable(var_sp); } } } 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 || child_block->GetInlinedFunctionInfo() == nullptr) { num_variables_added += child_block->AppendBlockVariables( can_create, get_child_block_variables, stop_if_child_block_is_inlined_function, filter, variable_list); } } } return num_variables_added; } uint32_t Block::AppendVariables(bool can_create, bool get_parent_variables, bool stop_if_block_is_inlined_function, const std::function &filter, VariableList *variable_list) { uint32_t num_variables_added = 0; VariableListSP variable_list_sp(GetBlockVariableList(can_create)); bool is_inlined_function = GetInlinedFunctionInfo() != nullptr; if (variable_list_sp) { for (size_t i = 0; i < variable_list_sp->GetSize(); ++i) { VariableSP variable = variable_list_sp->GetVariableAtIndex(i); if (filter(variable.get())) { num_variables_added++; variable_list->AddVariable(variable); } } } 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, filter, variable_list); } return num_variables_added; } SymbolFile *Block::GetSymbolFile() { if (ModuleSP module_sp = CalculateSymbolContextModule()) return module_sp->GetSymbolFile(); return nullptr; } CompilerDeclContext Block::GetDeclContext() { if (SymbolFile *sym_file = GetSymbolFile()) return sym_file->GetDeclContextForUID(GetID()); return CompilerDeclContext(); } 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 nullptr; } // 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 nullptr; }