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