858 lines · cpp
1//===-- Symbol.cpp --------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Symbol/Symbol.h"10 11#include "lldb/Core/Address.h"12#include "lldb/Core/Debugger.h"13#include "lldb/Core/Module.h"14#include "lldb/Core/ModuleSpec.h"15#include "lldb/Core/Section.h"16#include "lldb/Symbol/Function.h"17#include "lldb/Symbol/ObjectFile.h"18#include "lldb/Symbol/SymbolVendor.h"19#include "lldb/Symbol/Symtab.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/Target.h"22#include "lldb/Utility/DataEncoder.h"23#include "lldb/Utility/Stream.h"24#include "llvm/ADT/StringSwitch.h"25 26using namespace lldb;27using namespace lldb_private;28 29Symbol::Symbol()30 : SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false),31 m_is_debug(false), m_is_external(false), m_size_is_sibling(false),32 m_size_is_synthesized(false), m_size_is_valid(false),33 m_demangled_is_synthesized(false), m_contains_linker_annotations(false),34 m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(),35 m_addr_range() {}36 37Symbol::Symbol(uint32_t symID, llvm::StringRef name, SymbolType type,38 bool external, bool is_debug, bool is_trampoline,39 bool is_artificial, const lldb::SectionSP §ion_sp,40 addr_t offset, addr_t size, bool size_is_valid,41 bool contains_linker_annotations, uint32_t flags)42 : SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),43 m_is_synthetic(is_artificial), m_is_debug(is_debug),44 m_is_external(external), m_size_is_sibling(false),45 m_size_is_synthesized(false), m_size_is_valid(size_is_valid || size > 0),46 m_demangled_is_synthesized(false),47 m_contains_linker_annotations(contains_linker_annotations),48 m_is_weak(false), m_type(type), m_mangled(name),49 m_addr_range(section_sp, offset, size), m_flags(flags) {}50 51Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type,52 bool external, bool is_debug, bool is_trampoline,53 bool is_artificial, const AddressRange &range,54 bool size_is_valid, bool contains_linker_annotations,55 uint32_t flags)56 : SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),57 m_is_synthetic(is_artificial), m_is_debug(is_debug),58 m_is_external(external), m_size_is_sibling(false),59 m_size_is_synthesized(false),60 m_size_is_valid(size_is_valid || range.GetByteSize() > 0),61 m_demangled_is_synthesized(false),62 m_contains_linker_annotations(contains_linker_annotations),63 m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range),64 m_flags(flags) {}65 66Symbol::Symbol(const Symbol &rhs)67 : SymbolContextScope(rhs), m_uid(rhs.m_uid), m_type_data(rhs.m_type_data),68 m_type_data_resolved(rhs.m_type_data_resolved),69 m_is_synthetic(rhs.m_is_synthetic), m_is_debug(rhs.m_is_debug),70 m_is_external(rhs.m_is_external),71 m_size_is_sibling(rhs.m_size_is_sibling), m_size_is_synthesized(false),72 m_size_is_valid(rhs.m_size_is_valid),73 m_demangled_is_synthesized(rhs.m_demangled_is_synthesized),74 m_contains_linker_annotations(rhs.m_contains_linker_annotations),75 m_is_weak(rhs.m_is_weak), m_type(rhs.m_type), m_mangled(rhs.m_mangled),76 m_addr_range(rhs.m_addr_range), m_flags(rhs.m_flags) {}77 78const Symbol &Symbol::operator=(const Symbol &rhs) {79 if (this != &rhs) {80 SymbolContextScope::operator=(rhs);81 m_uid = rhs.m_uid;82 m_type_data = rhs.m_type_data;83 m_type_data_resolved = rhs.m_type_data_resolved;84 m_is_synthetic = rhs.m_is_synthetic;85 m_is_debug = rhs.m_is_debug;86 m_is_external = rhs.m_is_external;87 m_size_is_sibling = rhs.m_size_is_sibling;88 m_size_is_synthesized = rhs.m_size_is_sibling;89 m_size_is_valid = rhs.m_size_is_valid;90 m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;91 m_contains_linker_annotations = rhs.m_contains_linker_annotations;92 m_is_weak = rhs.m_is_weak;93 m_type = rhs.m_type;94 m_mangled = rhs.m_mangled;95 m_addr_range = rhs.m_addr_range;96 m_flags = rhs.m_flags;97 }98 return *this;99}100 101llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol,102 SectionList *section_list) {103 if (!section_list)104 return llvm::createStringError("no section list provided");105 106 if (!symbol.value && !symbol.address)107 return llvm::createStringError(108 "symbol must contain either a value or an address");109 110 if (symbol.value && symbol.address)111 return llvm::createStringError(112 "symbol cannot contain both a value and an address");113 114 const uint64_t size = symbol.size.value_or(0);115 const bool is_artificial = false;116 const bool is_trampoline = false;117 const bool is_debug = false;118 const bool external = false;119 const bool size_is_valid = symbol.size.has_value();120 const bool contains_linker_annotations = false;121 const uint32_t flags = 0;122 123 if (symbol.address) {124 if (SectionSP section_sp =125 section_list->FindSectionContainingFileAddress(*symbol.address)) {126 const uint64_t offset = *symbol.address - section_sp->GetFileAddress();127 return Symbol(symbol.id.value_or(0), Mangled(symbol.name),128 symbol.type.value_or(eSymbolTypeAny), external, is_debug,129 is_trampoline, is_artificial,130 AddressRange(section_sp, offset, size), size_is_valid,131 contains_linker_annotations, flags);132 }133 return llvm::createStringError(134 llvm::formatv("no section found for address: {0:x}", *symbol.address));135 }136 137 // Absolute symbols encode the integer value in the m_offset of the138 // AddressRange object and the section is set to nothing.139 return Symbol(symbol.id.value_or(0), Mangled(symbol.name),140 symbol.type.value_or(eSymbolTypeAny), external, is_debug,141 is_trampoline, is_artificial,142 AddressRange(SectionSP(), *symbol.value, size), size_is_valid,143 contains_linker_annotations, flags);144}145 146void Symbol::Clear() {147 m_uid = UINT32_MAX;148 m_mangled.Clear();149 m_type_data = 0;150 m_type_data_resolved = false;151 m_is_synthetic = false;152 m_is_debug = false;153 m_is_external = false;154 m_size_is_sibling = false;155 m_size_is_synthesized = false;156 m_size_is_valid = false;157 m_demangled_is_synthesized = false;158 m_contains_linker_annotations = false;159 m_is_weak = false;160 m_type = eSymbolTypeInvalid;161 m_flags = 0;162 m_addr_range.Clear();163}164 165bool Symbol::ValueIsAddress() const {166 return (bool)m_addr_range.GetBaseAddress().GetSection();167}168 169ConstString Symbol::GetDisplayName() const {170 return GetMangled().GetDisplayDemangledName();171}172 173ConstString Symbol::GetReExportedSymbolName() const {174 if (m_type == eSymbolTypeReExported) {175 // For eSymbolTypeReExported, the "const char *" from a ConstString is used176 // as the offset in the address range base address. We can then make this177 // back into a string that is the re-exported name.178 intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset();179 if (str_ptr != 0)180 return ConstString((const char *)str_ptr);181 else182 return GetName();183 }184 return ConstString();185}186 187FileSpec Symbol::GetReExportedSymbolSharedLibrary() const {188 if (m_type == eSymbolTypeReExported) {189 // For eSymbolTypeReExported, the "const char *" from a ConstString is used190 // as the offset in the address range base address. We can then make this191 // back into a string that is the re-exported name.192 intptr_t str_ptr = m_addr_range.GetByteSize();193 if (str_ptr != 0)194 return FileSpec((const char *)str_ptr);195 }196 return FileSpec();197}198 199void Symbol::SetReExportedSymbolName(ConstString name) {200 SetType(eSymbolTypeReExported);201 // For eSymbolTypeReExported, the "const char *" from a ConstString is used202 // as the offset in the address range base address.203 m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString());204}205 206bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) {207 if (m_type == eSymbolTypeReExported) {208 // For eSymbolTypeReExported, the "const char *" from a ConstString is used209 // as the offset in the address range base address.210 m_addr_range.SetByteSize(211 (uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString());212 return true;213 }214 return false;215}216 217uint32_t Symbol::GetSiblingIndex() const {218 return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;219}220 221bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }222 223bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }224 225void Symbol::GetDescription(226 Stream *s, lldb::DescriptionLevel level, Target *target,227 std::optional<Stream::HighlightSettings> settings) const {228 s->Printf("id = {0x%8.8x}", m_uid);229 230 if (m_addr_range.GetBaseAddress().GetSection()) {231 if (ValueIsAddress()) {232 const lldb::addr_t byte_size = GetByteSize();233 if (byte_size > 0) {234 s->PutCString(", range = ");235 m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress,236 Address::DumpStyleFileAddress);237 } else {238 s->PutCString(", address = ");239 m_addr_range.GetBaseAddress().Dump(s, target,240 Address::DumpStyleLoadAddress,241 Address::DumpStyleFileAddress);242 }243 } else244 s->Printf(", value = 0x%16.16" PRIx64,245 m_addr_range.GetBaseAddress().GetOffset());246 } else {247 if (m_size_is_sibling)248 s->Printf(", sibling = %5" PRIu64,249 m_addr_range.GetBaseAddress().GetOffset());250 else251 s->Printf(", value = 0x%16.16" PRIx64,252 m_addr_range.GetBaseAddress().GetOffset());253 }254 if (ConstString demangled = m_mangled.GetDemangledName()) {255 s->PutCString(", name=\"");256 s->PutCStringColorHighlighted(demangled.GetStringRef(), settings);257 s->PutCString("\"");258 }259 if (ConstString mangled_name = m_mangled.GetMangledName()) {260 s->PutCString(", mangled=\"");261 s->PutCStringColorHighlighted(mangled_name.GetStringRef(), settings);262 s->PutCString("\"");263 }264}265 266void Symbol::Dump(Stream *s, Target *target, uint32_t index,267 Mangled::NamePreference name_preference) const {268 s->Printf("[%5u] %6u %c%c%c %-15s ", index, GetID(), m_is_debug ? 'D' : ' ',269 m_is_synthetic ? 'S' : ' ', m_is_external ? 'X' : ' ',270 GetTypeAsString());271 272 // Make sure the size of the symbol is up to date before dumping273 GetByteSize();274 275 ConstString name = GetMangled().GetName(name_preference);276 if (ValueIsAddress()) {277 if (!m_addr_range.GetBaseAddress().Dump(s, nullptr,278 Address::DumpStyleFileAddress))279 s->Printf("%*s", 18, "");280 281 s->PutChar(' ');282 283 if (!m_addr_range.GetBaseAddress().Dump(s, target,284 Address::DumpStyleLoadAddress))285 s->Printf("%*s", 18, "");286 287 const char *format = m_size_is_sibling ? " Sibling -> [%5llu] 0x%8.8x %s\n"288 : " 0x%16.16" PRIx64 " 0x%8.8x %s\n";289 s->Printf(format, GetByteSize(), m_flags, name.AsCString(""));290 } else if (m_type == eSymbolTypeReExported) {291 s->Printf(292 " 0x%8.8x %s",293 m_flags, name.AsCString(""));294 295 ConstString reexport_name = GetReExportedSymbolName();296 intptr_t shlib = m_addr_range.GetByteSize();297 if (shlib)298 s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());299 else300 s->Printf(" -> %s\n", reexport_name.GetCString());301 } else {302 const char *format =303 m_size_is_sibling304 ? "0x%16.16" PRIx64305 " Sibling -> [%5llu] 0x%8.8x %s\n"306 : "0x%16.16" PRIx64 " 0x%16.16" PRIx64307 " 0x%8.8x %s\n";308 s->Printf(format, m_addr_range.GetBaseAddress().GetOffset(), GetByteSize(),309 m_flags, name.AsCString(""));310 }311}312 313uint32_t Symbol::GetPrologueByteSize() {314 if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) {315 if (!m_type_data_resolved) {316 m_type_data_resolved = true;317 318 const Address &base_address = m_addr_range.GetBaseAddress();319 Function *function = base_address.CalculateSymbolContextFunction();320 if (function) {321 // Functions have line entries which can also potentially have end of322 // prologue information. So if this symbol points to a function, use323 // the prologue information from there.324 m_type_data = function->GetPrologueByteSize();325 } else {326 ModuleSP module_sp(base_address.GetModule());327 SymbolContext sc;328 if (module_sp) {329 uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress(330 base_address, eSymbolContextLineEntry, sc);331 if (resolved_flags & eSymbolContextLineEntry) {332 // Default to the end of the first line entry.333 m_type_data = sc.line_entry.range.GetByteSize();334 335 // Set address for next line.336 Address addr(base_address);337 addr.Slide(m_type_data);338 339 // Check the first few instructions and look for one that has a340 // line number that is different than the first entry. This is also341 // done in Function::GetPrologueByteSize().342 uint16_t total_offset = m_type_data;343 for (int idx = 0; idx < 6; ++idx) {344 SymbolContext sc_temp;345 resolved_flags = module_sp->ResolveSymbolContextForAddress(346 addr, eSymbolContextLineEntry, sc_temp);347 // Make sure we got line number information...348 if (!(resolved_flags & eSymbolContextLineEntry))349 break;350 351 // If this line number is different than our first one, use it352 // and we're done.353 if (sc_temp.line_entry.line != sc.line_entry.line) {354 m_type_data = total_offset;355 break;356 }357 358 // Slide addr up to the next line address.359 addr.Slide(sc_temp.line_entry.range.GetByteSize());360 total_offset += sc_temp.line_entry.range.GetByteSize();361 // If we've gone too far, bail out.362 if (total_offset >= m_addr_range.GetByteSize())363 break;364 }365 366 // Sanity check - this may be a function in the middle of code that367 // has debug information, but not for this symbol. So the line368 // entries surrounding us won't lie inside our function. In that369 // case, the line entry will be bigger than we are, so we do that370 // quick check and if that is true, we just return 0.371 if (m_type_data >= m_addr_range.GetByteSize())372 m_type_data = 0;373 } else {374 // TODO: expose something in Process to figure out the375 // size of a function prologue.376 m_type_data = 0;377 }378 }379 }380 }381 return m_type_data;382 }383 return 0;384}385 386bool Symbol::Compare(ConstString name, SymbolType type) const {387 if (type == eSymbolTypeAny || m_type == type) {388 const Mangled &mangled = GetMangled();389 return mangled.GetMangledName() == name ||390 mangled.GetDemangledName() == name;391 }392 return false;393}394 395const char *Symbol::GetTypeAsString() const {396 return GetTypeAsString(static_cast<lldb::SymbolType>(m_type));397}398 399void Symbol::CalculateSymbolContext(SymbolContext *sc) {400 // Symbols can reconstruct the symbol and the module in the symbol context401 sc->symbol = this;402 if (ValueIsAddress())403 sc->module_sp = GetAddressRef().GetModule();404 else405 sc->module_sp.reset();406}407 408ModuleSP Symbol::CalculateSymbolContextModule() {409 if (ValueIsAddress())410 return GetAddressRef().GetModule();411 return ModuleSP();412}413 414Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }415 416void Symbol::DumpSymbolContext(Stream *s) {417 bool dumped_module = false;418 if (ValueIsAddress()) {419 ModuleSP module_sp(GetAddressRef().GetModule());420 if (module_sp) {421 dumped_module = true;422 module_sp->DumpSymbolContext(s);423 }424 }425 if (dumped_module)426 s->PutCString(", ");427 428 s->Printf("Symbol{0x%8.8x}", GetID());429}430 431lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }432 433Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(434 Target &target, ConstString &reexport_name, ModuleSpec &module_spec,435 ModuleList &seen_modules) const {436 ModuleSP module_sp;437 if (module_spec.GetFileSpec()) {438 // Try searching for the module file spec first using the full path439 module_sp = target.GetImages().FindFirstModule(module_spec);440 if (!module_sp) {441 // Next try and find the module by basename in case environment variables442 // or other runtime trickery causes shared libraries to be loaded from443 // alternate paths444 module_spec.GetFileSpec().ClearDirectory();445 module_sp = target.GetImages().FindFirstModule(module_spec);446 }447 }448 449 if (module_sp) {450 // There should not be cycles in the reexport list, but we don't want to451 // crash if there are so make sure we haven't seen this before:452 if (!seen_modules.AppendIfNeeded(module_sp))453 return nullptr;454 455 lldb_private::SymbolContextList sc_list;456 module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,457 sc_list);458 for (const SymbolContext &sc : sc_list) {459 if (sc.symbol->IsExternal())460 return sc.symbol;461 }462 // If we didn't find the symbol in this module, it may be because this463 // module re-exports some whole other library. We have to search those as464 // well:465 seen_modules.Append(module_sp);466 467 FileSpecList reexported_libraries =468 module_sp->GetObjectFile()->GetReExportedLibraries();469 size_t num_reexported_libraries = reexported_libraries.GetSize();470 for (size_t idx = 0; idx < num_reexported_libraries; idx++) {471 ModuleSpec reexported_module_spec;472 reexported_module_spec.GetFileSpec() =473 reexported_libraries.GetFileSpecAtIndex(idx);474 Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(475 target, reexport_name, reexported_module_spec, seen_modules);476 if (result_symbol)477 return result_symbol;478 }479 }480 return nullptr;481}482 483Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {484 ConstString reexport_name(GetReExportedSymbolName());485 if (reexport_name) {486 ModuleSpec module_spec;487 ModuleList seen_modules;488 module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();489 if (module_spec.GetFileSpec()) {490 return ResolveReExportedSymbolInModuleSpec(target, reexport_name,491 module_spec, seen_modules);492 }493 }494 return nullptr;495}496 497lldb::addr_t Symbol::GetFileAddress() const {498 if (ValueIsAddress())499 return GetAddressRef().GetFileAddress();500 else501 return LLDB_INVALID_ADDRESS;502}503 504lldb::addr_t Symbol::GetLoadAddress(Target *target) const {505 if (ValueIsAddress())506 return GetAddressRef().GetLoadAddress(target);507 else508 return LLDB_INVALID_ADDRESS;509}510 511ConstString Symbol::GetName() const { return GetMangled().GetName(); }512 513ConstString Symbol::GetNameNoArguments() const {514 return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments);515}516 517lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const {518 if (GetType() == lldb::eSymbolTypeUndefined)519 return LLDB_INVALID_ADDRESS;520 521 Address func_so_addr;522 523 bool is_indirect = IsIndirect();524 if (GetType() == eSymbolTypeReExported) {525 Symbol *reexported_symbol = ResolveReExportedSymbol(target);526 if (reexported_symbol) {527 func_so_addr = reexported_symbol->GetAddress();528 is_indirect = reexported_symbol->IsIndirect();529 }530 } else {531 func_so_addr = GetAddress();532 is_indirect = IsIndirect();533 }534 535 if (func_so_addr.IsValid()) {536 if (!target.GetProcessSP() && is_indirect) {537 // can't resolve indirect symbols without calling a function...538 return LLDB_INVALID_ADDRESS;539 }540 541 lldb::addr_t load_addr =542 func_so_addr.GetCallableLoadAddress(&target, is_indirect);543 544 if (load_addr != LLDB_INVALID_ADDRESS) {545 return load_addr;546 }547 }548 549 return LLDB_INVALID_ADDRESS;550}551 552lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,553 const char *flavor,554 bool prefer_file_cache) {555 ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule());556 if (module_sp && exe_ctx.HasTargetScope()) {557 return Disassembler::DisassembleRange(558 module_sp->GetArchitecture(), nullptr, flavor, nullptr, nullptr,559 exe_ctx.GetTargetRef(), m_addr_range, !prefer_file_cache);560 }561 return lldb::DisassemblerSP();562}563 564bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor,565 bool prefer_file_cache, Stream &strm) {566 lldb::DisassemblerSP disassembler_sp =567 GetInstructions(exe_ctx, flavor, prefer_file_cache);568 if (disassembler_sp) {569 const bool show_address = true;570 const bool show_bytes = false;571 const bool show_control_flow_kind = false;572 disassembler_sp->GetInstructionList().Dump(573 &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);574 return true;575 }576 return false;577}578 579bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {580 return m_addr_range.ContainsFileAddress(file_addr);581}582 583bool Symbol::IsSyntheticWithAutoGeneratedName() const {584 if (!IsSynthetic())585 return false;586 if (!m_mangled)587 return true;588 ConstString demangled = m_mangled.GetDemangledName();589 return demangled.GetStringRef().starts_with(GetSyntheticSymbolPrefix());590}591 592void Symbol::SynthesizeNameIfNeeded() const {593 if (m_is_synthetic && !m_mangled) {594 // Synthetic symbol names don't mean anything, but they do uniquely595 // identify individual symbols so we give them a unique name. The name596 // starts with the synthetic symbol prefix, followed by a unique number.597 // Typically the UserID of a real symbol is the symbol table index of the598 // symbol in the object file's symbol table(s), so it will be the same599 // every time you read in the object file. We want the same persistence for600 // synthetic symbols so that users can identify them across multiple debug601 // sessions, to understand crashes in those symbols and to reliably set602 // breakpoints on them.603 llvm::SmallString<256> name;604 llvm::raw_svector_ostream os(name);605 os << GetSyntheticSymbolPrefix()606 << llvm::format_hex_no_prefix(607 m_addr_range.GetBaseAddress().GetFileAddress(), 0);608 m_mangled.SetDemangledName(ConstString(os.str()));609 }610}611 612bool Symbol::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,613 const SectionList *section_list,614 const StringTableReader &strtab) {615 if (!data.ValidOffsetForDataOfSize(*offset_ptr, 8))616 return false;617 m_uid = data.GetU32(offset_ptr);618 m_type_data = data.GetU16(offset_ptr);619 const uint16_t bitfields = data.GetU16(offset_ptr);620 m_type_data_resolved = (1u << 15 & bitfields) != 0;621 m_is_synthetic = (1u << 14 & bitfields) != 0;622 m_is_debug = (1u << 13 & bitfields) != 0;623 m_is_external = (1u << 12 & bitfields) != 0;624 m_size_is_sibling = (1u << 11 & bitfields) != 0;625 m_size_is_synthesized = (1u << 10 & bitfields) != 0;626 m_size_is_valid = (1u << 9 & bitfields) != 0;627 m_demangled_is_synthesized = (1u << 8 & bitfields) != 0;628 m_contains_linker_annotations = (1u << 7 & bitfields) != 0;629 m_is_weak = (1u << 6 & bitfields) != 0;630 m_type = bitfields & 0x003f;631 if (!m_mangled.Decode(data, offset_ptr, strtab))632 return false;633 if (!data.ValidOffsetForDataOfSize(*offset_ptr, 20))634 return false;635 const bool is_addr = data.GetU8(offset_ptr) != 0;636 const uint64_t value = data.GetU64(offset_ptr);637 if (is_addr) {638 m_addr_range.GetBaseAddress().ResolveAddressUsingFileSections(value,639 section_list);640 } else {641 m_addr_range.GetBaseAddress().Clear();642 m_addr_range.GetBaseAddress().SetOffset(value);643 }644 m_addr_range.SetByteSize(data.GetU64(offset_ptr));645 m_flags = data.GetU32(offset_ptr);646 return true;647}648 649/// The encoding format for the symbol is as follows:650///651/// uint32_t m_uid;652/// uint16_t m_type_data;653/// uint16_t bitfield_data;654/// Mangled mangled;655/// uint8_t is_addr;656/// uint64_t file_addr_or_value;657/// uint64_t size;658/// uint32_t flags;659///660/// The only tricky thing in this encoding is encoding all of the bits in the661/// bitfields. We use a trick to store all bitfields as a 16 bit value and we662/// do the same thing when decoding the symbol. There are test that ensure this663/// encoding works for each individual bit. Everything else is very easy to664/// store.665void Symbol::Encode(DataEncoder &file, ConstStringTable &strtab) const {666 file.AppendU32(m_uid);667 file.AppendU16(m_type_data);668 uint16_t bitfields = m_type;669 if (m_type_data_resolved)670 bitfields |= 1u << 15;671 if (m_is_synthetic)672 bitfields |= 1u << 14;673 if (m_is_debug)674 bitfields |= 1u << 13;675 if (m_is_external)676 bitfields |= 1u << 12;677 if (m_size_is_sibling)678 bitfields |= 1u << 11;679 if (m_size_is_synthesized)680 bitfields |= 1u << 10;681 if (m_size_is_valid)682 bitfields |= 1u << 9;683 if (m_demangled_is_synthesized)684 bitfields |= 1u << 8;685 if (m_contains_linker_annotations)686 bitfields |= 1u << 7;687 if (m_is_weak)688 bitfields |= 1u << 6;689 file.AppendU16(bitfields);690 m_mangled.Encode(file, strtab);691 // A symbol's value might be an address, or it might be a constant. If the692 // symbol's base address doesn't have a section, then it is a constant value.693 // If it does have a section, we will encode the file address and re-resolve694 // the address when we decode it.695 bool is_addr = m_addr_range.GetBaseAddress().GetSection().get() != nullptr;696 file.AppendU8(is_addr);697 file.AppendU64(m_addr_range.GetBaseAddress().GetFileAddress());698 file.AppendU64(m_addr_range.GetByteSize());699 file.AppendU32(m_flags);700}701 702bool Symbol::operator==(const Symbol &rhs) const {703 if (m_uid != rhs.m_uid)704 return false;705 if (m_type_data != rhs.m_type_data)706 return false;707 if (m_type_data_resolved != rhs.m_type_data_resolved)708 return false;709 if (m_is_synthetic != rhs.m_is_synthetic)710 return false;711 if (m_is_debug != rhs.m_is_debug)712 return false;713 if (m_is_external != rhs.m_is_external)714 return false;715 if (m_size_is_sibling != rhs.m_size_is_sibling)716 return false;717 if (m_size_is_synthesized != rhs.m_size_is_synthesized)718 return false;719 if (m_size_is_valid != rhs.m_size_is_valid)720 return false;721 if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)722 return false;723 if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)724 return false;725 if (m_is_weak != rhs.m_is_weak)726 return false;727 if (m_type != rhs.m_type)728 return false;729 if (m_mangled != rhs.m_mangled)730 return false;731 if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())732 return false;733 if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())734 return false;735 if (m_flags != rhs.m_flags)736 return false;737 return true;738}739 740#define ENUM_TO_CSTRING(x) \741 case eSymbolType##x: \742 return #x;743 744const char *Symbol::GetTypeAsString(lldb::SymbolType symbol_type) {745 switch (symbol_type) {746 ENUM_TO_CSTRING(Invalid);747 ENUM_TO_CSTRING(Absolute);748 ENUM_TO_CSTRING(Code);749 ENUM_TO_CSTRING(Resolver);750 ENUM_TO_CSTRING(Data);751 ENUM_TO_CSTRING(Trampoline);752 ENUM_TO_CSTRING(Runtime);753 ENUM_TO_CSTRING(Exception);754 ENUM_TO_CSTRING(SourceFile);755 ENUM_TO_CSTRING(HeaderFile);756 ENUM_TO_CSTRING(ObjectFile);757 ENUM_TO_CSTRING(CommonBlock);758 ENUM_TO_CSTRING(Block);759 ENUM_TO_CSTRING(Local);760 ENUM_TO_CSTRING(Param);761 ENUM_TO_CSTRING(Variable);762 ENUM_TO_CSTRING(VariableType);763 ENUM_TO_CSTRING(LineEntry);764 ENUM_TO_CSTRING(LineHeader);765 ENUM_TO_CSTRING(ScopeBegin);766 ENUM_TO_CSTRING(ScopeEnd);767 ENUM_TO_CSTRING(Additional);768 ENUM_TO_CSTRING(Compiler);769 ENUM_TO_CSTRING(Instrumentation);770 ENUM_TO_CSTRING(Undefined);771 ENUM_TO_CSTRING(ObjCClass);772 ENUM_TO_CSTRING(ObjCMetaClass);773 ENUM_TO_CSTRING(ObjCIVar);774 ENUM_TO_CSTRING(ReExported);775 }776 return "<unknown SymbolType>";777}778 779lldb::SymbolType Symbol::GetTypeFromString(const char *str) {780 std::string str_lower = llvm::StringRef(str).lower();781 return llvm::StringSwitch<lldb::SymbolType>(str_lower)782 .Case("absolute", eSymbolTypeAbsolute)783 .Case("code", eSymbolTypeCode)784 .Case("resolver", eSymbolTypeResolver)785 .Case("data", eSymbolTypeData)786 .Case("trampoline", eSymbolTypeTrampoline)787 .Case("runtime", eSymbolTypeRuntime)788 .Case("exception", eSymbolTypeException)789 .Case("sourcefile", eSymbolTypeSourceFile)790 .Case("headerfile", eSymbolTypeHeaderFile)791 .Case("objectfile", eSymbolTypeObjectFile)792 .Case("commonblock", eSymbolTypeCommonBlock)793 .Case("block", eSymbolTypeBlock)794 .Case("local", eSymbolTypeLocal)795 .Case("param", eSymbolTypeParam)796 .Case("variable", eSymbolTypeVariable)797 .Case("variableType", eSymbolTypeVariableType)798 .Case("lineentry", eSymbolTypeLineEntry)799 .Case("lineheader", eSymbolTypeLineHeader)800 .Case("scopebegin", eSymbolTypeScopeBegin)801 .Case("scopeend", eSymbolTypeScopeEnd)802 .Case("additional,", eSymbolTypeAdditional)803 .Case("compiler", eSymbolTypeCompiler)804 .Case("instrumentation", eSymbolTypeInstrumentation)805 .Case("undefined", eSymbolTypeUndefined)806 .Case("objcclass", eSymbolTypeObjCClass)807 .Case("objcmetaclass", eSymbolTypeObjCMetaClass)808 .Case("objcivar", eSymbolTypeObjCIVar)809 .Case("reexported", eSymbolTypeReExported)810 .Default(eSymbolTypeInvalid);811}812 813namespace llvm {814namespace json {815 816bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,817 llvm::json::Path path) {818 llvm::json::ObjectMapper o(value, path);819 const bool mapped = o && o.map("value", symbol.value) &&820 o.map("address", symbol.address) &&821 o.map("size", symbol.size) && o.map("id", symbol.id) &&822 o.map("type", symbol.type) && o.map("name", symbol.name);823 824 if (!mapped)825 return false;826 827 if (!symbol.value && !symbol.address) {828 path.report("symbol must have either a value or an address");829 return false;830 }831 832 if (symbol.value && symbol.address) {833 path.report("symbol cannot have both a value and an address");834 return false;835 }836 837 return true;838}839 840bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,841 llvm::json::Path path) {842 if (auto str = value.getAsString()) {843 llvm::StringRef str_ref = str.value_or("");844 type = Symbol::GetTypeFromString(str_ref.data());845 846 if (type == eSymbolTypeInvalid) {847 path.report("invalid symbol type");848 return false;849 }850 851 return true;852 }853 path.report("expected string");854 return false;855}856} // namespace json857} // namespace llvm858