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