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() : UINT32_MAX; 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("[%5u] %6u %c%c%c %-15s ", 295 index, 296 GetID(), 297 m_is_debug ? 'D' : ' ', 298 m_is_synthetic ? 'S' : ' ', 299 m_is_external ? 'X' : ' ', 300 GetTypeAsString()); 301 302 // Make sure the size of the symbol is up to date before dumping 303 GetByteSize(); 304 305 if (ValueIsAddress()) 306 { 307 if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress)) 308 s->Printf("%*s", 18, ""); 309 310 s->PutChar(' '); 311 312 if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress)) 313 s->Printf("%*s", 18, ""); 314 315 const char *format = m_size_is_sibling ? 316 " Sibling -> [%5llu] 0x%8.8x %s\n": 317 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 318 s->Printf( format, 319 GetByteSize(), 320 m_flags, 321 m_mangled.GetName().AsCString("")); 322 } 323 else if (m_type == eSymbolTypeReExported) 324 { 325 s->Printf (" 0x%8.8x %s", 326 m_flags, 327 m_mangled.GetName().AsCString("")); 328 329 ConstString reexport_name = GetReExportedSymbolName(); 330 intptr_t shlib = m_addr_range.GetByteSize(); 331 if (shlib) 332 s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString()); 333 else 334 s->Printf(" -> %s\n", reexport_name.GetCString()); 335 } 336 else 337 { 338 const char *format = m_size_is_sibling ? 339 "0x%16.16" PRIx64 " Sibling -> [%5llu] 0x%8.8x %s\n": 340 "0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 341 s->Printf( format, 342 m_addr_range.GetBaseAddress().GetOffset(), 343 GetByteSize(), 344 m_flags, 345 m_mangled.GetName().AsCString("")); 346 } 347 } 348 349 uint32_t 350 Symbol::GetPrologueByteSize () 351 { 352 if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) 353 { 354 if (!m_type_data_resolved) 355 { 356 m_type_data_resolved = true; 357 358 const Address &base_address = m_addr_range.GetBaseAddress(); 359 Function *function = base_address.CalculateSymbolContextFunction(); 360 if (function) 361 { 362 // Functions have line entries which can also potentially have end of prologue information. 363 // So if this symbol points to a function, use the prologue information from there. 364 m_type_data = function->GetPrologueByteSize(); 365 } 366 else 367 { 368 ModuleSP module_sp (base_address.GetModule()); 369 SymbolContext sc; 370 if (module_sp) 371 { 372 uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address, 373 eSymbolContextLineEntry, 374 sc); 375 if (resolved_flags & eSymbolContextLineEntry) 376 { 377 // Default to the end of the first line entry. 378 m_type_data = sc.line_entry.range.GetByteSize(); 379 380 // Set address for next line. 381 Address addr (base_address); 382 addr.Slide (m_type_data); 383 384 // Check the first few instructions and look for one that has a line number that is 385 // different than the first entry. This is also done in Function::GetPrologueByteSize(). 386 uint16_t total_offset = m_type_data; 387 for (int idx = 0; idx < 6; ++idx) 388 { 389 SymbolContext sc_temp; 390 resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp); 391 // Make sure we got line number information... 392 if (!(resolved_flags & eSymbolContextLineEntry)) 393 break; 394 395 // If this line number is different than our first one, use it and we're done. 396 if (sc_temp.line_entry.line != sc.line_entry.line) 397 { 398 m_type_data = total_offset; 399 break; 400 } 401 402 // Slide addr up to the next line address. 403 addr.Slide (sc_temp.line_entry.range.GetByteSize()); 404 total_offset += sc_temp.line_entry.range.GetByteSize(); 405 // If we've gone too far, bail out. 406 if (total_offset >= m_addr_range.GetByteSize()) 407 break; 408 } 409 410 // Sanity check - this may be a function in the middle of code that has debug information, but 411 // not for this symbol. So the line entries surrounding us won't lie inside our function. 412 // In that case, the line entry will be bigger than we are, so we do that quick check and 413 // if that is true, we just return 0. 414 if (m_type_data >= m_addr_range.GetByteSize()) 415 m_type_data = 0; 416 } 417 else 418 { 419 // TODO: expose something in Process to figure out the 420 // size of a function prologue. 421 m_type_data = 0; 422 } 423 } 424 } 425 } 426 return m_type_data; 427 } 428 return 0; 429 } 430 431 bool 432 Symbol::Compare(const ConstString& name, SymbolType type) const 433 { 434 if (type == eSymbolTypeAny || m_type == type) 435 return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name; 436 return false; 437 } 438 439 #define ENUM_TO_CSTRING(x) case eSymbolType##x: return #x; 440 441 const char * 442 Symbol::GetTypeAsString() const 443 { 444 switch (m_type) 445 { 446 ENUM_TO_CSTRING(Invalid); 447 ENUM_TO_CSTRING(Absolute); 448 ENUM_TO_CSTRING(Code); 449 ENUM_TO_CSTRING(Resolver); 450 ENUM_TO_CSTRING(Data); 451 ENUM_TO_CSTRING(Trampoline); 452 ENUM_TO_CSTRING(Runtime); 453 ENUM_TO_CSTRING(Exception); 454 ENUM_TO_CSTRING(SourceFile); 455 ENUM_TO_CSTRING(HeaderFile); 456 ENUM_TO_CSTRING(ObjectFile); 457 ENUM_TO_CSTRING(CommonBlock); 458 ENUM_TO_CSTRING(Block); 459 ENUM_TO_CSTRING(Local); 460 ENUM_TO_CSTRING(Param); 461 ENUM_TO_CSTRING(Variable); 462 ENUM_TO_CSTRING(VariableType); 463 ENUM_TO_CSTRING(LineEntry); 464 ENUM_TO_CSTRING(LineHeader); 465 ENUM_TO_CSTRING(ScopeBegin); 466 ENUM_TO_CSTRING(ScopeEnd); 467 ENUM_TO_CSTRING(Additional); 468 ENUM_TO_CSTRING(Compiler); 469 ENUM_TO_CSTRING(Instrumentation); 470 ENUM_TO_CSTRING(Undefined); 471 ENUM_TO_CSTRING(ObjCClass); 472 ENUM_TO_CSTRING(ObjCMetaClass); 473 ENUM_TO_CSTRING(ObjCIVar); 474 ENUM_TO_CSTRING(ReExported); 475 default: 476 break; 477 } 478 return "<unknown SymbolType>"; 479 } 480 481 void 482 Symbol::CalculateSymbolContext (SymbolContext *sc) 483 { 484 // Symbols can reconstruct the symbol and the module in the symbol context 485 sc->symbol = this; 486 if (ValueIsAddress()) 487 sc->module_sp = GetAddress().GetModule(); 488 else 489 sc->module_sp.reset(); 490 } 491 492 ModuleSP 493 Symbol::CalculateSymbolContextModule () 494 { 495 if (ValueIsAddress()) 496 return GetAddress().GetModule(); 497 return ModuleSP(); 498 } 499 500 Symbol * 501 Symbol::CalculateSymbolContextSymbol () 502 { 503 return this; 504 } 505 506 void 507 Symbol::DumpSymbolContext (Stream *s) 508 { 509 bool dumped_module = false; 510 if (ValueIsAddress()) 511 { 512 ModuleSP module_sp (GetAddress().GetModule()); 513 if (module_sp) 514 { 515 dumped_module = true; 516 module_sp->DumpSymbolContext(s); 517 } 518 } 519 if (dumped_module) 520 s->PutCString(", "); 521 522 s->Printf("Symbol{0x%8.8x}", GetID()); 523 } 524 525 lldb::addr_t 526 Symbol::GetByteSize () const 527 { 528 return m_addr_range.GetByteSize(); 529 } 530 531 532 Symbol * 533 Symbol::ResolveReExportedSymbolInModuleSpec (Target &target, 534 ConstString &reexport_name, 535 ModuleSpec &module_spec, 536 ModuleList &seen_modules) const 537 { 538 ModuleSP module_sp; 539 if (module_spec.GetFileSpec()) 540 { 541 // Try searching for the module file spec first using the full path 542 module_sp = target.GetImages().FindFirstModule(module_spec); 543 if (!module_sp) 544 { 545 // Next try and find the module by basename in case environment 546 // variables or other runtime trickery causes shared libraries 547 // to be loaded from alternate paths 548 module_spec.GetFileSpec().GetDirectory().Clear(); 549 module_sp = target.GetImages().FindFirstModule(module_spec); 550 } 551 } 552 553 if (module_sp) 554 { 555 // There should not be cycles in the reexport list, but we don't want to crash if there are so make sure 556 // we haven't seen this before: 557 if (!seen_modules.AppendIfNeeded(module_sp)) 558 return nullptr; 559 560 lldb_private::SymbolContextList sc_list; 561 module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list); 562 const size_t num_scs = sc_list.GetSize(); 563 if (num_scs > 0) 564 { 565 for (size_t i=0; i<num_scs; ++i) 566 { 567 lldb_private::SymbolContext sc; 568 if (sc_list.GetContextAtIndex(i, sc)) 569 { 570 if (sc.symbol->IsExternal()) 571 return sc.symbol; 572 } 573 } 574 } 575 // If we didn't find the symbol in this module, it may be because this module re-exports some 576 // whole other library. We have to search those as well: 577 seen_modules.Append(module_sp); 578 579 FileSpecList reexported_libraries = module_sp->GetObjectFile()->GetReExportedLibraries(); 580 size_t num_reexported_libraries = reexported_libraries.GetSize(); 581 for (size_t idx = 0; idx < num_reexported_libraries; idx++) 582 { 583 ModuleSpec reexported_module_spec; 584 reexported_module_spec.GetFileSpec() = reexported_libraries.GetFileSpecAtIndex(idx); 585 Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(target, 586 reexport_name, 587 reexported_module_spec, 588 seen_modules); 589 if (result_symbol) 590 return result_symbol; 591 } 592 } 593 return nullptr; 594 } 595 596 Symbol * 597 Symbol::ResolveReExportedSymbol (Target &target) const 598 { 599 ConstString reexport_name (GetReExportedSymbolName()); 600 if (reexport_name) 601 { 602 ModuleSpec module_spec; 603 ModuleList seen_modules; 604 module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary(); 605 if (module_spec.GetFileSpec()) 606 { 607 return ResolveReExportedSymbolInModuleSpec(target, reexport_name, module_spec, seen_modules); 608 } 609 } 610 return nullptr; 611 } 612 613 lldb::addr_t 614 Symbol::ResolveCallableAddress(Target &target) const 615 { 616 if (GetType() == lldb::eSymbolTypeUndefined) 617 return LLDB_INVALID_ADDRESS; 618 619 Address func_so_addr; 620 621 bool is_indirect = IsIndirect(); 622 if (GetType() == eSymbolTypeReExported) 623 { 624 Symbol *reexported_symbol = ResolveReExportedSymbol(target); 625 if (reexported_symbol) 626 { 627 func_so_addr = reexported_symbol->GetAddress(); 628 is_indirect = reexported_symbol->IsIndirect(); 629 } 630 } 631 else 632 { 633 func_so_addr = GetAddress(); 634 is_indirect = IsIndirect(); 635 } 636 637 if (func_so_addr.IsValid()) 638 { 639 if (!target.GetProcessSP() && is_indirect) 640 { 641 // can't resolve indirect symbols without calling a function... 642 return LLDB_INVALID_ADDRESS; 643 } 644 645 lldb::addr_t load_addr = func_so_addr.GetCallableLoadAddress (&target, is_indirect); 646 647 if (load_addr != LLDB_INVALID_ADDRESS) 648 { 649 return load_addr; 650 } 651 } 652 653 return LLDB_INVALID_ADDRESS; 654 } 655 656 657 lldb::DisassemblerSP 658 Symbol::GetInstructions (const ExecutionContext &exe_ctx, 659 const char *flavor, 660 bool prefer_file_cache) 661 { 662 ModuleSP module_sp (m_addr_range.GetBaseAddress().GetModule()); 663 if (module_sp) 664 { 665 const bool prefer_file_cache = false; 666 return Disassembler::DisassembleRange (module_sp->GetArchitecture(), 667 nullptr, 668 flavor, 669 exe_ctx, 670 m_addr_range, 671 prefer_file_cache); 672 } 673 return lldb::DisassemblerSP(); 674 } 675 676 bool 677 Symbol::GetDisassembly (const ExecutionContext &exe_ctx, 678 const char *flavor, 679 bool prefer_file_cache, 680 Stream &strm) 681 { 682 lldb::DisassemblerSP disassembler_sp = GetInstructions (exe_ctx, flavor, prefer_file_cache); 683 if (disassembler_sp) 684 { 685 const bool show_address = true; 686 const bool show_bytes = false; 687 disassembler_sp->GetInstructionList().Dump (&strm, show_address, show_bytes, &exe_ctx); 688 return true; 689 } 690 return false; 691 } 692