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