brintos

brintos / llvm-project-archived public Read only

0
0
Text · 31.0 KiB · 40497db Raw
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 &section_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