1 //===-- Symbol.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/Symbol.h" 11 12 #include "lldb/Core/Module.h" 13 #include "lldb/Core/ModuleSpec.h" 14 #include "lldb/Core/Section.h" 15 #include "lldb/Core/Stream.h" 16 #include "lldb/Symbol/ObjectFile.h" 17 #include "lldb/Symbol/Symtab.h" 18 #include "lldb/Symbol/Function.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Symbol/SymbolVendor.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 27 Symbol::Symbol() : 28 SymbolContextScope (), 29 m_uid (UINT32_MAX), 30 m_type_data (0), 31 m_type_data_resolved (false), 32 m_is_synthetic (false), 33 m_is_debug (false), 34 m_is_external (false), 35 m_size_is_sibling (false), 36 m_size_is_synthesized (false), 37 m_size_is_valid (false), 38 m_demangled_is_synthesized (false), 39 m_contains_linker_annotations (false), 40 m_type (eSymbolTypeInvalid), 41 m_mangled (), 42 m_addr_range (), 43 m_flags () 44 { 45 } 46 47 Symbol::Symbol 48 ( 49 uint32_t symID, 50 const char *name, 51 bool name_is_mangled, 52 SymbolType type, 53 bool external, 54 bool is_debug, 55 bool is_trampoline, 56 bool is_artificial, 57 const lldb::SectionSP §ion_sp, 58 addr_t offset, 59 addr_t size, 60 bool size_is_valid, 61 bool contains_linker_annotations, 62 uint32_t flags 63 ) : 64 SymbolContextScope (), 65 m_uid (symID), 66 m_type_data (0), 67 m_type_data_resolved (false), 68 m_is_synthetic (is_artificial), 69 m_is_debug (is_debug), 70 m_is_external (external), 71 m_size_is_sibling (false), 72 m_size_is_synthesized (false), 73 m_size_is_valid (size_is_valid || size > 0), 74 m_demangled_is_synthesized (false), 75 m_contains_linker_annotations (contains_linker_annotations), 76 m_type (type), 77 m_mangled (ConstString(name), name_is_mangled), 78 m_addr_range (section_sp, offset, size), 79 m_flags (flags) 80 { 81 } 82 83 Symbol::Symbol 84 ( 85 uint32_t symID, 86 const Mangled &mangled, 87 SymbolType type, 88 bool external, 89 bool is_debug, 90 bool is_trampoline, 91 bool is_artificial, 92 const AddressRange &range, 93 bool size_is_valid, 94 bool contains_linker_annotations, 95 uint32_t flags 96 ) : 97 SymbolContextScope (), 98 m_uid (symID), 99 m_type_data (0), 100 m_type_data_resolved (false), 101 m_is_synthetic (is_artificial), 102 m_is_debug (is_debug), 103 m_is_external (external), 104 m_size_is_sibling (false), 105 m_size_is_synthesized (false), 106 m_size_is_valid (size_is_valid || range.GetByteSize() > 0), 107 m_demangled_is_synthesized (false), 108 m_contains_linker_annotations (contains_linker_annotations), 109 m_type (type), 110 m_mangled (mangled), 111 m_addr_range (range), 112 m_flags (flags) 113 { 114 } 115 116 Symbol::Symbol(const Symbol& rhs): 117 SymbolContextScope (rhs), 118 m_uid (rhs.m_uid), 119 m_type_data (rhs.m_type_data), 120 m_type_data_resolved (rhs.m_type_data_resolved), 121 m_is_synthetic (rhs.m_is_synthetic), 122 m_is_debug (rhs.m_is_debug), 123 m_is_external (rhs.m_is_external), 124 m_size_is_sibling (rhs.m_size_is_sibling), 125 m_size_is_synthesized (false), 126 m_size_is_valid (rhs.m_size_is_valid), 127 m_demangled_is_synthesized (rhs.m_demangled_is_synthesized), 128 m_contains_linker_annotations (rhs.m_contains_linker_annotations), 129 m_type (rhs.m_type), 130 m_mangled (rhs.m_mangled), 131 m_addr_range (rhs.m_addr_range), 132 m_flags (rhs.m_flags) 133 { 134 } 135 136 const Symbol& 137 Symbol::operator= (const Symbol& rhs) 138 { 139 if (this != &rhs) 140 { 141 SymbolContextScope::operator= (rhs); 142 m_uid = rhs.m_uid; 143 m_type_data = rhs.m_type_data; 144 m_type_data_resolved = rhs.m_type_data_resolved; 145 m_is_synthetic = rhs.m_is_synthetic; 146 m_is_debug = rhs.m_is_debug; 147 m_is_external = rhs.m_is_external; 148 m_size_is_sibling = rhs.m_size_is_sibling; 149 m_size_is_synthesized = rhs.m_size_is_sibling; 150 m_size_is_valid = rhs.m_size_is_valid; 151 m_demangled_is_synthesized = rhs.m_demangled_is_synthesized; 152 m_contains_linker_annotations = rhs.m_contains_linker_annotations; 153 m_type = rhs.m_type; 154 m_mangled = rhs.m_mangled; 155 m_addr_range = rhs.m_addr_range; 156 m_flags = rhs.m_flags; 157 } 158 return *this; 159 } 160 161 void 162 Symbol::Clear() 163 { 164 m_uid = UINT32_MAX; 165 m_mangled.Clear(); 166 m_type_data = 0; 167 m_type_data_resolved = false; 168 m_is_synthetic = false; 169 m_is_debug = false; 170 m_is_external = false; 171 m_size_is_sibling = false; 172 m_size_is_synthesized = false; 173 m_size_is_valid = false; 174 m_demangled_is_synthesized = false; 175 m_contains_linker_annotations = false; 176 m_type = eSymbolTypeInvalid; 177 m_flags = 0; 178 m_addr_range.Clear(); 179 } 180 181 bool 182 Symbol::ValueIsAddress() const 183 { 184 return m_addr_range.GetBaseAddress().GetSection().get() != nullptr; 185 } 186 187 ConstString 188 Symbol::GetReExportedSymbolName() const 189 { 190 if (m_type == eSymbolTypeReExported) 191 { 192 // For eSymbolTypeReExported, the "const char *" from a ConstString 193 // is used as the offset in the address range base address. We can 194 // then make this back into a string that is the re-exported name. 195 intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset(); 196 if (str_ptr != 0) 197 return ConstString((const char *)str_ptr); 198 else 199 return GetName(); 200 } 201 return ConstString(); 202 } 203 204 FileSpec 205 Symbol::GetReExportedSymbolSharedLibrary() const 206 { 207 if (m_type == eSymbolTypeReExported) 208 { 209 // For eSymbolTypeReExported, the "const char *" from a ConstString 210 // is used as the offset in the address range base address. We can 211 // then make this back into a string that is the re-exported name. 212 intptr_t str_ptr = m_addr_range.GetByteSize(); 213 if (str_ptr != 0) 214 return FileSpec((const char *)str_ptr, false); 215 } 216 return FileSpec(); 217 } 218 219 void 220 Symbol::SetReExportedSymbolName(const ConstString &name) 221 { 222 SetType (eSymbolTypeReExported); 223 // For eSymbolTypeReExported, the "const char *" from a ConstString 224 // is used as the offset in the address range base address. 225 m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString()); 226 } 227 228 bool 229 Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) 230 { 231 if (m_type == eSymbolTypeReExported) 232 { 233 // For eSymbolTypeReExported, the "const char *" from a ConstString 234 // is used as the offset in the address range base address. 235 m_addr_range.SetByteSize((uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString()); 236 return true; 237 } 238 return false; 239 240 } 241 242 uint32_t 243 Symbol::GetSiblingIndex() const 244 { 245 return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX; 246 } 247 248 bool 249 Symbol::IsTrampoline () const 250 { 251 return m_type == eSymbolTypeTrampoline; 252 } 253 254 bool 255 Symbol::IsIndirect () const 256 { 257 return m_type == eSymbolTypeResolver; 258 } 259 260 void 261 Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const 262 { 263 s->Printf("id = {0x%8.8x}", m_uid); 264 265 if (m_addr_range.GetBaseAddress().GetSection()) 266 { 267 if (ValueIsAddress()) 268 { 269 const lldb::addr_t byte_size = GetByteSize(); 270 if (byte_size > 0) 271 { 272 s->PutCString (", range = "); 273 m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 274 } 275 else 276 { 277 s->PutCString (", address = "); 278 m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 279 } 280 } 281 else 282 s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); 283 } 284 else 285 { 286 if (m_size_is_sibling) 287 s->Printf (", sibling = %5" PRIu64, m_addr_range.GetBaseAddress().GetOffset()); 288 else 289 s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); 290 } 291 if (m_mangled.GetDemangledName()) 292 s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString()); 293 if (m_mangled.GetMangledName()) 294 s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString()); 295 296 } 297 298 void 299 Symbol::Dump(Stream *s, Target *target, uint32_t index) const 300 { 301 s->Printf("[%5u] %6u %c%c%c %-15s ", 302 index, 303 GetID(), 304 m_is_debug ? 'D' : ' ', 305 m_is_synthetic ? 'S' : ' ', 306 m_is_external ? 'X' : ' ', 307 GetTypeAsString()); 308 309 // Make sure the size of the symbol is up to date before dumping 310 GetByteSize(); 311 312 if (ValueIsAddress()) 313 { 314 if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress)) 315 s->Printf("%*s", 18, ""); 316 317 s->PutChar(' '); 318 319 if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress)) 320 s->Printf("%*s", 18, ""); 321 322 const char *format = m_size_is_sibling ? 323 " Sibling -> [%5llu] 0x%8.8x %s\n": 324 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 325 s->Printf( format, 326 GetByteSize(), 327 m_flags, 328 m_mangled.GetName().AsCString("")); 329 } 330 else if (m_type == eSymbolTypeReExported) 331 { 332 s->Printf (" 0x%8.8x %s", 333 m_flags, 334 m_mangled.GetName().AsCString("")); 335 336 ConstString reexport_name = GetReExportedSymbolName(); 337 intptr_t shlib = m_addr_range.GetByteSize(); 338 if (shlib) 339 s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString()); 340 else 341 s->Printf(" -> %s\n", reexport_name.GetCString()); 342 } 343 else 344 { 345 const char *format = m_size_is_sibling ? 346 "0x%16.16" PRIx64 " Sibling -> [%5llu] 0x%8.8x %s\n": 347 "0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 348 s->Printf( format, 349 m_addr_range.GetBaseAddress().GetOffset(), 350 GetByteSize(), 351 m_flags, 352 m_mangled.GetName().AsCString("")); 353 } 354 } 355 356 uint32_t 357 Symbol::GetPrologueByteSize () 358 { 359 if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) 360 { 361 if (!m_type_data_resolved) 362 { 363 m_type_data_resolved = true; 364 365 const Address &base_address = m_addr_range.GetBaseAddress(); 366 Function *function = base_address.CalculateSymbolContextFunction(); 367 if (function) 368 { 369 // Functions have line entries which can also potentially have end of prologue information. 370 // So if this symbol points to a function, use the prologue information from there. 371 m_type_data = function->GetPrologueByteSize(); 372 } 373 else 374 { 375 ModuleSP module_sp (base_address.GetModule()); 376 SymbolContext sc; 377 if (module_sp) 378 { 379 uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address, 380 eSymbolContextLineEntry, 381 sc); 382 if (resolved_flags & eSymbolContextLineEntry) 383 { 384 // Default to the end of the first line entry. 385 m_type_data = sc.line_entry.range.GetByteSize(); 386 387 // Set address for next line. 388 Address addr (base_address); 389 addr.Slide (m_type_data); 390 391 // Check the first few instructions and look for one that has a line number that is 392 // different than the first entry. This is also done in Function::GetPrologueByteSize(). 393 uint16_t total_offset = m_type_data; 394 for (int idx = 0; idx < 6; ++idx) 395 { 396 SymbolContext sc_temp; 397 resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp); 398 // Make sure we got line number information... 399 if (!(resolved_flags & eSymbolContextLineEntry)) 400 break; 401 402 // If this line number is different than our first one, use it and we're done. 403 if (sc_temp.line_entry.line != sc.line_entry.line) 404 { 405 m_type_data = total_offset; 406 break; 407 } 408 409 // Slide addr up to the next line address. 410 addr.Slide (sc_temp.line_entry.range.GetByteSize()); 411 total_offset += sc_temp.line_entry.range.GetByteSize(); 412 // If we've gone too far, bail out. 413 if (total_offset >= m_addr_range.GetByteSize()) 414 break; 415 } 416 417 // Sanity check - this may be a function in the middle of code that has debug information, but 418 // not for this symbol. So the line entries surrounding us won't lie inside our function. 419 // In that case, the line entry will be bigger than we are, so we do that quick check and 420 // if that is true, we just return 0. 421 if (m_type_data >= m_addr_range.GetByteSize()) 422 m_type_data = 0; 423 } 424 else 425 { 426 // TODO: expose something in Process to figure out the 427 // size of a function prologue. 428 m_type_data = 0; 429 } 430 } 431 } 432 } 433 return m_type_data; 434 } 435 return 0; 436 } 437 438 bool 439 Symbol::Compare(const ConstString& name, SymbolType type) const 440 { 441 if (type == eSymbolTypeAny || m_type == type) 442 return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name; 443 return false; 444 } 445 446 #define ENUM_TO_CSTRING(x) case eSymbolType##x: return #x; 447 448 const char * 449 Symbol::GetTypeAsString() const 450 { 451 switch (m_type) 452 { 453 ENUM_TO_CSTRING(Invalid); 454 ENUM_TO_CSTRING(Absolute); 455 ENUM_TO_CSTRING(Code); 456 ENUM_TO_CSTRING(Resolver); 457 ENUM_TO_CSTRING(Data); 458 ENUM_TO_CSTRING(Trampoline); 459 ENUM_TO_CSTRING(Runtime); 460 ENUM_TO_CSTRING(Exception); 461 ENUM_TO_CSTRING(SourceFile); 462 ENUM_TO_CSTRING(HeaderFile); 463 ENUM_TO_CSTRING(ObjectFile); 464 ENUM_TO_CSTRING(CommonBlock); 465 ENUM_TO_CSTRING(Block); 466 ENUM_TO_CSTRING(Local); 467 ENUM_TO_CSTRING(Param); 468 ENUM_TO_CSTRING(Variable); 469 ENUM_TO_CSTRING(VariableType); 470 ENUM_TO_CSTRING(LineEntry); 471 ENUM_TO_CSTRING(LineHeader); 472 ENUM_TO_CSTRING(ScopeBegin); 473 ENUM_TO_CSTRING(ScopeEnd); 474 ENUM_TO_CSTRING(Additional); 475 ENUM_TO_CSTRING(Compiler); 476 ENUM_TO_CSTRING(Instrumentation); 477 ENUM_TO_CSTRING(Undefined); 478 ENUM_TO_CSTRING(ObjCClass); 479 ENUM_TO_CSTRING(ObjCMetaClass); 480 ENUM_TO_CSTRING(ObjCIVar); 481 ENUM_TO_CSTRING(ReExported); 482 default: 483 break; 484 } 485 return "<unknown SymbolType>"; 486 } 487 488 void 489 Symbol::CalculateSymbolContext (SymbolContext *sc) 490 { 491 // Symbols can reconstruct the symbol and the module in the symbol context 492 sc->symbol = this; 493 if (ValueIsAddress()) 494 sc->module_sp = GetAddressRef().GetModule(); 495 else 496 sc->module_sp.reset(); 497 } 498 499 ModuleSP 500 Symbol::CalculateSymbolContextModule () 501 { 502 if (ValueIsAddress()) 503 return GetAddressRef().GetModule(); 504 return ModuleSP(); 505 } 506 507 Symbol * 508 Symbol::CalculateSymbolContextSymbol () 509 { 510 return this; 511 } 512 513 void 514 Symbol::DumpSymbolContext (Stream *s) 515 { 516 bool dumped_module = false; 517 if (ValueIsAddress()) 518 { 519 ModuleSP module_sp (GetAddressRef().GetModule()); 520 if (module_sp) 521 { 522 dumped_module = true; 523 module_sp->DumpSymbolContext(s); 524 } 525 } 526 if (dumped_module) 527 s->PutCString(", "); 528 529 s->Printf("Symbol{0x%8.8x}", GetID()); 530 } 531 532 lldb::addr_t 533 Symbol::GetByteSize () const 534 { 535 return m_addr_range.GetByteSize(); 536 } 537 538 539 Symbol * 540 Symbol::ResolveReExportedSymbolInModuleSpec (Target &target, 541 ConstString &reexport_name, 542 ModuleSpec &module_spec, 543 ModuleList &seen_modules) const 544 { 545 ModuleSP module_sp; 546 if (module_spec.GetFileSpec()) 547 { 548 // Try searching for the module file spec first using the full path 549 module_sp = target.GetImages().FindFirstModule(module_spec); 550 if (!module_sp) 551 { 552 // Next try and find the module by basename in case environment 553 // variables or other runtime trickery causes shared libraries 554 // to be loaded from alternate paths 555 module_spec.GetFileSpec().GetDirectory().Clear(); 556 module_sp = target.GetImages().FindFirstModule(module_spec); 557 } 558 } 559 560 if (module_sp) 561 { 562 // There should not be cycles in the reexport list, but we don't want to crash if there are so make sure 563 // we haven't seen this before: 564 if (!seen_modules.AppendIfNeeded(module_sp)) 565 return nullptr; 566 567 lldb_private::SymbolContextList sc_list; 568 module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list); 569 const size_t num_scs = sc_list.GetSize(); 570 if (num_scs > 0) 571 { 572 for (size_t i=0; i<num_scs; ++i) 573 { 574 lldb_private::SymbolContext sc; 575 if (sc_list.GetContextAtIndex(i, sc)) 576 { 577 if (sc.symbol->IsExternal()) 578 return sc.symbol; 579 } 580 } 581 } 582 // If we didn't find the symbol in this module, it may be because this module re-exports some 583 // whole other library. We have to search those as well: 584 seen_modules.Append(module_sp); 585 586 FileSpecList reexported_libraries = module_sp->GetObjectFile()->GetReExportedLibraries(); 587 size_t num_reexported_libraries = reexported_libraries.GetSize(); 588 for (size_t idx = 0; idx < num_reexported_libraries; idx++) 589 { 590 ModuleSpec reexported_module_spec; 591 reexported_module_spec.GetFileSpec() = reexported_libraries.GetFileSpecAtIndex(idx); 592 Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(target, 593 reexport_name, 594 reexported_module_spec, 595 seen_modules); 596 if (result_symbol) 597 return result_symbol; 598 } 599 } 600 return nullptr; 601 } 602 603 Symbol * 604 Symbol::ResolveReExportedSymbol (Target &target) const 605 { 606 ConstString reexport_name (GetReExportedSymbolName()); 607 if (reexport_name) 608 { 609 ModuleSpec module_spec; 610 ModuleList seen_modules; 611 module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary(); 612 if (module_spec.GetFileSpec()) 613 { 614 return ResolveReExportedSymbolInModuleSpec(target, reexport_name, module_spec, seen_modules); 615 } 616 } 617 return nullptr; 618 } 619 620 lldb::addr_t 621 Symbol::GetFileAddress () const 622 { 623 if (ValueIsAddress()) 624 return GetAddressRef().GetFileAddress(); 625 else 626 return LLDB_INVALID_ADDRESS; 627 } 628 629 lldb::addr_t 630 Symbol::GetLoadAddress (Target *target) const 631 { 632 if (ValueIsAddress()) 633 return GetAddressRef().GetLoadAddress(target); 634 else 635 return LLDB_INVALID_ADDRESS; 636 } 637 638 639 lldb::addr_t 640 Symbol::ResolveCallableAddress(Target &target) const 641 { 642 if (GetType() == lldb::eSymbolTypeUndefined) 643 return LLDB_INVALID_ADDRESS; 644 645 Address func_so_addr; 646 647 bool is_indirect = IsIndirect(); 648 if (GetType() == eSymbolTypeReExported) 649 { 650 Symbol *reexported_symbol = ResolveReExportedSymbol(target); 651 if (reexported_symbol) 652 { 653 func_so_addr = reexported_symbol->GetAddress(); 654 is_indirect = reexported_symbol->IsIndirect(); 655 } 656 } 657 else 658 { 659 func_so_addr = GetAddress(); 660 is_indirect = IsIndirect(); 661 } 662 663 if (func_so_addr.IsValid()) 664 { 665 if (!target.GetProcessSP() && is_indirect) 666 { 667 // can't resolve indirect symbols without calling a function... 668 return LLDB_INVALID_ADDRESS; 669 } 670 671 lldb::addr_t load_addr = func_so_addr.GetCallableLoadAddress (&target, is_indirect); 672 673 if (load_addr != LLDB_INVALID_ADDRESS) 674 { 675 return load_addr; 676 } 677 } 678 679 return LLDB_INVALID_ADDRESS; 680 } 681 682 683 lldb::DisassemblerSP 684 Symbol::GetInstructions (const ExecutionContext &exe_ctx, 685 const char *flavor, 686 bool prefer_file_cache) 687 { 688 ModuleSP module_sp (m_addr_range.GetBaseAddress().GetModule()); 689 if (module_sp) 690 { 691 const bool prefer_file_cache = false; 692 return Disassembler::DisassembleRange (module_sp->GetArchitecture(), 693 nullptr, 694 flavor, 695 exe_ctx, 696 m_addr_range, 697 prefer_file_cache); 698 } 699 return lldb::DisassemblerSP(); 700 } 701 702 bool 703 Symbol::GetDisassembly (const ExecutionContext &exe_ctx, 704 const char *flavor, 705 bool prefer_file_cache, 706 Stream &strm) 707 { 708 lldb::DisassemblerSP disassembler_sp = GetInstructions (exe_ctx, flavor, prefer_file_cache); 709 if (disassembler_sp) 710 { 711 const bool show_address = true; 712 const bool show_bytes = false; 713 disassembler_sp->GetInstructionList().Dump (&strm, show_address, show_bytes, &exe_ctx); 714 return true; 715 } 716 return false; 717 } 718