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