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