519 lines · cpp
1//===-- Block.cpp ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Symbol/Block.h"10 11#include "lldb/Core/Module.h"12#include "lldb/Core/Section.h"13#include "lldb/Symbol/Function.h"14#include "lldb/Symbol/SymbolFile.h"15#include "lldb/Symbol/VariableList.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"18 19#include <memory>20 21using namespace lldb;22using namespace lldb_private;23 24Block::Block(Function &function, user_id_t function_uid)25 : Block(function_uid, function) {}26 27Block::Block(lldb::user_id_t uid, SymbolContextScope &parent_scope)28 : UserID(uid), m_parent_scope(parent_scope), m_parsed_block_info(false),29 m_parsed_block_variables(false), m_parsed_child_blocks(false) {}30 31Block::~Block() = default;32 33void Block::GetDescription(Stream *s, Function *function,34 lldb::DescriptionLevel level, Target *target) const {35 *s << "id = " << ((const UserID &)*this);36 37 size_t num_ranges = m_ranges.GetSize();38 if (num_ranges > 0) {39 40 addr_t base_addr = LLDB_INVALID_ADDRESS;41 if (target)42 base_addr = function->GetAddress().GetLoadAddress(target);43 if (base_addr == LLDB_INVALID_ADDRESS)44 base_addr = function->GetAddress().GetFileAddress();45 46 s->Printf(", range%s = ", num_ranges > 1 ? "s" : "");47 for (size_t i = 0; i < num_ranges; ++i) {48 const Range &range = m_ranges.GetEntryRef(i);49 DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(),50 base_addr + range.GetRangeEnd(), 4);51 }52 }53 54 if (m_inlineInfoSP.get() != nullptr) {55 bool show_fullpaths = (level == eDescriptionLevelVerbose);56 m_inlineInfoSP->Dump(s, show_fullpaths);57 }58}59 60void Block::Dump(Stream *s, addr_t base_addr, int32_t depth,61 bool show_context) const {62 if (depth < 0) {63 Block *parent = GetParent();64 if (parent) {65 // We have a depth that is less than zero, print our parent blocks first66 parent->Dump(s, base_addr, depth + 1, show_context);67 }68 }69 70 s->Printf("%p: ", static_cast<const void *>(this));71 s->Indent();72 *s << "Block" << static_cast<const UserID &>(*this);73 const Block *parent_block = GetParent();74 if (parent_block) {75 s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID());76 }77 if (m_inlineInfoSP.get() != nullptr) {78 bool show_fullpaths = false;79 m_inlineInfoSP->Dump(s, show_fullpaths);80 }81 82 if (!m_ranges.IsEmpty()) {83 *s << ", ranges =";84 85 size_t num_ranges = m_ranges.GetSize();86 for (size_t i = 0; i < num_ranges; ++i) {87 const Range &range = m_ranges.GetEntryRef(i);88 if (parent_block != nullptr && !parent_block->Contains(range))89 *s << '!';90 else91 *s << ' ';92 DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(),93 base_addr + range.GetRangeEnd(), 4);94 }95 }96 s->EOL();97 98 if (depth > 0) {99 s->IndentMore();100 101 if (m_variable_list_sp.get()) {102 m_variable_list_sp->Dump(s, show_context);103 }104 105 collection::const_iterator pos, end = m_children.end();106 for (pos = m_children.begin(); pos != end; ++pos)107 (*pos)->Dump(s, base_addr, depth - 1, show_context);108 109 s->IndentLess();110 }111}112 113Block *Block::FindBlockByID(user_id_t block_id) {114 if (block_id == GetID())115 return this;116 117 Block *matching_block = nullptr;118 collection::const_iterator pos, end = m_children.end();119 for (pos = m_children.begin(); pos != end; ++pos) {120 matching_block = (*pos)->FindBlockByID(block_id);121 if (matching_block)122 break;123 }124 return matching_block;125}126 127Block *Block::FindInnermostBlockByOffset(const lldb::addr_t offset) {128 if (!Contains(offset))129 return nullptr;130 for (const BlockSP &block_sp : m_children) {131 if (Block *block = block_sp->FindInnermostBlockByOffset(offset))132 return block;133 }134 return this;135}136 137void Block::CalculateSymbolContext(SymbolContext *sc) {138 m_parent_scope.CalculateSymbolContext(sc);139 sc->block = this;140}141 142lldb::ModuleSP Block::CalculateSymbolContextModule() {143 return m_parent_scope.CalculateSymbolContextModule();144}145 146CompileUnit *Block::CalculateSymbolContextCompileUnit() {147 return m_parent_scope.CalculateSymbolContextCompileUnit();148}149 150Function *Block::CalculateSymbolContextFunction() {151 return m_parent_scope.CalculateSymbolContextFunction();152}153 154Block *Block::CalculateSymbolContextBlock() { return this; }155 156Function &Block::GetFunction() {157 // Blocks always have an enclosing function because their parent is either a158 // function or a block (which has a parent, inductively).159 Function *function = CalculateSymbolContextFunction();160 assert(function);161 return *function;162}163 164void Block::DumpSymbolContext(Stream *s) {165 GetFunction().DumpSymbolContext(s);166 s->Printf(", Block{0x%8.8" PRIx64 "}", GetID());167}168 169void Block::DumpAddressRanges(Stream *s, lldb::addr_t base_addr) {170 if (!m_ranges.IsEmpty()) {171 size_t num_ranges = m_ranges.GetSize();172 for (size_t i = 0; i < num_ranges; ++i) {173 const Range &range = m_ranges.GetEntryRef(i);174 DumpAddressRange(s->AsRawOstream(), base_addr + range.GetRangeBase(),175 base_addr + range.GetRangeEnd(), 4);176 }177 }178}179 180bool Block::Contains(addr_t range_offset) const {181 return m_ranges.FindEntryThatContains(range_offset) != nullptr;182}183 184bool Block::Contains(const Block *block) const {185 if (this == block)186 return false; // This block doesn't contain itself...187 188 // Walk the parent chain for "block" and see if any if them match this block189 const Block *block_parent;190 for (block_parent = block->GetParent(); block_parent != nullptr;191 block_parent = block_parent->GetParent()) {192 if (this == block_parent)193 return true; // One of the parents of "block" is this object!194 }195 return false;196}197 198bool Block::Contains(const Range &range) const {199 return m_ranges.FindEntryThatContains(range) != nullptr;200}201 202Block *Block::GetParent() const {203 return m_parent_scope.CalculateSymbolContextBlock();204}205 206Block *Block::GetContainingInlinedBlock() {207 if (GetInlinedFunctionInfo())208 return this;209 return GetInlinedParent();210}211 212Block *Block::GetInlinedParent() {213 Block *parent_block = GetParent();214 if (parent_block) {215 if (parent_block->GetInlinedFunctionInfo())216 return parent_block;217 else218 return parent_block->GetInlinedParent();219 }220 return nullptr;221}222 223Block *Block::GetContainingInlinedBlockWithCallSite(224 const Declaration &find_call_site) {225 Block *inlined_block = GetContainingInlinedBlock();226 227 while (inlined_block) {228 const auto *function_info = inlined_block->GetInlinedFunctionInfo();229 230 if (function_info &&231 function_info->GetCallSite().FileAndLineEqual(find_call_site, true))232 return inlined_block;233 inlined_block = inlined_block->GetInlinedParent();234 }235 return nullptr;236}237 238bool Block::GetRangeContainingOffset(const addr_t offset, Range &range) {239 const Range *range_ptr = m_ranges.FindEntryThatContains(offset);240 if (range_ptr) {241 range = *range_ptr;242 return true;243 }244 range.Clear();245 return false;246}247 248bool Block::GetRangeContainingAddress(const Address &addr,249 AddressRange &range) {250 Function &function = GetFunction();251 if (uint32_t idx = GetRangeIndexContainingAddress(addr); idx != UINT32_MAX) {252 const Range *range_ptr = m_ranges.GetEntryAtIndex(idx);253 assert(range_ptr);254 255 Address func_addr = function.GetAddress();256 range.GetBaseAddress() =257 Address(func_addr.GetFileAddress() + range_ptr->GetRangeBase(),258 func_addr.GetModule()->GetSectionList());259 range.SetByteSize(range_ptr->GetByteSize());260 return true;261 }262 range.Clear();263 return false;264}265 266bool Block::GetRangeContainingLoadAddress(lldb::addr_t load_addr,267 Target &target, AddressRange &range) {268 Address load_address;269 load_address.SetLoadAddress(load_addr, &target);270 AddressRange containing_range;271 return GetRangeContainingAddress(load_address, containing_range);272}273 274uint32_t Block::GetRangeIndexContainingAddress(const Address &addr) {275 Function &function = GetFunction();276 277 const Address &func_addr = function.GetAddress();278 if (addr.GetModule() != func_addr.GetModule())279 return UINT32_MAX;280 281 const addr_t file_addr = addr.GetFileAddress();282 const addr_t func_file_addr = func_addr.GetFileAddress();283 return m_ranges.FindEntryIndexThatContains(file_addr - func_file_addr);284}285 286static AddressRange ToAddressRange(const Address &func_addr,287 const Block::Range &block_range) {288 assert(func_addr.GetModule());289 return AddressRange(func_addr.GetFileAddress() + block_range.base,290 block_range.size,291 func_addr.GetModule()->GetSectionList());292}293 294bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) {295 if (range_idx >= m_ranges.GetSize())296 return false;297 298 Address addr = GetFunction().GetAddress();299 if (!addr.GetModule())300 return false;301 302 range = ToAddressRange(addr, m_ranges.GetEntryRef(range_idx));303 return true;304}305 306AddressRanges Block::GetRanges() {307 Address addr = GetFunction().GetAddress();308 if (!addr.GetModule())309 return {};310 311 AddressRanges ranges;312 for (size_t i = 0, e = m_ranges.GetSize(); i < e; ++i)313 ranges.push_back(ToAddressRange(addr, m_ranges.GetEntryRef(i)));314 return ranges;315}316 317bool Block::GetStartAddress(Address &addr) {318 Address func_addr = GetFunction().GetAddress();319 if (!func_addr.GetModule() || m_ranges.IsEmpty())320 return false;321 322 addr = ToAddressRange(func_addr, m_ranges.GetEntryRef(0)).GetBaseAddress();323 return true;324}325 326void Block::FinalizeRanges() {327 m_ranges.Sort();328 m_ranges.CombineConsecutiveRanges();329}330 331void Block::AddRange(const Range &range) {332 Block *parent_block = GetParent();333 if (parent_block && !parent_block->Contains(range)) {334 Log *log = GetLog(LLDBLog::Symbols);335 if (log) {336 ModuleSP module_sp(m_parent_scope.CalculateSymbolContextModule());337 Function &function = GetFunction();338 const addr_t function_file_addr = function.GetAddress().GetFileAddress();339 const addr_t block_start_addr = function_file_addr + range.GetRangeBase();340 const addr_t block_end_addr = function_file_addr + range.GetRangeEnd();341 Type *func_type = function.GetType();342 343 const Declaration &func_decl = func_type->GetDeclaration();344 if (func_decl.GetLine()) {345 LLDB_LOGF(log,346 "warning: %s:%u block {0x%8.8" PRIx64347 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64348 ") which is not contained in parent block {0x%8.8" PRIx64349 "} in function {0x%8.8" PRIx64 "} from %s",350 func_decl.GetFile().GetPath().c_str(), func_decl.GetLine(),351 GetID(), (uint32_t)m_ranges.GetSize(), block_start_addr,352 block_end_addr, parent_block->GetID(), function.GetID(),353 module_sp->GetFileSpec().GetPath().c_str());354 } else {355 LLDB_LOGF(log,356 "warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64357 " - 0x%" PRIx64358 ") which is not contained in parent block {0x%8.8" PRIx64359 "} in function {0x%8.8" PRIx64 "} from %s",360 GetID(), (uint32_t)m_ranges.GetSize(), block_start_addr,361 block_end_addr, parent_block->GetID(), function.GetID(),362 module_sp->GetFileSpec().GetPath().c_str());363 }364 }365 parent_block->AddRange(range);366 }367 m_ranges.Append(range);368}369 370// Return the current number of bytes that this object occupies in memory371size_t Block::MemorySize() const {372 size_t mem_size = sizeof(Block) + m_ranges.GetSize() * sizeof(Range);373 if (m_inlineInfoSP.get())374 mem_size += m_inlineInfoSP->MemorySize();375 if (m_variable_list_sp.get())376 mem_size += m_variable_list_sp->MemorySize();377 return mem_size;378}379 380BlockSP Block::CreateChild(user_id_t uid) {381 m_children.push_back(std::shared_ptr<Block>(new Block(uid, *this)));382 return m_children.back();383}384 385void Block::SetInlinedFunctionInfo(const char *name, const char *mangled,386 const Declaration *decl_ptr,387 const Declaration *call_decl_ptr) {388 m_inlineInfoSP = std::make_shared<InlineFunctionInfo>(name, mangled, decl_ptr,389 call_decl_ptr);390}391 392VariableListSP Block::GetBlockVariableList(bool can_create) {393 if (!m_parsed_block_variables) {394 if (m_variable_list_sp.get() == nullptr && can_create) {395 m_parsed_block_variables = true;396 SymbolContext sc;397 CalculateSymbolContext(&sc);398 assert(sc.module_sp);399 sc.module_sp->GetSymbolFile()->ParseVariablesForContext(sc);400 }401 }402 return m_variable_list_sp;403}404 405uint32_t406Block::AppendBlockVariables(bool can_create, bool get_child_block_variables,407 bool stop_if_child_block_is_inlined_function,408 const std::function<bool(Variable *)> &filter,409 VariableList *variable_list) {410 uint32_t num_variables_added = 0;411 VariableList *block_var_list = GetBlockVariableList(can_create).get();412 if (block_var_list) {413 for (const VariableSP &var_sp : *block_var_list) {414 if (filter(var_sp.get())) {415 num_variables_added++;416 variable_list->AddVariable(var_sp);417 }418 }419 }420 421 if (get_child_block_variables) {422 collection::const_iterator pos, end = m_children.end();423 for (pos = m_children.begin(); pos != end; ++pos) {424 Block *child_block = pos->get();425 if (!stop_if_child_block_is_inlined_function ||426 child_block->GetInlinedFunctionInfo() == nullptr) {427 num_variables_added += child_block->AppendBlockVariables(428 can_create, get_child_block_variables,429 stop_if_child_block_is_inlined_function, filter, variable_list);430 }431 }432 }433 return num_variables_added;434}435 436uint32_t Block::AppendVariables(bool can_create, bool get_parent_variables,437 bool stop_if_block_is_inlined_function,438 const std::function<bool(Variable *)> &filter,439 VariableList *variable_list) {440 uint32_t num_variables_added = 0;441 VariableListSP variable_list_sp(GetBlockVariableList(can_create));442 443 bool is_inlined_function = GetInlinedFunctionInfo() != nullptr;444 if (variable_list_sp) {445 for (size_t i = 0; i < variable_list_sp->GetSize(); ++i) {446 VariableSP variable = variable_list_sp->GetVariableAtIndex(i);447 if (filter(variable.get())) {448 num_variables_added++;449 variable_list->AddVariable(variable);450 }451 }452 }453 454 if (get_parent_variables) {455 if (stop_if_block_is_inlined_function && is_inlined_function)456 return num_variables_added;457 458 Block *parent_block = GetParent();459 if (parent_block)460 num_variables_added += parent_block->AppendVariables(461 can_create, get_parent_variables, stop_if_block_is_inlined_function,462 filter, variable_list);463 }464 return num_variables_added;465}466 467SymbolFile *Block::GetSymbolFile() {468 if (ModuleSP module_sp = CalculateSymbolContextModule())469 return module_sp->GetSymbolFile();470 return nullptr;471}472 473CompilerDeclContext Block::GetDeclContext() {474 if (SymbolFile *sym_file = GetSymbolFile())475 return sym_file->GetDeclContextForUID(GetID());476 return CompilerDeclContext();477}478 479void Block::SetBlockInfoHasBeenParsed(bool b, bool set_children) {480 m_parsed_block_info = b;481 if (set_children) {482 m_parsed_child_blocks = true;483 collection::const_iterator pos, end = m_children.end();484 for (pos = m_children.begin(); pos != end; ++pos)485 (*pos)->SetBlockInfoHasBeenParsed(b, true);486 }487}488 489void Block::SetDidParseVariables(bool b, bool set_children) {490 m_parsed_block_variables = b;491 if (set_children) {492 collection::const_iterator pos, end = m_children.end();493 for (pos = m_children.begin(); pos != end; ++pos)494 (*pos)->SetDidParseVariables(b, true);495 }496}497 498Block *Block::GetSibling() const {499 if (Block *parent_block = GetParent())500 return parent_block->GetSiblingForChild(this);501 return nullptr;502}503 504// A parent of child blocks can be asked to find a sibling block given505// one of its child blocks506Block *Block::GetSiblingForChild(const Block *child_block) const {507 if (!m_children.empty()) {508 collection::const_iterator pos, end = m_children.end();509 for (pos = m_children.begin(); pos != end; ++pos) {510 if (pos->get() == child_block) {511 if (++pos != end)512 return pos->get();513 break;514 }515 }516 }517 return nullptr;518}519