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