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 §ion_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::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
Clear()150 void 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
ValueIsAddress() const169 bool Symbol::ValueIsAddress() const {
170 return (bool)m_addr_range.GetBaseAddress().GetSection();
171 }
172
GetDisplayName() const173 ConstString Symbol::GetDisplayName() const {
174 return GetMangled().GetDisplayDemangledName();
175 }
176
GetReExportedSymbolName() const177 ConstString 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
GetReExportedSymbolSharedLibrary() const191 FileSpec 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
SetReExportedSymbolName(ConstString name)203 void 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
SetReExportedSymbolSharedLibrary(const FileSpec & fspec)210 bool 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
GetSiblingIndex() const221 uint32_t Symbol::GetSiblingIndex() const {
222 return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;
223 }
224
IsTrampoline() const225 bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
226
IsIndirect() const227 bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
228
GetDescription(Stream * s,lldb::DescriptionLevel level,Target * target,std::optional<Stream::HighlightSettings> settings) const229 void 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
Dump(Stream * s,Target * target,uint32_t index,Mangled::NamePreference name_preference) const270 void 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
GetPrologueByteSize()317 uint32_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
Compare(ConstString name,SymbolType type) const390 bool 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
GetTypeAsString() const403 const 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
CalculateSymbolContext(SymbolContext * sc)440 void 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
CalculateSymbolContextModule()449 ModuleSP Symbol::CalculateSymbolContextModule() {
450 if (ValueIsAddress())
451 return GetAddressRef().GetModule();
452 return ModuleSP();
453 }
454
CalculateSymbolContextSymbol()455 Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }
456
DumpSymbolContext(Stream * s)457 void 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
GetByteSize() const472 lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }
473
ResolveReExportedSymbolInModuleSpec(Target & target,ConstString & reexport_name,ModuleSpec & module_spec,ModuleList & seen_modules) const474 Symbol *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
ResolveReExportedSymbol(Target & target) const524 Symbol *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
GetFileAddress() const538 lldb::addr_t Symbol::GetFileAddress() const {
539 if (ValueIsAddress())
540 return GetAddressRef().GetFileAddress();
541 else
542 return LLDB_INVALID_ADDRESS;
543 }
544
GetLoadAddress(Target * target) const545 lldb::addr_t Symbol::GetLoadAddress(Target *target) const {
546 if (ValueIsAddress())
547 return GetAddressRef().GetLoadAddress(target);
548 else
549 return LLDB_INVALID_ADDRESS;
550 }
551
GetName() const552 ConstString Symbol::GetName() const { return GetMangled().GetName(); }
553
GetNameNoArguments() const554 ConstString Symbol::GetNameNoArguments() const {
555 return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments);
556 }
557
ResolveCallableAddress(Target & target) const558 lldb::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
GetInstructions(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache)593 lldb::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
GetDisassembly(const ExecutionContext & exe_ctx,const char * flavor,bool prefer_file_cache,Stream & strm)605 bool 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
ContainsFileAddress(lldb::addr_t file_addr) const620 bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {
621 return m_addr_range.ContainsFileAddress(file_addr);
622 }
623
IsSyntheticWithAutoGeneratedName() const624 bool 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
SynthesizeNameIfNeeded() const633 void 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
Decode(const DataExtractor & data,lldb::offset_t * offset_ptr,const SectionList * section_list,const StringTableReader & strtab)651 bool 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.
Encode(DataEncoder & file,ConstStringTable & strtab) const704 void 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
operator ==(const Symbol & rhs) const741 bool 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
779 namespace llvm {
780 namespace json {
781
fromJSON(const llvm::json::Value & value,lldb_private::JSONSymbol & symbol,llvm::json::Path path)782 bool 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
fromJSON(const llvm::json::Value & value,lldb::SymbolType & type,llvm::json::Path path)806 bool 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