Path: blob/main/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp
39587 views
//===-- Symbol.cpp --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Symbol/Symbol.h"910#include "lldb/Core/Address.h"11#include "lldb/Core/Debugger.h"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/DataEncoder.h"22#include "lldb/Utility/Stream.h"23#include "llvm/ADT/StringSwitch.h"2425using namespace lldb;26using namespace lldb_private;2728Symbol::Symbol()29: SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false),30m_is_debug(false), m_is_external(false), m_size_is_sibling(false),31m_size_is_synthesized(false), m_size_is_valid(false),32m_demangled_is_synthesized(false), m_contains_linker_annotations(false),33m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(),34m_addr_range() {}3536Symbol::Symbol(uint32_t symID, llvm::StringRef name, SymbolType type,37bool external, bool is_debug, bool is_trampoline,38bool is_artificial, const lldb::SectionSP §ion_sp,39addr_t offset, addr_t size, bool size_is_valid,40bool contains_linker_annotations, uint32_t flags)41: SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),42m_is_synthetic(is_artificial), m_is_debug(is_debug),43m_is_external(external), m_size_is_sibling(false),44m_size_is_synthesized(false), m_size_is_valid(size_is_valid || size > 0),45m_demangled_is_synthesized(false),46m_contains_linker_annotations(contains_linker_annotations),47m_is_weak(false), m_type(type), m_mangled(name),48m_addr_range(section_sp, offset, size), m_flags(flags) {}4950Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type,51bool external, bool is_debug, bool is_trampoline,52bool is_artificial, const AddressRange &range,53bool size_is_valid, bool contains_linker_annotations,54uint32_t flags)55: SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),56m_is_synthetic(is_artificial), m_is_debug(is_debug),57m_is_external(external), m_size_is_sibling(false),58m_size_is_synthesized(false),59m_size_is_valid(size_is_valid || range.GetByteSize() > 0),60m_demangled_is_synthesized(false),61m_contains_linker_annotations(contains_linker_annotations),62m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range),63m_flags(flags) {}6465Symbol::Symbol(const Symbol &rhs)66: SymbolContextScope(rhs), m_uid(rhs.m_uid), m_type_data(rhs.m_type_data),67m_type_data_resolved(rhs.m_type_data_resolved),68m_is_synthetic(rhs.m_is_synthetic), m_is_debug(rhs.m_is_debug),69m_is_external(rhs.m_is_external),70m_size_is_sibling(rhs.m_size_is_sibling), m_size_is_synthesized(false),71m_size_is_valid(rhs.m_size_is_valid),72m_demangled_is_synthesized(rhs.m_demangled_is_synthesized),73m_contains_linker_annotations(rhs.m_contains_linker_annotations),74m_is_weak(rhs.m_is_weak), m_type(rhs.m_type), m_mangled(rhs.m_mangled),75m_addr_range(rhs.m_addr_range), m_flags(rhs.m_flags) {}7677const Symbol &Symbol::operator=(const Symbol &rhs) {78if (this != &rhs) {79SymbolContextScope::operator=(rhs);80m_uid = rhs.m_uid;81m_type_data = rhs.m_type_data;82m_type_data_resolved = rhs.m_type_data_resolved;83m_is_synthetic = rhs.m_is_synthetic;84m_is_debug = rhs.m_is_debug;85m_is_external = rhs.m_is_external;86m_size_is_sibling = rhs.m_size_is_sibling;87m_size_is_synthesized = rhs.m_size_is_sibling;88m_size_is_valid = rhs.m_size_is_valid;89m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;90m_contains_linker_annotations = rhs.m_contains_linker_annotations;91m_is_weak = rhs.m_is_weak;92m_type = rhs.m_type;93m_mangled = rhs.m_mangled;94m_addr_range = rhs.m_addr_range;95m_flags = rhs.m_flags;96}97return *this;98}99100llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol,101SectionList *section_list) {102if (!section_list)103return llvm::createStringError("no section list provided");104105if (!symbol.value && !symbol.address)106return llvm::createStringError(107"symbol must contain either a value or an address");108109if (symbol.value && symbol.address)110return llvm::createStringError(111"symbol cannot contain both a value and an address");112113const uint64_t size = symbol.size.value_or(0);114const bool is_artificial = false;115const bool is_trampoline = false;116const bool is_debug = false;117const bool external = false;118const bool size_is_valid = symbol.size.has_value();119const bool contains_linker_annotations = false;120const uint32_t flags = 0;121122if (symbol.address) {123if (SectionSP section_sp =124section_list->FindSectionContainingFileAddress(*symbol.address)) {125const uint64_t offset = *symbol.address - section_sp->GetFileAddress();126return Symbol(symbol.id.value_or(0), Mangled(symbol.name),127symbol.type.value_or(eSymbolTypeAny), external, is_debug,128is_trampoline, is_artificial,129AddressRange(section_sp, offset, size), size_is_valid,130contains_linker_annotations, flags);131}132return llvm::createStringError(133llvm::formatv("no section found for address: {0:x}", *symbol.address));134}135136// Absolute symbols encode the integer value in the m_offset of the137// AddressRange object and the section is set to nothing.138return Symbol(symbol.id.value_or(0), Mangled(symbol.name),139symbol.type.value_or(eSymbolTypeAny), external, is_debug,140is_trampoline, is_artificial,141AddressRange(SectionSP(), *symbol.value, size), size_is_valid,142contains_linker_annotations, flags);143}144145void Symbol::Clear() {146m_uid = UINT32_MAX;147m_mangled.Clear();148m_type_data = 0;149m_type_data_resolved = false;150m_is_synthetic = false;151m_is_debug = false;152m_is_external = false;153m_size_is_sibling = false;154m_size_is_synthesized = false;155m_size_is_valid = false;156m_demangled_is_synthesized = false;157m_contains_linker_annotations = false;158m_is_weak = false;159m_type = eSymbolTypeInvalid;160m_flags = 0;161m_addr_range.Clear();162}163164bool Symbol::ValueIsAddress() const {165return (bool)m_addr_range.GetBaseAddress().GetSection();166}167168ConstString Symbol::GetDisplayName() const {169return GetMangled().GetDisplayDemangledName();170}171172ConstString Symbol::GetReExportedSymbolName() const {173if (m_type == eSymbolTypeReExported) {174// For eSymbolTypeReExported, the "const char *" from a ConstString is used175// as the offset in the address range base address. We can then make this176// back into a string that is the re-exported name.177intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset();178if (str_ptr != 0)179return ConstString((const char *)str_ptr);180else181return GetName();182}183return ConstString();184}185186FileSpec Symbol::GetReExportedSymbolSharedLibrary() const {187if (m_type == eSymbolTypeReExported) {188// For eSymbolTypeReExported, the "const char *" from a ConstString is used189// as the offset in the address range base address. We can then make this190// back into a string that is the re-exported name.191intptr_t str_ptr = m_addr_range.GetByteSize();192if (str_ptr != 0)193return FileSpec((const char *)str_ptr);194}195return FileSpec();196}197198void Symbol::SetReExportedSymbolName(ConstString name) {199SetType(eSymbolTypeReExported);200// For eSymbolTypeReExported, the "const char *" from a ConstString is used201// as the offset in the address range base address.202m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString());203}204205bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) {206if (m_type == eSymbolTypeReExported) {207// For eSymbolTypeReExported, the "const char *" from a ConstString is used208// as the offset in the address range base address.209m_addr_range.SetByteSize(210(uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString());211return true;212}213return false;214}215216uint32_t Symbol::GetSiblingIndex() const {217return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;218}219220bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }221222bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }223224void Symbol::GetDescription(225Stream *s, lldb::DescriptionLevel level, Target *target,226std::optional<Stream::HighlightSettings> settings) const {227s->Printf("id = {0x%8.8x}", m_uid);228229if (m_addr_range.GetBaseAddress().GetSection()) {230if (ValueIsAddress()) {231const lldb::addr_t byte_size = GetByteSize();232if (byte_size > 0) {233s->PutCString(", range = ");234m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress,235Address::DumpStyleFileAddress);236} else {237s->PutCString(", address = ");238m_addr_range.GetBaseAddress().Dump(s, target,239Address::DumpStyleLoadAddress,240Address::DumpStyleFileAddress);241}242} else243s->Printf(", value = 0x%16.16" PRIx64,244m_addr_range.GetBaseAddress().GetOffset());245} else {246if (m_size_is_sibling)247s->Printf(", sibling = %5" PRIu64,248m_addr_range.GetBaseAddress().GetOffset());249else250s->Printf(", value = 0x%16.16" PRIx64,251m_addr_range.GetBaseAddress().GetOffset());252}253if (ConstString demangled = m_mangled.GetDemangledName()) {254s->PutCString(", name=\"");255s->PutCStringColorHighlighted(demangled.GetStringRef(), settings);256s->PutCString("\"");257}258if (ConstString mangled_name = m_mangled.GetMangledName()) {259s->PutCString(", mangled=\"");260s->PutCStringColorHighlighted(mangled_name.GetStringRef(), settings);261s->PutCString("\"");262}263}264265void Symbol::Dump(Stream *s, Target *target, uint32_t index,266Mangled::NamePreference name_preference) const {267s->Printf("[%5u] %6u %c%c%c %-15s ", index, GetID(), m_is_debug ? 'D' : ' ',268m_is_synthetic ? 'S' : ' ', m_is_external ? 'X' : ' ',269GetTypeAsString());270271// Make sure the size of the symbol is up to date before dumping272GetByteSize();273274ConstString name = GetMangled().GetName(name_preference);275if (ValueIsAddress()) {276if (!m_addr_range.GetBaseAddress().Dump(s, nullptr,277Address::DumpStyleFileAddress))278s->Printf("%*s", 18, "");279280s->PutChar(' ');281282if (!m_addr_range.GetBaseAddress().Dump(s, target,283Address::DumpStyleLoadAddress))284s->Printf("%*s", 18, "");285286const char *format = m_size_is_sibling ? " Sibling -> [%5llu] 0x%8.8x %s\n"287: " 0x%16.16" PRIx64 " 0x%8.8x %s\n";288s->Printf(format, GetByteSize(), m_flags, name.AsCString(""));289} else if (m_type == eSymbolTypeReExported) {290s->Printf(291" 0x%8.8x %s",292m_flags, name.AsCString(""));293294ConstString reexport_name = GetReExportedSymbolName();295intptr_t shlib = m_addr_range.GetByteSize();296if (shlib)297s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());298else299s->Printf(" -> %s\n", reexport_name.GetCString());300} else {301const char *format =302m_size_is_sibling303? "0x%16.16" PRIx64304" Sibling -> [%5llu] 0x%8.8x %s\n"305: "0x%16.16" PRIx64 " 0x%16.16" PRIx64306" 0x%8.8x %s\n";307s->Printf(format, m_addr_range.GetBaseAddress().GetOffset(), GetByteSize(),308m_flags, name.AsCString(""));309}310}311312uint32_t Symbol::GetPrologueByteSize() {313if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) {314if (!m_type_data_resolved) {315m_type_data_resolved = true;316317const Address &base_address = m_addr_range.GetBaseAddress();318Function *function = base_address.CalculateSymbolContextFunction();319if (function) {320// Functions have line entries which can also potentially have end of321// prologue information. So if this symbol points to a function, use322// the prologue information from there.323m_type_data = function->GetPrologueByteSize();324} else {325ModuleSP module_sp(base_address.GetModule());326SymbolContext sc;327if (module_sp) {328uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress(329base_address, eSymbolContextLineEntry, sc);330if (resolved_flags & eSymbolContextLineEntry) {331// Default to the end of the first line entry.332m_type_data = sc.line_entry.range.GetByteSize();333334// Set address for next line.335Address addr(base_address);336addr.Slide(m_type_data);337338// Check the first few instructions and look for one that has a339// line number that is different than the first entry. This is also340// done in Function::GetPrologueByteSize().341uint16_t total_offset = m_type_data;342for (int idx = 0; idx < 6; ++idx) {343SymbolContext sc_temp;344resolved_flags = module_sp->ResolveSymbolContextForAddress(345addr, eSymbolContextLineEntry, sc_temp);346// Make sure we got line number information...347if (!(resolved_flags & eSymbolContextLineEntry))348break;349350// If this line number is different than our first one, use it351// and we're done.352if (sc_temp.line_entry.line != sc.line_entry.line) {353m_type_data = total_offset;354break;355}356357// Slide addr up to the next line address.358addr.Slide(sc_temp.line_entry.range.GetByteSize());359total_offset += sc_temp.line_entry.range.GetByteSize();360// If we've gone too far, bail out.361if (total_offset >= m_addr_range.GetByteSize())362break;363}364365// Sanity check - this may be a function in the middle of code that366// has debug information, but not for this symbol. So the line367// entries surrounding us won't lie inside our function. In that368// case, the line entry will be bigger than we are, so we do that369// quick check and if that is true, we just return 0.370if (m_type_data >= m_addr_range.GetByteSize())371m_type_data = 0;372} else {373// TODO: expose something in Process to figure out the374// size of a function prologue.375m_type_data = 0;376}377}378}379}380return m_type_data;381}382return 0;383}384385bool Symbol::Compare(ConstString name, SymbolType type) const {386if (type == eSymbolTypeAny || m_type == type) {387const Mangled &mangled = GetMangled();388return mangled.GetMangledName() == name ||389mangled.GetDemangledName() == name;390}391return false;392}393394#define ENUM_TO_CSTRING(x) \395case eSymbolType##x: \396return #x;397398const char *Symbol::GetTypeAsString() const {399switch (m_type) {400ENUM_TO_CSTRING(Invalid);401ENUM_TO_CSTRING(Absolute);402ENUM_TO_CSTRING(Code);403ENUM_TO_CSTRING(Resolver);404ENUM_TO_CSTRING(Data);405ENUM_TO_CSTRING(Trampoline);406ENUM_TO_CSTRING(Runtime);407ENUM_TO_CSTRING(Exception);408ENUM_TO_CSTRING(SourceFile);409ENUM_TO_CSTRING(HeaderFile);410ENUM_TO_CSTRING(ObjectFile);411ENUM_TO_CSTRING(CommonBlock);412ENUM_TO_CSTRING(Block);413ENUM_TO_CSTRING(Local);414ENUM_TO_CSTRING(Param);415ENUM_TO_CSTRING(Variable);416ENUM_TO_CSTRING(VariableType);417ENUM_TO_CSTRING(LineEntry);418ENUM_TO_CSTRING(LineHeader);419ENUM_TO_CSTRING(ScopeBegin);420ENUM_TO_CSTRING(ScopeEnd);421ENUM_TO_CSTRING(Additional);422ENUM_TO_CSTRING(Compiler);423ENUM_TO_CSTRING(Instrumentation);424ENUM_TO_CSTRING(Undefined);425ENUM_TO_CSTRING(ObjCClass);426ENUM_TO_CSTRING(ObjCMetaClass);427ENUM_TO_CSTRING(ObjCIVar);428ENUM_TO_CSTRING(ReExported);429default:430break;431}432return "<unknown SymbolType>";433}434435void Symbol::CalculateSymbolContext(SymbolContext *sc) {436// Symbols can reconstruct the symbol and the module in the symbol context437sc->symbol = this;438if (ValueIsAddress())439sc->module_sp = GetAddressRef().GetModule();440else441sc->module_sp.reset();442}443444ModuleSP Symbol::CalculateSymbolContextModule() {445if (ValueIsAddress())446return GetAddressRef().GetModule();447return ModuleSP();448}449450Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }451452void Symbol::DumpSymbolContext(Stream *s) {453bool dumped_module = false;454if (ValueIsAddress()) {455ModuleSP module_sp(GetAddressRef().GetModule());456if (module_sp) {457dumped_module = true;458module_sp->DumpSymbolContext(s);459}460}461if (dumped_module)462s->PutCString(", ");463464s->Printf("Symbol{0x%8.8x}", GetID());465}466467lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }468469Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(470Target &target, ConstString &reexport_name, ModuleSpec &module_spec,471ModuleList &seen_modules) const {472ModuleSP module_sp;473if (module_spec.GetFileSpec()) {474// Try searching for the module file spec first using the full path475module_sp = target.GetImages().FindFirstModule(module_spec);476if (!module_sp) {477// Next try and find the module by basename in case environment variables478// or other runtime trickery causes shared libraries to be loaded from479// alternate paths480module_spec.GetFileSpec().ClearDirectory();481module_sp = target.GetImages().FindFirstModule(module_spec);482}483}484485if (module_sp) {486// There should not be cycles in the reexport list, but we don't want to487// crash if there are so make sure we haven't seen this before:488if (!seen_modules.AppendIfNeeded(module_sp))489return nullptr;490491lldb_private::SymbolContextList sc_list;492module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,493sc_list);494for (const SymbolContext &sc : sc_list) {495if (sc.symbol->IsExternal())496return sc.symbol;497}498// If we didn't find the symbol in this module, it may be because this499// module re-exports some whole other library. We have to search those as500// well:501seen_modules.Append(module_sp);502503FileSpecList reexported_libraries =504module_sp->GetObjectFile()->GetReExportedLibraries();505size_t num_reexported_libraries = reexported_libraries.GetSize();506for (size_t idx = 0; idx < num_reexported_libraries; idx++) {507ModuleSpec reexported_module_spec;508reexported_module_spec.GetFileSpec() =509reexported_libraries.GetFileSpecAtIndex(idx);510Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(511target, reexport_name, reexported_module_spec, seen_modules);512if (result_symbol)513return result_symbol;514}515}516return nullptr;517}518519Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {520ConstString reexport_name(GetReExportedSymbolName());521if (reexport_name) {522ModuleSpec module_spec;523ModuleList seen_modules;524module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();525if (module_spec.GetFileSpec()) {526return ResolveReExportedSymbolInModuleSpec(target, reexport_name,527module_spec, seen_modules);528}529}530return nullptr;531}532533lldb::addr_t Symbol::GetFileAddress() const {534if (ValueIsAddress())535return GetAddressRef().GetFileAddress();536else537return LLDB_INVALID_ADDRESS;538}539540lldb::addr_t Symbol::GetLoadAddress(Target *target) const {541if (ValueIsAddress())542return GetAddressRef().GetLoadAddress(target);543else544return LLDB_INVALID_ADDRESS;545}546547ConstString Symbol::GetName() const { return GetMangled().GetName(); }548549ConstString Symbol::GetNameNoArguments() const {550return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments);551}552553lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const {554if (GetType() == lldb::eSymbolTypeUndefined)555return LLDB_INVALID_ADDRESS;556557Address func_so_addr;558559bool is_indirect = IsIndirect();560if (GetType() == eSymbolTypeReExported) {561Symbol *reexported_symbol = ResolveReExportedSymbol(target);562if (reexported_symbol) {563func_so_addr = reexported_symbol->GetAddress();564is_indirect = reexported_symbol->IsIndirect();565}566} else {567func_so_addr = GetAddress();568is_indirect = IsIndirect();569}570571if (func_so_addr.IsValid()) {572if (!target.GetProcessSP() && is_indirect) {573// can't resolve indirect symbols without calling a function...574return LLDB_INVALID_ADDRESS;575}576577lldb::addr_t load_addr =578func_so_addr.GetCallableLoadAddress(&target, is_indirect);579580if (load_addr != LLDB_INVALID_ADDRESS) {581return load_addr;582}583}584585return LLDB_INVALID_ADDRESS;586}587588lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,589const char *flavor,590bool prefer_file_cache) {591ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule());592if (module_sp && exe_ctx.HasTargetScope()) {593return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr,594flavor, exe_ctx.GetTargetRef(),595m_addr_range, !prefer_file_cache);596}597return lldb::DisassemblerSP();598}599600bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor,601bool prefer_file_cache, Stream &strm) {602lldb::DisassemblerSP disassembler_sp =603GetInstructions(exe_ctx, flavor, prefer_file_cache);604if (disassembler_sp) {605const bool show_address = true;606const bool show_bytes = false;607const bool show_control_flow_kind = false;608disassembler_sp->GetInstructionList().Dump(609&strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);610return true;611}612return false;613}614615bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {616return m_addr_range.ContainsFileAddress(file_addr);617}618619bool Symbol::IsSyntheticWithAutoGeneratedName() const {620if (!IsSynthetic())621return false;622if (!m_mangled)623return true;624ConstString demangled = m_mangled.GetDemangledName();625return demangled.GetStringRef().starts_with(GetSyntheticSymbolPrefix());626}627628void Symbol::SynthesizeNameIfNeeded() const {629if (m_is_synthetic && !m_mangled) {630// Synthetic symbol names don't mean anything, but they do uniquely631// identify individual symbols so we give them a unique name. The name632// starts with the synthetic symbol prefix, followed by a unique number.633// Typically the UserID of a real symbol is the symbol table index of the634// symbol in the object file's symbol table(s), so it will be the same635// every time you read in the object file. We want the same persistence for636// synthetic symbols so that users can identify them across multiple debug637// sessions, to understand crashes in those symbols and to reliably set638// breakpoints on them.639llvm::SmallString<256> name;640llvm::raw_svector_ostream os(name);641os << GetSyntheticSymbolPrefix() << GetID();642m_mangled.SetDemangledName(ConstString(os.str()));643}644}645646bool Symbol::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,647const SectionList *section_list,648const StringTableReader &strtab) {649if (!data.ValidOffsetForDataOfSize(*offset_ptr, 8))650return false;651m_uid = data.GetU32(offset_ptr);652m_type_data = data.GetU16(offset_ptr);653const uint16_t bitfields = data.GetU16(offset_ptr);654m_type_data_resolved = (1u << 15 & bitfields) != 0;655m_is_synthetic = (1u << 14 & bitfields) != 0;656m_is_debug = (1u << 13 & bitfields) != 0;657m_is_external = (1u << 12 & bitfields) != 0;658m_size_is_sibling = (1u << 11 & bitfields) != 0;659m_size_is_synthesized = (1u << 10 & bitfields) != 0;660m_size_is_valid = (1u << 9 & bitfields) != 0;661m_demangled_is_synthesized = (1u << 8 & bitfields) != 0;662m_contains_linker_annotations = (1u << 7 & bitfields) != 0;663m_is_weak = (1u << 6 & bitfields) != 0;664m_type = bitfields & 0x003f;665if (!m_mangled.Decode(data, offset_ptr, strtab))666return false;667if (!data.ValidOffsetForDataOfSize(*offset_ptr, 20))668return false;669const bool is_addr = data.GetU8(offset_ptr) != 0;670const uint64_t value = data.GetU64(offset_ptr);671if (is_addr) {672m_addr_range.GetBaseAddress().ResolveAddressUsingFileSections(value,673section_list);674} else {675m_addr_range.GetBaseAddress().Clear();676m_addr_range.GetBaseAddress().SetOffset(value);677}678m_addr_range.SetByteSize(data.GetU64(offset_ptr));679m_flags = data.GetU32(offset_ptr);680return true;681}682683/// The encoding format for the symbol is as follows:684///685/// uint32_t m_uid;686/// uint16_t m_type_data;687/// uint16_t bitfield_data;688/// Mangled mangled;689/// uint8_t is_addr;690/// uint64_t file_addr_or_value;691/// uint64_t size;692/// uint32_t flags;693///694/// The only tricky thing in this encoding is encoding all of the bits in the695/// bitfields. We use a trick to store all bitfields as a 16 bit value and we696/// do the same thing when decoding the symbol. There are test that ensure this697/// encoding works for each individual bit. Everything else is very easy to698/// store.699void Symbol::Encode(DataEncoder &file, ConstStringTable &strtab) const {700file.AppendU32(m_uid);701file.AppendU16(m_type_data);702uint16_t bitfields = m_type;703if (m_type_data_resolved)704bitfields |= 1u << 15;705if (m_is_synthetic)706bitfields |= 1u << 14;707if (m_is_debug)708bitfields |= 1u << 13;709if (m_is_external)710bitfields |= 1u << 12;711if (m_size_is_sibling)712bitfields |= 1u << 11;713if (m_size_is_synthesized)714bitfields |= 1u << 10;715if (m_size_is_valid)716bitfields |= 1u << 9;717if (m_demangled_is_synthesized)718bitfields |= 1u << 8;719if (m_contains_linker_annotations)720bitfields |= 1u << 7;721if (m_is_weak)722bitfields |= 1u << 6;723file.AppendU16(bitfields);724m_mangled.Encode(file, strtab);725// A symbol's value might be an address, or it might be a constant. If the726// symbol's base address doesn't have a section, then it is a constant value.727// If it does have a section, we will encode the file address and re-resolve728// the address when we decode it.729bool is_addr = m_addr_range.GetBaseAddress().GetSection().get() != nullptr;730file.AppendU8(is_addr);731file.AppendU64(m_addr_range.GetBaseAddress().GetFileAddress());732file.AppendU64(m_addr_range.GetByteSize());733file.AppendU32(m_flags);734}735736bool Symbol::operator==(const Symbol &rhs) const {737if (m_uid != rhs.m_uid)738return false;739if (m_type_data != rhs.m_type_data)740return false;741if (m_type_data_resolved != rhs.m_type_data_resolved)742return false;743if (m_is_synthetic != rhs.m_is_synthetic)744return false;745if (m_is_debug != rhs.m_is_debug)746return false;747if (m_is_external != rhs.m_is_external)748return false;749if (m_size_is_sibling != rhs.m_size_is_sibling)750return false;751if (m_size_is_synthesized != rhs.m_size_is_synthesized)752return false;753if (m_size_is_valid != rhs.m_size_is_valid)754return false;755if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)756return false;757if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)758return false;759if (m_is_weak != rhs.m_is_weak)760return false;761if (m_type != rhs.m_type)762return false;763if (m_mangled != rhs.m_mangled)764return false;765if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())766return false;767if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())768return false;769if (m_flags != rhs.m_flags)770return false;771return true;772}773774namespace llvm {775namespace json {776777bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,778llvm::json::Path path) {779llvm::json::ObjectMapper o(value, path);780const bool mapped = o && o.map("value", symbol.value) &&781o.map("address", symbol.address) &&782o.map("size", symbol.size) && o.map("id", symbol.id) &&783o.map("type", symbol.type) && o.map("name", symbol.name);784785if (!mapped)786return false;787788if (!symbol.value && !symbol.address) {789path.report("symbol must have either a value or an address");790return false;791}792793if (symbol.value && symbol.address) {794path.report("symbol cannot have both a value and an address");795return false;796}797798return true;799}800801bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,802llvm::json::Path path) {803if (auto str = value.getAsString()) {804type = llvm::StringSwitch<lldb::SymbolType>(*str)805.Case("absolute", eSymbolTypeAbsolute)806.Case("code", eSymbolTypeCode)807.Case("resolver", eSymbolTypeResolver)808.Case("data", eSymbolTypeData)809.Case("trampoline", eSymbolTypeTrampoline)810.Case("runtime", eSymbolTypeRuntime)811.Case("exception", eSymbolTypeException)812.Case("sourcefile", eSymbolTypeSourceFile)813.Case("headerfile", eSymbolTypeHeaderFile)814.Case("objectfile", eSymbolTypeObjectFile)815.Case("commonblock", eSymbolTypeCommonBlock)816.Case("block", eSymbolTypeBlock)817.Case("local", eSymbolTypeLocal)818.Case("param", eSymbolTypeParam)819.Case("variable", eSymbolTypeVariable)820.Case("variableType", eSymbolTypeVariableType)821.Case("lineentry", eSymbolTypeLineEntry)822.Case("lineheader", eSymbolTypeLineHeader)823.Case("scopebegin", eSymbolTypeScopeBegin)824.Case("scopeend", eSymbolTypeScopeEnd)825.Case("additional,", eSymbolTypeAdditional)826.Case("compiler", eSymbolTypeCompiler)827.Case("instrumentation", eSymbolTypeInstrumentation)828.Case("undefined", eSymbolTypeUndefined)829.Case("objcclass", eSymbolTypeObjCClass)830.Case("objcmetaClass", eSymbolTypeObjCMetaClass)831.Case("objcivar", eSymbolTypeObjCIVar)832.Case("reexporte", eSymbolTypeReExported)833.Default(eSymbolTypeInvalid);834835if (type == eSymbolTypeInvalid) {836path.report("invalid symbol type");837return false;838}839840return true;841}842path.report("expected string");843return false;844}845} // namespace json846} // namespace llvm847848849