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::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