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