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