diff options
Diffstat (limited to 'lldb/source/Symbol/Symbol.cpp')
| -rw-r--r-- | lldb/source/Symbol/Symbol.cpp | 569 | 
1 files changed, 569 insertions, 0 deletions
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp new file mode 100644 index 0000000000000..3f24143358138 --- /dev/null +++ b/lldb/source/Symbol/Symbol.cpp @@ -0,0 +1,569 @@ +//===-- Symbol.cpp ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Symbol.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Symtab.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +Symbol::Symbol() +    : SymbolContextScope(), m_uid(UINT32_MAX), m_type_data(0), +      m_type_data_resolved(false), m_is_synthetic(false), m_is_debug(false), +      m_is_external(false), m_size_is_sibling(false), +      m_size_is_synthesized(false), m_size_is_valid(false), +      m_demangled_is_synthesized(false), m_contains_linker_annotations(false), +      m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(), m_addr_range(), +      m_flags() {} + +Symbol::Symbol(uint32_t symID, llvm::StringRef name, SymbolType type, bool external, +               bool is_debug, bool is_trampoline, bool is_artificial, +               const lldb::SectionSP §ion_sp, addr_t offset, addr_t size, +               bool size_is_valid, bool contains_linker_annotations, +               uint32_t flags) +    : SymbolContextScope(), m_uid(symID), m_type_data(0), +      m_type_data_resolved(false), m_is_synthetic(is_artificial), +      m_is_debug(is_debug), m_is_external(external), m_size_is_sibling(false), +      m_size_is_synthesized(false), m_size_is_valid(size_is_valid || size > 0), +      m_demangled_is_synthesized(false), +      m_contains_linker_annotations(contains_linker_annotations), +      m_is_weak(false), m_type(type), +      m_mangled(name), +      m_addr_range(section_sp, offset, size), m_flags(flags) {} + +Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type, +               bool external, bool is_debug, bool is_trampoline, +               bool is_artificial, const AddressRange &range, +               bool size_is_valid, bool contains_linker_annotations, +               uint32_t flags) +    : SymbolContextScope(), m_uid(symID), m_type_data(0), +      m_type_data_resolved(false), m_is_synthetic(is_artificial), +      m_is_debug(is_debug), m_is_external(external), m_size_is_sibling(false), +      m_size_is_synthesized(false), +      m_size_is_valid(size_is_valid || range.GetByteSize() > 0), +      m_demangled_is_synthesized(false), +      m_contains_linker_annotations(contains_linker_annotations),  +      m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range),  +      m_flags(flags) {} + +Symbol::Symbol(const Symbol &rhs) +    : SymbolContextScope(rhs), m_uid(rhs.m_uid), m_type_data(rhs.m_type_data), +      m_type_data_resolved(rhs.m_type_data_resolved), +      m_is_synthetic(rhs.m_is_synthetic), m_is_debug(rhs.m_is_debug), +      m_is_external(rhs.m_is_external), +      m_size_is_sibling(rhs.m_size_is_sibling), m_size_is_synthesized(false), +      m_size_is_valid(rhs.m_size_is_valid), +      m_demangled_is_synthesized(rhs.m_demangled_is_synthesized), +      m_contains_linker_annotations(rhs.m_contains_linker_annotations), +      m_is_weak(rhs.m_is_weak), m_type(rhs.m_type), m_mangled(rhs.m_mangled), +      m_addr_range(rhs.m_addr_range), m_flags(rhs.m_flags) {} + +const Symbol &Symbol::operator=(const Symbol &rhs) { +  if (this != &rhs) { +    SymbolContextScope::operator=(rhs); +    m_uid = rhs.m_uid; +    m_type_data = rhs.m_type_data; +    m_type_data_resolved = rhs.m_type_data_resolved; +    m_is_synthetic = rhs.m_is_synthetic; +    m_is_debug = rhs.m_is_debug; +    m_is_external = rhs.m_is_external; +    m_size_is_sibling = rhs.m_size_is_sibling; +    m_size_is_synthesized = rhs.m_size_is_sibling; +    m_size_is_valid = rhs.m_size_is_valid; +    m_demangled_is_synthesized = rhs.m_demangled_is_synthesized; +    m_contains_linker_annotations = rhs.m_contains_linker_annotations; +    m_is_weak = rhs.m_is_weak; +    m_type = rhs.m_type; +    m_mangled = rhs.m_mangled; +    m_addr_range = rhs.m_addr_range; +    m_flags = rhs.m_flags; +  } +  return *this; +} + +void Symbol::Clear() { +  m_uid = UINT32_MAX; +  m_mangled.Clear(); +  m_type_data = 0; +  m_type_data_resolved = false; +  m_is_synthetic = false; +  m_is_debug = false; +  m_is_external = false; +  m_size_is_sibling = false; +  m_size_is_synthesized = false; +  m_size_is_valid = false; +  m_demangled_is_synthesized = false; +  m_contains_linker_annotations = false; +  m_is_weak = false; +  m_type = eSymbolTypeInvalid; +  m_flags = 0; +  m_addr_range.Clear(); +} + +bool Symbol::ValueIsAddress() const { +  return m_addr_range.GetBaseAddress().GetSection().get() != nullptr; +} + +ConstString Symbol::GetDisplayName() const { +  return m_mangled.GetDisplayDemangledName(GetLanguage()); +} + +ConstString Symbol::GetReExportedSymbolName() const { +  if (m_type == eSymbolTypeReExported) { +    // For eSymbolTypeReExported, the "const char *" from a ConstString is used +    // as the offset in the address range base address. We can then make this +    // back into a string that is the re-exported name. +    intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset(); +    if (str_ptr != 0) +      return ConstString((const char *)str_ptr); +    else +      return GetName(); +  } +  return ConstString(); +} + +FileSpec Symbol::GetReExportedSymbolSharedLibrary() const { +  if (m_type == eSymbolTypeReExported) { +    // For eSymbolTypeReExported, the "const char *" from a ConstString is used +    // as the offset in the address range base address. We can then make this +    // back into a string that is the re-exported name. +    intptr_t str_ptr = m_addr_range.GetByteSize(); +    if (str_ptr != 0) +      return FileSpec((const char *)str_ptr); +  } +  return FileSpec(); +} + +void Symbol::SetReExportedSymbolName(ConstString name) { +  SetType(eSymbolTypeReExported); +  // For eSymbolTypeReExported, the "const char *" from a ConstString is used +  // as the offset in the address range base address. +  m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString()); +} + +bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) { +  if (m_type == eSymbolTypeReExported) { +    // For eSymbolTypeReExported, the "const char *" from a ConstString is used +    // as the offset in the address range base address. +    m_addr_range.SetByteSize( +        (uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString()); +    return true; +  } +  return false; +} + +uint32_t Symbol::GetSiblingIndex() const { +  return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX; +} + +bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; } + +bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; } + +void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level, +                            Target *target) const { +  s->Printf("id = {0x%8.8x}", m_uid); + +  if (m_addr_range.GetBaseAddress().GetSection()) { +    if (ValueIsAddress()) { +      const lldb::addr_t byte_size = GetByteSize(); +      if (byte_size > 0) { +        s->PutCString(", range = "); +        m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, +                          Address::DumpStyleFileAddress); +      } else { +        s->PutCString(", address = "); +        m_addr_range.GetBaseAddress().Dump(s, target, +                                           Address::DumpStyleLoadAddress, +                                           Address::DumpStyleFileAddress); +      } +    } else +      s->Printf(", value = 0x%16.16" PRIx64, +                m_addr_range.GetBaseAddress().GetOffset()); +  } else { +    if (m_size_is_sibling) +      s->Printf(", sibling = %5" PRIu64, +                m_addr_range.GetBaseAddress().GetOffset()); +    else +      s->Printf(", value = 0x%16.16" PRIx64, +                m_addr_range.GetBaseAddress().GetOffset()); +  } +  ConstString demangled = m_mangled.GetDemangledName(GetLanguage()); +  if (demangled) +    s->Printf(", name=\"%s\"", demangled.AsCString()); +  if (m_mangled.GetMangledName()) +    s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString()); +} + +void Symbol::Dump(Stream *s, Target *target, uint32_t index) const { +  s->Printf("[%5u] %6u %c%c%c %-15s ", index, GetID(), m_is_debug ? 'D' : ' ', +            m_is_synthetic ? 'S' : ' ', m_is_external ? 'X' : ' ', +            GetTypeAsString()); + +  // Make sure the size of the symbol is up to date before dumping +  GetByteSize(); + +  ConstString name = m_mangled.GetName(GetLanguage()); +  if (ValueIsAddress()) { +    if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, +                                            Address::DumpStyleFileAddress)) +      s->Printf("%*s", 18, ""); + +    s->PutChar(' '); + +    if (!m_addr_range.GetBaseAddress().Dump(s, target, +                                            Address::DumpStyleLoadAddress)) +      s->Printf("%*s", 18, ""); + +    const char *format = m_size_is_sibling ? " Sibling -> [%5llu] 0x%8.8x %s\n" +                                           : " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; +    s->Printf(format, GetByteSize(), m_flags, name.AsCString("")); +  } else if (m_type == eSymbolTypeReExported) { +    s->Printf( +        "                                                         0x%8.8x %s", +        m_flags, name.AsCString("")); + +    ConstString reexport_name = GetReExportedSymbolName(); +    intptr_t shlib = m_addr_range.GetByteSize(); +    if (shlib) +      s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString()); +    else +      s->Printf(" -> %s\n", reexport_name.GetCString()); +  } else { +    const char *format = +        m_size_is_sibling +            ? "0x%16.16" PRIx64 +              "                    Sibling -> [%5llu] 0x%8.8x %s\n" +            : "0x%16.16" PRIx64 "                    0x%16.16" PRIx64 +              " 0x%8.8x %s\n"; +    s->Printf(format, m_addr_range.GetBaseAddress().GetOffset(), GetByteSize(), +              m_flags, name.AsCString("")); +  } +} + +uint32_t Symbol::GetPrologueByteSize() { +  if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) { +    if (!m_type_data_resolved) { +      m_type_data_resolved = true; + +      const Address &base_address = m_addr_range.GetBaseAddress(); +      Function *function = base_address.CalculateSymbolContextFunction(); +      if (function) { +        // Functions have line entries which can also potentially have end of +        // prologue information. So if this symbol points to a function, use +        // the prologue information from there. +        m_type_data = function->GetPrologueByteSize(); +      } else { +        ModuleSP module_sp(base_address.GetModule()); +        SymbolContext sc; +        if (module_sp) { +          uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress( +              base_address, eSymbolContextLineEntry, sc); +          if (resolved_flags & eSymbolContextLineEntry) { +            // Default to the end of the first line entry. +            m_type_data = sc.line_entry.range.GetByteSize(); + +            // Set address for next line. +            Address addr(base_address); +            addr.Slide(m_type_data); + +            // Check the first few instructions and look for one that has a +            // line number that is different than the first entry. This is also +            // done in Function::GetPrologueByteSize(). +            uint16_t total_offset = m_type_data; +            for (int idx = 0; idx < 6; ++idx) { +              SymbolContext sc_temp; +              resolved_flags = module_sp->ResolveSymbolContextForAddress( +                  addr, eSymbolContextLineEntry, sc_temp); +              // Make sure we got line number information... +              if (!(resolved_flags & eSymbolContextLineEntry)) +                break; + +              // If this line number is different than our first one, use it +              // and we're done. +              if (sc_temp.line_entry.line != sc.line_entry.line) { +                m_type_data = total_offset; +                break; +              } + +              // Slide addr up to the next line address. +              addr.Slide(sc_temp.line_entry.range.GetByteSize()); +              total_offset += sc_temp.line_entry.range.GetByteSize(); +              // If we've gone too far, bail out. +              if (total_offset >= m_addr_range.GetByteSize()) +                break; +            } + +            // Sanity check - this may be a function in the middle of code that +            // has debug information, but not for this symbol.  So the line +            // entries surrounding us won't lie inside our function. In that +            // case, the line entry will be bigger than we are, so we do that +            // quick check and if that is true, we just return 0. +            if (m_type_data >= m_addr_range.GetByteSize()) +              m_type_data = 0; +          } else { +            // TODO: expose something in Process to figure out the +            // size of a function prologue. +            m_type_data = 0; +          } +        } +      } +    } +    return m_type_data; +  } +  return 0; +} + +bool Symbol::Compare(ConstString name, SymbolType type) const { +  if (type == eSymbolTypeAny || m_type == type) +    return m_mangled.GetMangledName() == name || +           m_mangled.GetDemangledName(GetLanguage()) == name; +  return false; +} + +#define ENUM_TO_CSTRING(x)                                                     \ +  case eSymbolType##x:                                                         \ +    return #x; + +const char *Symbol::GetTypeAsString() const { +  switch (m_type) { +    ENUM_TO_CSTRING(Invalid); +    ENUM_TO_CSTRING(Absolute); +    ENUM_TO_CSTRING(Code); +    ENUM_TO_CSTRING(Resolver); +    ENUM_TO_CSTRING(Data); +    ENUM_TO_CSTRING(Trampoline); +    ENUM_TO_CSTRING(Runtime); +    ENUM_TO_CSTRING(Exception); +    ENUM_TO_CSTRING(SourceFile); +    ENUM_TO_CSTRING(HeaderFile); +    ENUM_TO_CSTRING(ObjectFile); +    ENUM_TO_CSTRING(CommonBlock); +    ENUM_TO_CSTRING(Block); +    ENUM_TO_CSTRING(Local); +    ENUM_TO_CSTRING(Param); +    ENUM_TO_CSTRING(Variable); +    ENUM_TO_CSTRING(VariableType); +    ENUM_TO_CSTRING(LineEntry); +    ENUM_TO_CSTRING(LineHeader); +    ENUM_TO_CSTRING(ScopeBegin); +    ENUM_TO_CSTRING(ScopeEnd); +    ENUM_TO_CSTRING(Additional); +    ENUM_TO_CSTRING(Compiler); +    ENUM_TO_CSTRING(Instrumentation); +    ENUM_TO_CSTRING(Undefined); +    ENUM_TO_CSTRING(ObjCClass); +    ENUM_TO_CSTRING(ObjCMetaClass); +    ENUM_TO_CSTRING(ObjCIVar); +    ENUM_TO_CSTRING(ReExported); +  default: +    break; +  } +  return "<unknown SymbolType>"; +} + +void Symbol::CalculateSymbolContext(SymbolContext *sc) { +  // Symbols can reconstruct the symbol and the module in the symbol context +  sc->symbol = this; +  if (ValueIsAddress()) +    sc->module_sp = GetAddressRef().GetModule(); +  else +    sc->module_sp.reset(); +} + +ModuleSP Symbol::CalculateSymbolContextModule() { +  if (ValueIsAddress()) +    return GetAddressRef().GetModule(); +  return ModuleSP(); +} + +Symbol *Symbol::CalculateSymbolContextSymbol() { return this; } + +void Symbol::DumpSymbolContext(Stream *s) { +  bool dumped_module = false; +  if (ValueIsAddress()) { +    ModuleSP module_sp(GetAddressRef().GetModule()); +    if (module_sp) { +      dumped_module = true; +      module_sp->DumpSymbolContext(s); +    } +  } +  if (dumped_module) +    s->PutCString(", "); + +  s->Printf("Symbol{0x%8.8x}", GetID()); +} + +lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); } + +Symbol *Symbol::ResolveReExportedSymbolInModuleSpec( +    Target &target, ConstString &reexport_name, ModuleSpec &module_spec, +    ModuleList &seen_modules) const { +  ModuleSP module_sp; +  if (module_spec.GetFileSpec()) { +    // Try searching for the module file spec first using the full path +    module_sp = target.GetImages().FindFirstModule(module_spec); +    if (!module_sp) { +      // Next try and find the module by basename in case environment variables +      // or other runtime trickery causes shared libraries to be loaded from +      // alternate paths +      module_spec.GetFileSpec().GetDirectory().Clear(); +      module_sp = target.GetImages().FindFirstModule(module_spec); +    } +  } + +  if (module_sp) { +    // There should not be cycles in the reexport list, but we don't want to +    // crash if there are so make sure we haven't seen this before: +    if (!seen_modules.AppendIfNeeded(module_sp)) +      return nullptr; + +    lldb_private::SymbolContextList sc_list; +    module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, +                                          sc_list); +    const size_t num_scs = sc_list.GetSize(); +    if (num_scs > 0) { +      for (size_t i = 0; i < num_scs; ++i) { +        lldb_private::SymbolContext sc; +        if (sc_list.GetContextAtIndex(i, sc)) { +          if (sc.symbol->IsExternal()) +            return sc.symbol; +        } +      } +    } +    // If we didn't find the symbol in this module, it may be because this +    // module re-exports some whole other library.  We have to search those as +    // well: +    seen_modules.Append(module_sp); + +    FileSpecList reexported_libraries = +        module_sp->GetObjectFile()->GetReExportedLibraries(); +    size_t num_reexported_libraries = reexported_libraries.GetSize(); +    for (size_t idx = 0; idx < num_reexported_libraries; idx++) { +      ModuleSpec reexported_module_spec; +      reexported_module_spec.GetFileSpec() = +          reexported_libraries.GetFileSpecAtIndex(idx); +      Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec( +          target, reexport_name, reexported_module_spec, seen_modules); +      if (result_symbol) +        return result_symbol; +    } +  } +  return nullptr; +} + +Symbol *Symbol::ResolveReExportedSymbol(Target &target) const { +  ConstString reexport_name(GetReExportedSymbolName()); +  if (reexport_name) { +    ModuleSpec module_spec; +    ModuleList seen_modules; +    module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary(); +    if (module_spec.GetFileSpec()) { +      return ResolveReExportedSymbolInModuleSpec(target, reexport_name, +                                                 module_spec, seen_modules); +    } +  } +  return nullptr; +} + +lldb::addr_t Symbol::GetFileAddress() const { +  if (ValueIsAddress()) +    return GetAddressRef().GetFileAddress(); +  else +    return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t Symbol::GetLoadAddress(Target *target) const { +  if (ValueIsAddress()) +    return GetAddressRef().GetLoadAddress(target); +  else +    return LLDB_INVALID_ADDRESS; +} + +ConstString Symbol::GetName() const { return m_mangled.GetName(GetLanguage()); } + +ConstString Symbol::GetNameNoArguments() const { +  return m_mangled.GetName(GetLanguage(), +                           Mangled::ePreferDemangledWithoutArguments); +} + +lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const { +  if (GetType() == lldb::eSymbolTypeUndefined) +    return LLDB_INVALID_ADDRESS; + +  Address func_so_addr; + +  bool is_indirect = IsIndirect(); +  if (GetType() == eSymbolTypeReExported) { +    Symbol *reexported_symbol = ResolveReExportedSymbol(target); +    if (reexported_symbol) { +      func_so_addr = reexported_symbol->GetAddress(); +      is_indirect = reexported_symbol->IsIndirect(); +    } +  } else { +    func_so_addr = GetAddress(); +    is_indirect = IsIndirect(); +  } + +  if (func_so_addr.IsValid()) { +    if (!target.GetProcessSP() && is_indirect) { +      // can't resolve indirect symbols without calling a function... +      return LLDB_INVALID_ADDRESS; +    } + +    lldb::addr_t load_addr = +        func_so_addr.GetCallableLoadAddress(&target, is_indirect); + +    if (load_addr != LLDB_INVALID_ADDRESS) { +      return load_addr; +    } +  } + +  return LLDB_INVALID_ADDRESS; +} + +lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx, +                                             const char *flavor, +                                             bool prefer_file_cache) { +  ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule()); +  if (module_sp) { +    const bool prefer_file_cache = false; +    return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, +                                          flavor, exe_ctx, m_addr_range, +                                          prefer_file_cache); +  } +  return lldb::DisassemblerSP(); +} + +bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor, +                            bool prefer_file_cache, Stream &strm) { +  lldb::DisassemblerSP disassembler_sp = +      GetInstructions(exe_ctx, flavor, prefer_file_cache); +  if (disassembler_sp) { +    const bool show_address = true; +    const bool show_bytes = false; +    disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes, +                                               &exe_ctx); +    return true; +  } +  return false; +} + +bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const { +  return m_addr_range.ContainsFileAddress(file_addr); +}  | 
