xref: /freebsd/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
26 using namespace lldb;
27 using namespace lldb_private;
28 
Symbol()29 Symbol::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 
Symbol(uint32_t symID,llvm::StringRef name,SymbolType type,bool external,bool is_debug,bool is_trampoline,bool is_artificial,const lldb::SectionSP & section_sp,addr_t offset,addr_t size,bool size_is_valid,bool contains_linker_annotations,uint32_t flags)37 Symbol::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 
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)51 Symbol::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 
Symbol(const Symbol & rhs)66 Symbol::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 
operator =(const Symbol & rhs)78 const 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 
FromJSON(const JSONSymbol & symbol,SectionList * section_list)101 llvm::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 the
138   // 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 
Clear()146 void 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 
ValueIsAddress() const165 bool Symbol::ValueIsAddress() const {
166   return (bool)m_addr_range.GetBaseAddress().GetSection();
167 }
168 
GetDisplayName() const169 ConstString Symbol::GetDisplayName() const {
170   return GetMangled().GetDisplayDemangledName();
171 }
172 
GetReExportedSymbolName() const173 ConstString Symbol::GetReExportedSymbolName() const {
174   if (m_type == eSymbolTypeReExported) {
175     // For eSymbolTypeReExported, the "const char *" from a ConstString is used
176     // as the offset in the address range base address. We can then make this
177     // 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     else
182       return GetName();
183   }
184   return ConstString();
185 }
186 
GetReExportedSymbolSharedLibrary() const187 FileSpec Symbol::GetReExportedSymbolSharedLibrary() const {
188   if (m_type == eSymbolTypeReExported) {
189     // For eSymbolTypeReExported, the "const char *" from a ConstString is used
190     // as the offset in the address range base address. We can then make this
191     // 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 
SetReExportedSymbolName(ConstString name)199 void Symbol::SetReExportedSymbolName(ConstString name) {
200   SetType(eSymbolTypeReExported);
201   // For eSymbolTypeReExported, the "const char *" from a ConstString is used
202   // as the offset in the address range base address.
203   m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString());
204 }
205 
SetReExportedSymbolSharedLibrary(const FileSpec & fspec)206 bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) {
207   if (m_type == eSymbolTypeReExported) {
208     // For eSymbolTypeReExported, the "const char *" from a ConstString is used
209     // 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 
GetSiblingIndex() const217 uint32_t Symbol::GetSiblingIndex() const {
218   return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;
219 }
220 
IsTrampoline() const221 bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
222 
IsIndirect() const223 bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
224 
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target,std::optional<Stream::HighlightSettings> settings) const225 void 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     } else
244       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     else
251       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 
Dump(Stream * s,Target * target,uint32_t index,Mangled::NamePreference name_preference) const266 void 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 dumping
273   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     else
300       s->Printf(" -> %s\n", reexport_name.GetCString());
301   } else {
302     const char *format =
303         m_size_is_sibling
304             ? "0x%16.16" PRIx64
305               "                    Sibling -> [%5llu] 0x%8.8x %s\n"
306             : "0x%16.16" PRIx64 "                    0x%16.16" PRIx64
307               " 0x%8.8x %s\n";
308     s->Printf(format, m_addr_range.GetBaseAddress().GetOffset(), GetByteSize(),
309               m_flags, name.AsCString(""));
310   }
311 }
312 
GetPrologueByteSize()313 uint32_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 of
322         // prologue information. So if this symbol points to a function, use
323         // 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 a
340             // line number that is different than the first entry. This is also
341             // 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 it
352               // 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 that
367             // has debug information, but not for this symbol.  So the line
368             // entries surrounding us won't lie inside our function. In that
369             // case, the line entry will be bigger than we are, so we do that
370             // 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 the
375             // 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 
Compare(ConstString name,SymbolType type) const386 bool 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 
395 #define ENUM_TO_CSTRING(x)                                                     \
396   case eSymbolType##x:                                                         \
397     return #x;
398 
GetTypeAsString() const399 const char *Symbol::GetTypeAsString() const {
400   switch (m_type) {
401     ENUM_TO_CSTRING(Invalid);
402     ENUM_TO_CSTRING(Absolute);
403     ENUM_TO_CSTRING(Code);
404     ENUM_TO_CSTRING(Resolver);
405     ENUM_TO_CSTRING(Data);
406     ENUM_TO_CSTRING(Trampoline);
407     ENUM_TO_CSTRING(Runtime);
408     ENUM_TO_CSTRING(Exception);
409     ENUM_TO_CSTRING(SourceFile);
410     ENUM_TO_CSTRING(HeaderFile);
411     ENUM_TO_CSTRING(ObjectFile);
412     ENUM_TO_CSTRING(CommonBlock);
413     ENUM_TO_CSTRING(Block);
414     ENUM_TO_CSTRING(Local);
415     ENUM_TO_CSTRING(Param);
416     ENUM_TO_CSTRING(Variable);
417     ENUM_TO_CSTRING(VariableType);
418     ENUM_TO_CSTRING(LineEntry);
419     ENUM_TO_CSTRING(LineHeader);
420     ENUM_TO_CSTRING(ScopeBegin);
421     ENUM_TO_CSTRING(ScopeEnd);
422     ENUM_TO_CSTRING(Additional);
423     ENUM_TO_CSTRING(Compiler);
424     ENUM_TO_CSTRING(Instrumentation);
425     ENUM_TO_CSTRING(Undefined);
426     ENUM_TO_CSTRING(ObjCClass);
427     ENUM_TO_CSTRING(ObjCMetaClass);
428     ENUM_TO_CSTRING(ObjCIVar);
429     ENUM_TO_CSTRING(ReExported);
430   default:
431     break;
432   }
433   return "<unknown SymbolType>";
434 }
435 
CalculateSymbolContext(SymbolContext * sc)436 void Symbol::CalculateSymbolContext(SymbolContext *sc) {
437   // Symbols can reconstruct the symbol and the module in the symbol context
438   sc->symbol = this;
439   if (ValueIsAddress())
440     sc->module_sp = GetAddressRef().GetModule();
441   else
442     sc->module_sp.reset();
443 }
444 
CalculateSymbolContextModule()445 ModuleSP Symbol::CalculateSymbolContextModule() {
446   if (ValueIsAddress())
447     return GetAddressRef().GetModule();
448   return ModuleSP();
449 }
450 
CalculateSymbolContextSymbol()451 Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }
452 
DumpSymbolContext(Stream * s)453 void Symbol::DumpSymbolContext(Stream *s) {
454   bool dumped_module = false;
455   if (ValueIsAddress()) {
456     ModuleSP module_sp(GetAddressRef().GetModule());
457     if (module_sp) {
458       dumped_module = true;
459       module_sp->DumpSymbolContext(s);
460     }
461   }
462   if (dumped_module)
463     s->PutCString(", ");
464 
465   s->Printf("Symbol{0x%8.8x}", GetID());
466 }
467 
GetByteSize() const468 lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }
469 
ResolveReExportedSymbolInModuleSpec(Target & target,ConstString & reexport_name,ModuleSpec & module_spec,ModuleList & seen_modules) const470 Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(
471     Target &target, ConstString &reexport_name, ModuleSpec &module_spec,
472     ModuleList &seen_modules) const {
473   ModuleSP module_sp;
474   if (module_spec.GetFileSpec()) {
475     // Try searching for the module file spec first using the full path
476     module_sp = target.GetImages().FindFirstModule(module_spec);
477     if (!module_sp) {
478       // Next try and find the module by basename in case environment variables
479       // or other runtime trickery causes shared libraries to be loaded from
480       // alternate paths
481       module_spec.GetFileSpec().ClearDirectory();
482       module_sp = target.GetImages().FindFirstModule(module_spec);
483     }
484   }
485 
486   if (module_sp) {
487     // There should not be cycles in the reexport list, but we don't want to
488     // crash if there are so make sure we haven't seen this before:
489     if (!seen_modules.AppendIfNeeded(module_sp))
490       return nullptr;
491 
492     lldb_private::SymbolContextList sc_list;
493     module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,
494                                           sc_list);
495     for (const SymbolContext &sc : sc_list) {
496       if (sc.symbol->IsExternal())
497         return sc.symbol;
498     }
499     // If we didn't find the symbol in this module, it may be because this
500     // module re-exports some whole other library.  We have to search those as
501     // well:
502     seen_modules.Append(module_sp);
503 
504     FileSpecList reexported_libraries =
505         module_sp->GetObjectFile()->GetReExportedLibraries();
506     size_t num_reexported_libraries = reexported_libraries.GetSize();
507     for (size_t idx = 0; idx < num_reexported_libraries; idx++) {
508       ModuleSpec reexported_module_spec;
509       reexported_module_spec.GetFileSpec() =
510           reexported_libraries.GetFileSpecAtIndex(idx);
511       Symbol *result_symbol = ResolveReExportedSymbolInModuleSpec(
512           target, reexport_name, reexported_module_spec, seen_modules);
513       if (result_symbol)
514         return result_symbol;
515     }
516   }
517   return nullptr;
518 }
519 
ResolveReExportedSymbol(Target & target) const520 Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {
521   ConstString reexport_name(GetReExportedSymbolName());
522   if (reexport_name) {
523     ModuleSpec module_spec;
524     ModuleList seen_modules;
525     module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
526     if (module_spec.GetFileSpec()) {
527       return ResolveReExportedSymbolInModuleSpec(target, reexport_name,
528                                                  module_spec, seen_modules);
529     }
530   }
531   return nullptr;
532 }
533 
GetFileAddress() const534 lldb::addr_t Symbol::GetFileAddress() const {
535   if (ValueIsAddress())
536     return GetAddressRef().GetFileAddress();
537   else
538     return LLDB_INVALID_ADDRESS;
539 }
540 
GetLoadAddress(Target * target) const541 lldb::addr_t Symbol::GetLoadAddress(Target *target) const {
542   if (ValueIsAddress())
543     return GetAddressRef().GetLoadAddress(target);
544   else
545     return LLDB_INVALID_ADDRESS;
546 }
547 
GetName() const548 ConstString Symbol::GetName() const { return GetMangled().GetName(); }
549 
GetNameNoArguments() const550 ConstString Symbol::GetNameNoArguments() const {
551   return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments);
552 }
553 
ResolveCallableAddress(Target & target) const554 lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const {
555   if (GetType() == lldb::eSymbolTypeUndefined)
556     return LLDB_INVALID_ADDRESS;
557 
558   Address func_so_addr;
559 
560   bool is_indirect = IsIndirect();
561   if (GetType() == eSymbolTypeReExported) {
562     Symbol *reexported_symbol = ResolveReExportedSymbol(target);
563     if (reexported_symbol) {
564       func_so_addr = reexported_symbol->GetAddress();
565       is_indirect = reexported_symbol->IsIndirect();
566     }
567   } else {
568     func_so_addr = GetAddress();
569     is_indirect = IsIndirect();
570   }
571 
572   if (func_so_addr.IsValid()) {
573     if (!target.GetProcessSP() && is_indirect) {
574       // can't resolve indirect symbols without calling a function...
575       return LLDB_INVALID_ADDRESS;
576     }
577 
578     lldb::addr_t load_addr =
579         func_so_addr.GetCallableLoadAddress(&target, is_indirect);
580 
581     if (load_addr != LLDB_INVALID_ADDRESS) {
582       return load_addr;
583     }
584   }
585 
586   return LLDB_INVALID_ADDRESS;
587 }
588 
GetInstructions(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache)589 lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,
590                                              const char *flavor,
591                                              bool prefer_file_cache) {
592   ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule());
593   if (module_sp && exe_ctx.HasTargetScope()) {
594     return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr,
595                                           flavor, exe_ctx.GetTargetRef(),
596                                           m_addr_range, !prefer_file_cache);
597   }
598   return lldb::DisassemblerSP();
599 }
600 
GetDisassembly(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache,Stream & strm)601 bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor,
602                             bool prefer_file_cache, Stream &strm) {
603   lldb::DisassemblerSP disassembler_sp =
604       GetInstructions(exe_ctx, flavor, prefer_file_cache);
605   if (disassembler_sp) {
606     const bool show_address = true;
607     const bool show_bytes = false;
608     const bool show_control_flow_kind = false;
609     disassembler_sp->GetInstructionList().Dump(
610         &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
611     return true;
612   }
613   return false;
614 }
615 
ContainsFileAddress(lldb::addr_t file_addr) const616 bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {
617   return m_addr_range.ContainsFileAddress(file_addr);
618 }
619 
IsSyntheticWithAutoGeneratedName() const620 bool Symbol::IsSyntheticWithAutoGeneratedName() const {
621   if (!IsSynthetic())
622     return false;
623   if (!m_mangled)
624     return true;
625   ConstString demangled = m_mangled.GetDemangledName();
626   return demangled.GetStringRef().starts_with(GetSyntheticSymbolPrefix());
627 }
628 
SynthesizeNameIfNeeded() const629 void Symbol::SynthesizeNameIfNeeded() const {
630   if (m_is_synthetic && !m_mangled) {
631     // Synthetic symbol names don't mean anything, but they do uniquely
632     // identify individual symbols so we give them a unique name. The name
633     // starts with the synthetic symbol prefix, followed by a unique number.
634     // Typically the UserID of a real symbol is the symbol table index of the
635     // symbol in the object file's symbol table(s), so it will be the same
636     // every time you read in the object file. We want the same persistence for
637     // synthetic symbols so that users can identify them across multiple debug
638     // sessions, to understand crashes in those symbols and to reliably set
639     // breakpoints on them.
640     llvm::SmallString<256> name;
641     llvm::raw_svector_ostream os(name);
642     os << GetSyntheticSymbolPrefix() << GetID();
643     m_mangled.SetDemangledName(ConstString(os.str()));
644   }
645 }
646 
Decode(const DataExtractor & data,lldb::offset_t * offset_ptr,const SectionList * section_list,const StringTableReader & strtab)647 bool Symbol::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
648                     const SectionList *section_list,
649                     const StringTableReader &strtab) {
650   if (!data.ValidOffsetForDataOfSize(*offset_ptr, 8))
651     return false;
652   m_uid = data.GetU32(offset_ptr);
653   m_type_data = data.GetU16(offset_ptr);
654   const uint16_t bitfields = data.GetU16(offset_ptr);
655   m_type_data_resolved = (1u << 15 & bitfields) != 0;
656   m_is_synthetic = (1u << 14 & bitfields) != 0;
657   m_is_debug = (1u << 13 & bitfields) != 0;
658   m_is_external = (1u << 12 & bitfields) != 0;
659   m_size_is_sibling = (1u << 11 & bitfields) != 0;
660   m_size_is_synthesized = (1u << 10 & bitfields) != 0;
661   m_size_is_valid = (1u << 9 & bitfields) != 0;
662   m_demangled_is_synthesized = (1u << 8 & bitfields) != 0;
663   m_contains_linker_annotations = (1u << 7 & bitfields) != 0;
664   m_is_weak = (1u << 6 & bitfields) != 0;
665   m_type = bitfields & 0x003f;
666   if (!m_mangled.Decode(data, offset_ptr, strtab))
667     return false;
668   if (!data.ValidOffsetForDataOfSize(*offset_ptr, 20))
669     return false;
670   const bool is_addr = data.GetU8(offset_ptr) != 0;
671   const uint64_t value = data.GetU64(offset_ptr);
672   if (is_addr) {
673     m_addr_range.GetBaseAddress().ResolveAddressUsingFileSections(value,
674                                                                   section_list);
675   } else {
676     m_addr_range.GetBaseAddress().Clear();
677     m_addr_range.GetBaseAddress().SetOffset(value);
678   }
679   m_addr_range.SetByteSize(data.GetU64(offset_ptr));
680   m_flags = data.GetU32(offset_ptr);
681   return true;
682 }
683 
684 /// The encoding format for the symbol is as follows:
685 ///
686 /// uint32_t m_uid;
687 /// uint16_t m_type_data;
688 /// uint16_t bitfield_data;
689 /// Mangled mangled;
690 /// uint8_t is_addr;
691 /// uint64_t file_addr_or_value;
692 /// uint64_t size;
693 /// uint32_t flags;
694 ///
695 /// The only tricky thing in this encoding is encoding all of the bits in the
696 /// bitfields. We use a trick to store all bitfields as a 16 bit value and we
697 /// do the same thing when decoding the symbol. There are test that ensure this
698 /// encoding works for each individual bit. Everything else is very easy to
699 /// store.
Encode(DataEncoder & file,ConstStringTable & strtab) const700 void Symbol::Encode(DataEncoder &file, ConstStringTable &strtab) const {
701   file.AppendU32(m_uid);
702   file.AppendU16(m_type_data);
703   uint16_t bitfields = m_type;
704   if (m_type_data_resolved)
705     bitfields |= 1u << 15;
706   if (m_is_synthetic)
707     bitfields |= 1u << 14;
708   if (m_is_debug)
709     bitfields |= 1u << 13;
710   if (m_is_external)
711     bitfields |= 1u << 12;
712   if (m_size_is_sibling)
713     bitfields |= 1u << 11;
714   if (m_size_is_synthesized)
715     bitfields |= 1u << 10;
716   if (m_size_is_valid)
717     bitfields |= 1u << 9;
718   if (m_demangled_is_synthesized)
719     bitfields |= 1u << 8;
720   if (m_contains_linker_annotations)
721     bitfields |= 1u << 7;
722   if (m_is_weak)
723     bitfields |= 1u << 6;
724   file.AppendU16(bitfields);
725   m_mangled.Encode(file, strtab);
726   // A symbol's value might be an address, or it might be a constant. If the
727   // symbol's base address doesn't have a section, then it is a constant value.
728   // If it does have a section, we will encode the file address and re-resolve
729   // the address when we decode it.
730   bool is_addr = m_addr_range.GetBaseAddress().GetSection().get() != nullptr;
731   file.AppendU8(is_addr);
732   file.AppendU64(m_addr_range.GetBaseAddress().GetFileAddress());
733   file.AppendU64(m_addr_range.GetByteSize());
734   file.AppendU32(m_flags);
735 }
736 
operator ==(const Symbol & rhs) const737 bool Symbol::operator==(const Symbol &rhs) const {
738   if (m_uid != rhs.m_uid)
739     return false;
740   if (m_type_data != rhs.m_type_data)
741     return false;
742   if (m_type_data_resolved != rhs.m_type_data_resolved)
743     return false;
744   if (m_is_synthetic != rhs.m_is_synthetic)
745     return false;
746   if (m_is_debug != rhs.m_is_debug)
747     return false;
748   if (m_is_external != rhs.m_is_external)
749     return false;
750   if (m_size_is_sibling != rhs.m_size_is_sibling)
751     return false;
752   if (m_size_is_synthesized != rhs.m_size_is_synthesized)
753     return false;
754   if (m_size_is_valid != rhs.m_size_is_valid)
755     return false;
756   if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)
757     return false;
758   if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)
759     return false;
760   if (m_is_weak != rhs.m_is_weak)
761     return false;
762   if (m_type != rhs.m_type)
763     return false;
764   if (m_mangled != rhs.m_mangled)
765     return false;
766   if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())
767     return false;
768   if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())
769     return false;
770   if (m_flags != rhs.m_flags)
771     return false;
772   return true;
773 }
774 
775 namespace llvm {
776 namespace json {
777 
fromJSON(const llvm::json::Value & value,lldb_private::JSONSymbol & symbol,llvm::json::Path path)778 bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,
779               llvm::json::Path path) {
780   llvm::json::ObjectMapper o(value, path);
781   const bool mapped = o && o.map("value", symbol.value) &&
782                       o.map("address", symbol.address) &&
783                       o.map("size", symbol.size) && o.map("id", symbol.id) &&
784                       o.map("type", symbol.type) && o.map("name", symbol.name);
785 
786   if (!mapped)
787     return false;
788 
789   if (!symbol.value && !symbol.address) {
790     path.report("symbol must have either a value or an address");
791     return false;
792   }
793 
794   if (symbol.value && symbol.address) {
795     path.report("symbol cannot have both a value and an address");
796     return false;
797   }
798 
799   return true;
800 }
801 
fromJSON(const llvm::json::Value & value,lldb::SymbolType & type,llvm::json::Path path)802 bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,
803               llvm::json::Path path) {
804   if (auto str = value.getAsString()) {
805     type = llvm::StringSwitch<lldb::SymbolType>(*str)
806                .Case("absolute", eSymbolTypeAbsolute)
807                .Case("code", eSymbolTypeCode)
808                .Case("resolver", eSymbolTypeResolver)
809                .Case("data", eSymbolTypeData)
810                .Case("trampoline", eSymbolTypeTrampoline)
811                .Case("runtime", eSymbolTypeRuntime)
812                .Case("exception", eSymbolTypeException)
813                .Case("sourcefile", eSymbolTypeSourceFile)
814                .Case("headerfile", eSymbolTypeHeaderFile)
815                .Case("objectfile", eSymbolTypeObjectFile)
816                .Case("commonblock", eSymbolTypeCommonBlock)
817                .Case("block", eSymbolTypeBlock)
818                .Case("local", eSymbolTypeLocal)
819                .Case("param", eSymbolTypeParam)
820                .Case("variable", eSymbolTypeVariable)
821                .Case("variableType", eSymbolTypeVariableType)
822                .Case("lineentry", eSymbolTypeLineEntry)
823                .Case("lineheader", eSymbolTypeLineHeader)
824                .Case("scopebegin", eSymbolTypeScopeBegin)
825                .Case("scopeend", eSymbolTypeScopeEnd)
826                .Case("additional,", eSymbolTypeAdditional)
827                .Case("compiler", eSymbolTypeCompiler)
828                .Case("instrumentation", eSymbolTypeInstrumentation)
829                .Case("undefined", eSymbolTypeUndefined)
830                .Case("objcclass", eSymbolTypeObjCClass)
831                .Case("objcmetaClass", eSymbolTypeObjCMetaClass)
832                .Case("objcivar", eSymbolTypeObjCIVar)
833                .Case("reexporte", eSymbolTypeReExported)
834                .Default(eSymbolTypeInvalid);
835 
836     if (type == eSymbolTypeInvalid) {
837       path.report("invalid symbol type");
838       return false;
839     }
840 
841     return true;
842   }
843   path.report("expected string");
844   return false;
845 }
846 } // namespace json
847 } // namespace llvm
848