1//===-- Symbol.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Symbol/Symbol.h"
10
11#include "lldb/Core/Address.h"
12#include "lldb/Core/Debugger.h"
13#include "lldb/Core/Module.h"
14#include "lldb/Core/ModuleSpec.h"
15#include "lldb/Core/Section.h"
16#include "lldb/Symbol/Function.h"
17#include "lldb/Symbol/ObjectFile.h"
18#include "lldb/Symbol/SymbolVendor.h"
19#include "lldb/Symbol/Symtab.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Utility/DataEncoder.h"
23#include "lldb/Utility/Stream.h"
24#include "llvm/ADT/StringSwitch.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29Symbol::Symbol()
30 : SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false),
31 m_is_debug(false), m_is_external(false), m_size_is_sibling(false),
32 m_size_is_synthesized(false), m_size_is_valid(false),
33 m_demangled_is_synthesized(false), m_contains_linker_annotations(false),
34 m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(),
35 m_addr_range() {}
36
37Symbol::Symbol(uint32_t symID, llvm::StringRef name, SymbolType type,
38 bool external, bool is_debug, bool is_trampoline,
39 bool is_artificial, const lldb::SectionSP &section_sp,
40 addr_t offset, addr_t size, bool size_is_valid,
41 bool contains_linker_annotations, uint32_t flags)
42 : SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),
43 m_is_synthetic(is_artificial), m_is_debug(is_debug),
44 m_is_external(external), m_size_is_sibling(false),
45 m_size_is_synthesized(false), m_size_is_valid(size_is_valid || size > 0),
46 m_demangled_is_synthesized(false),
47 m_contains_linker_annotations(contains_linker_annotations),
48 m_is_weak(false), m_type(type), m_mangled(name),
49 m_addr_range(section_sp, offset, size), m_flags(flags) {}
50
51Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type,
52 bool external, bool is_debug, bool is_trampoline,
53 bool is_artificial, const AddressRange &range,
54 bool size_is_valid, bool contains_linker_annotations,
55 uint32_t flags)
56 : SymbolContextScope(), m_uid(symID), m_type_data_resolved(false),
57 m_is_synthetic(is_artificial), m_is_debug(is_debug),
58 m_is_external(external), m_size_is_sibling(false),
59 m_size_is_synthesized(false),
60 m_size_is_valid(size_is_valid || range.GetByteSize() > 0),
61 m_demangled_is_synthesized(false),
62 m_contains_linker_annotations(contains_linker_annotations),
63 m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range),
64 m_flags(flags) {}
65
66Symbol::Symbol(const Symbol &rhs)
67 : SymbolContextScope(rhs), m_uid(rhs.m_uid), m_type_data(rhs.m_type_data),
68 m_type_data_resolved(rhs.m_type_data_resolved),
69 m_is_synthetic(rhs.m_is_synthetic), m_is_debug(rhs.m_is_debug),
70 m_is_external(rhs.m_is_external),
71 m_size_is_sibling(rhs.m_size_is_sibling), m_size_is_synthesized(false),
72 m_size_is_valid(rhs.m_size_is_valid),
73 m_demangled_is_synthesized(rhs.m_demangled_is_synthesized),
74 m_contains_linker_annotations(rhs.m_contains_linker_annotations),
75 m_is_weak(rhs.m_is_weak), m_type(rhs.m_type), m_mangled(rhs.m_mangled),
76 m_addr_range(rhs.m_addr_range), m_flags(rhs.m_flags) {}
77
78const Symbol &Symbol::operator=(const Symbol &rhs) {
79 if (this != &rhs) {
80 SymbolContextScope::operator=(rhs);
81 m_uid = rhs.m_uid;
82 m_type_data = rhs.m_type_data;
83 m_type_data_resolved = rhs.m_type_data_resolved;
84 m_is_synthetic = rhs.m_is_synthetic;
85 m_is_debug = rhs.m_is_debug;
86 m_is_external = rhs.m_is_external;
87 m_size_is_sibling = rhs.m_size_is_sibling;
88 m_size_is_synthesized = rhs.m_size_is_sibling;
89 m_size_is_valid = rhs.m_size_is_valid;
90 m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
91 m_contains_linker_annotations = rhs.m_contains_linker_annotations;
92 m_is_weak = rhs.m_is_weak;
93 m_type = rhs.m_type;
94 m_mangled = rhs.m_mangled;
95 m_addr_range = rhs.m_addr_range;
96 m_flags = rhs.m_flags;
97 }
98 return *this;
99}
100
101llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol,
102 SectionList *section_list) {
103 if (!section_list)
104 return llvm::make_error<llvm::StringError>(Args: "no section list provided",
105 Args: llvm::inconvertibleErrorCode());
106
107 if (!symbol.value && !symbol.address)
108 return llvm::make_error<llvm::StringError>(
109 Args: "symbol must contain either a value or an address",
110 Args: llvm::inconvertibleErrorCode());
111
112 if (symbol.value && symbol.address)
113 return llvm::make_error<llvm::StringError>(
114 Args: "symbol cannot contain both a value and an address",
115 Args: llvm::inconvertibleErrorCode());
116
117 const uint64_t size = symbol.size.value_or(u: 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(addr: *symbol.address)) {
129 const uint64_t offset = *symbol.address - section_sp->GetFileAddress();
130 return Symbol(symbol.id.value_or(u: 0), Mangled(symbol.name),
131 symbol.type.value_or(u: 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 Args: llvm::formatv(Fmt: "no section found for address: {0:x}", Vals: *symbol.address),
138 Args: 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(u: 0), Mangled(symbol.name),
144 symbol.type.value_or(u: eSymbolTypeAny), external, is_debug,
145 is_trampoline, is_artificial,
146 AddressRange(SectionSP(), *symbol.value, size), size_is_valid,
147 contains_linker_annotations, flags);
148}
149
150void Symbol::Clear() {
151 m_uid = UINT32_MAX;
152 m_mangled.Clear();
153 m_type_data = 0;
154 m_type_data_resolved = false;
155 m_is_synthetic = false;
156 m_is_debug = false;
157 m_is_external = false;
158 m_size_is_sibling = false;
159 m_size_is_synthesized = false;
160 m_size_is_valid = false;
161 m_demangled_is_synthesized = false;
162 m_contains_linker_annotations = false;
163 m_is_weak = false;
164 m_type = eSymbolTypeInvalid;
165 m_flags = 0;
166 m_addr_range.Clear();
167}
168
169bool Symbol::ValueIsAddress() const {
170 return (bool)m_addr_range.GetBaseAddress().GetSection();
171}
172
173ConstString Symbol::GetDisplayName() const {
174 return GetMangled().GetDisplayDemangledName();
175}
176
177ConstString Symbol::GetReExportedSymbolName() const {
178 if (m_type == eSymbolTypeReExported) {
179 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
180 // as the offset in the address range base address. We can then make this
181 // back into a string that is the re-exported name.
182 intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset();
183 if (str_ptr != 0)
184 return ConstString((const char *)str_ptr);
185 else
186 return GetName();
187 }
188 return ConstString();
189}
190
191FileSpec Symbol::GetReExportedSymbolSharedLibrary() const {
192 if (m_type == eSymbolTypeReExported) {
193 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
194 // as the offset in the address range base address. We can then make this
195 // back into a string that is the re-exported name.
196 intptr_t str_ptr = m_addr_range.GetByteSize();
197 if (str_ptr != 0)
198 return FileSpec((const char *)str_ptr);
199 }
200 return FileSpec();
201}
202
203void Symbol::SetReExportedSymbolName(ConstString name) {
204 SetType(eSymbolTypeReExported);
205 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
206 // as the offset in the address range base address.
207 m_addr_range.GetBaseAddress().SetOffset((uintptr_t)name.GetCString());
208}
209
210bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) {
211 if (m_type == eSymbolTypeReExported) {
212 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
213 // as the offset in the address range base address.
214 m_addr_range.SetByteSize(
215 (uintptr_t)ConstString(fspec.GetPath().c_str()).GetCString());
216 return true;
217 }
218 return false;
219}
220
221uint32_t Symbol::GetSiblingIndex() const {
222 return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;
223}
224
225bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
226
227bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
228
229void Symbol::GetDescription(
230 Stream *s, lldb::DescriptionLevel level, Target *target,
231 std::optional<Stream::HighlightSettings> settings) const {
232 s->Printf(format: "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(cstr: ", range = ");
239 m_addr_range.Dump(s, target, style: Address::DumpStyleLoadAddress,
240 fallback_style: Address::DumpStyleFileAddress);
241 } else {
242 s->PutCString(cstr: ", address = ");
243 m_addr_range.GetBaseAddress().Dump(s, exe_scope: target,
244 style: Address::DumpStyleLoadAddress,
245 fallback_style: Address::DumpStyleFileAddress);
246 }
247 } else
248 s->Printf(format: ", value = 0x%16.16" PRIx64,
249 m_addr_range.GetBaseAddress().GetOffset());
250 } else {
251 if (m_size_is_sibling)
252 s->Printf(format: ", sibling = %5" PRIu64,
253 m_addr_range.GetBaseAddress().GetOffset());
254 else
255 s->Printf(format: ", value = 0x%16.16" PRIx64,
256 m_addr_range.GetBaseAddress().GetOffset());
257 }
258 if (ConstString demangled = m_mangled.GetDemangledName()) {
259 s->PutCString(cstr: ", name=\"");
260 s->PutCStringColorHighlighted(text: demangled.GetStringRef(), settings);
261 s->PutCString(cstr: "\"");
262 }
263 if (ConstString mangled_name = m_mangled.GetMangledName()) {
264 s->PutCString(cstr: ", mangled=\"");
265 s->PutCStringColorHighlighted(text: mangled_name.GetStringRef(), settings);
266 s->PutCString(cstr: "\"");
267 }
268}
269
270void Symbol::Dump(Stream *s, Target *target, uint32_t index,
271 Mangled::NamePreference name_preference) const {
272 s->Printf(format: "[%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(preference: name_preference);
280 if (ValueIsAddress()) {
281 if (!m_addr_range.GetBaseAddress().Dump(s, exe_scope: nullptr,
282 style: Address::DumpStyleFileAddress))
283 s->Printf(format: "%*s", 18, "");
284
285 s->PutChar(ch: ' ');
286
287 if (!m_addr_range.GetBaseAddress().Dump(s, exe_scope: target,
288 style: Address::DumpStyleLoadAddress))
289 s->Printf(format: "%*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(value_if_empty: ""));
294 } else if (m_type == eSymbolTypeReExported) {
295 s->Printf(
296 format: " 0x%8.8x %s",
297 m_flags, name.AsCString(value_if_empty: ""));
298
299 ConstString reexport_name = GetReExportedSymbolName();
300 intptr_t shlib = m_addr_range.GetByteSize();
301 if (shlib)
302 s->Printf(format: " -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());
303 else
304 s->Printf(format: " -> %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(value_if_empty: ""));
314 }
315}
316
317uint32_t Symbol::GetPrologueByteSize() {
318 if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) {
319 if (!m_type_data_resolved) {
320 m_type_data_resolved = true;
321
322 const Address &base_address = m_addr_range.GetBaseAddress();
323 Function *function = base_address.CalculateSymbolContextFunction();
324 if (function) {
325 // Functions have line entries which can also potentially have end of
326 // prologue information. So if this symbol points to a function, use
327 // the prologue information from there.
328 m_type_data = function->GetPrologueByteSize();
329 } else {
330 ModuleSP module_sp(base_address.GetModule());
331 SymbolContext sc;
332 if (module_sp) {
333 uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress(
334 so_addr: base_address, resolve_scope: 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(offset: 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 so_addr: addr, resolve_scope: eSymbolContextLineEntry, sc&: 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(offset: sc_temp.line_entry.range.GetByteSize());
364 total_offset += sc_temp.line_entry.range.GetByteSize();
365 // If we've gone too far, bail out.
366 if (total_offset >= m_addr_range.GetByteSize())
367 break;
368 }
369
370 // Sanity check - this may be a function in the middle of code that
371 // has debug information, but not for this symbol. So the line
372 // entries surrounding us won't lie inside our function. In that
373 // case, the line entry will be bigger than we are, so we do that
374 // quick check and if that is true, we just return 0.
375 if (m_type_data >= m_addr_range.GetByteSize())
376 m_type_data = 0;
377 } else {
378 // TODO: expose something in Process to figure out the
379 // size of a function prologue.
380 m_type_data = 0;
381 }
382 }
383 }
384 }
385 return m_type_data;
386 }
387 return 0;
388}
389
390bool Symbol::Compare(ConstString name, SymbolType type) const {
391 if (type == eSymbolTypeAny || m_type == type) {
392 const Mangled &mangled = GetMangled();
393 return mangled.GetMangledName() == name ||
394 mangled.GetDemangledName() == name;
395 }
396 return false;
397}
398
399#define ENUM_TO_CSTRING(x) \
400 case eSymbolType##x: \
401 return #x;
402
403const char *Symbol::GetTypeAsString() const {
404 switch (m_type) {
405 ENUM_TO_CSTRING(Invalid);
406 ENUM_TO_CSTRING(Absolute);
407 ENUM_TO_CSTRING(Code);
408 ENUM_TO_CSTRING(Resolver);
409 ENUM_TO_CSTRING(Data);
410 ENUM_TO_CSTRING(Trampoline);
411 ENUM_TO_CSTRING(Runtime);
412 ENUM_TO_CSTRING(Exception);
413 ENUM_TO_CSTRING(SourceFile);
414 ENUM_TO_CSTRING(HeaderFile);
415 ENUM_TO_CSTRING(ObjectFile);
416 ENUM_TO_CSTRING(CommonBlock);
417 ENUM_TO_CSTRING(Block);
418 ENUM_TO_CSTRING(Local);
419 ENUM_TO_CSTRING(Param);
420 ENUM_TO_CSTRING(Variable);
421 ENUM_TO_CSTRING(VariableType);
422 ENUM_TO_CSTRING(LineEntry);
423 ENUM_TO_CSTRING(LineHeader);
424 ENUM_TO_CSTRING(ScopeBegin);
425 ENUM_TO_CSTRING(ScopeEnd);
426 ENUM_TO_CSTRING(Additional);
427 ENUM_TO_CSTRING(Compiler);
428 ENUM_TO_CSTRING(Instrumentation);
429 ENUM_TO_CSTRING(Undefined);
430 ENUM_TO_CSTRING(ObjCClass);
431 ENUM_TO_CSTRING(ObjCMetaClass);
432 ENUM_TO_CSTRING(ObjCIVar);
433 ENUM_TO_CSTRING(ReExported);
434 default:
435 break;
436 }
437 return "<unknown SymbolType>";
438}
439
440void Symbol::CalculateSymbolContext(SymbolContext *sc) {
441 // Symbols can reconstruct the symbol and the module in the symbol context
442 sc->symbol = this;
443 if (ValueIsAddress())
444 sc->module_sp = GetAddressRef().GetModule();
445 else
446 sc->module_sp.reset();
447}
448
449ModuleSP Symbol::CalculateSymbolContextModule() {
450 if (ValueIsAddress())
451 return GetAddressRef().GetModule();
452 return ModuleSP();
453}
454
455Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }
456
457void Symbol::DumpSymbolContext(Stream *s) {
458 bool dumped_module = false;
459 if (ValueIsAddress()) {
460 ModuleSP module_sp(GetAddressRef().GetModule());
461 if (module_sp) {
462 dumped_module = true;
463 module_sp->DumpSymbolContext(s);
464 }
465 }
466 if (dumped_module)
467 s->PutCString(cstr: ", ");
468
469 s->Printf(format: "Symbol{0x%8.8x}", GetID());
470}
471
472lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }
473
474Symbol *Symbol::ResolveReExportedSymbolInModuleSpec(
475 Target &target, ConstString &reexport_name, ModuleSpec &module_spec,
476 ModuleList &seen_modules) const {
477 ModuleSP module_sp;
478 if (module_spec.GetFileSpec()) {
479 // Try searching for the module file spec first using the full path
480 module_sp = target.GetImages().FindFirstModule(module_spec);
481 if (!module_sp) {
482 // Next try and find the module by basename in case environment variables
483 // or other runtime trickery causes shared libraries to be loaded from
484 // alternate paths
485 module_spec.GetFileSpec().ClearDirectory();
486 module_sp = target.GetImages().FindFirstModule(module_spec);
487 }
488 }
489
490 if (module_sp) {
491 // There should not be cycles in the reexport list, but we don't want to
492 // crash if there are so make sure we haven't seen this before:
493 if (!seen_modules.AppendIfNeeded(new_module: module_sp))
494 return nullptr;
495
496 lldb_private::SymbolContextList sc_list;
497 module_sp->FindSymbolsWithNameAndType(name: reexport_name, symbol_type: 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, module_spec&: reexported_module_spec, seen_modules);
517 if (result_symbol)
518 return result_symbol;
519 }
520 }
521 return nullptr;
522}
523
524Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {
525 ConstString reexport_name(GetReExportedSymbolName());
526 if (reexport_name) {
527 ModuleSpec module_spec;
528 ModuleList seen_modules;
529 module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary();
530 if (module_spec.GetFileSpec()) {
531 return ResolveReExportedSymbolInModuleSpec(target, reexport_name,
532 module_spec, seen_modules);
533 }
534 }
535 return nullptr;
536}
537
538lldb::addr_t Symbol::GetFileAddress() const {
539 if (ValueIsAddress())
540 return GetAddressRef().GetFileAddress();
541 else
542 return LLDB_INVALID_ADDRESS;
543}
544
545lldb::addr_t Symbol::GetLoadAddress(Target *target) const {
546 if (ValueIsAddress())
547 return GetAddressRef().GetLoadAddress(target);
548 else
549 return LLDB_INVALID_ADDRESS;
550}
551
552ConstString Symbol::GetName() const { return GetMangled().GetName(); }
553
554ConstString Symbol::GetNameNoArguments() const {
555 return GetMangled().GetName(preference: Mangled::ePreferDemangledWithoutArguments);
556}
557
558lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const {
559 if (GetType() == lldb::eSymbolTypeUndefined)
560 return LLDB_INVALID_ADDRESS;
561
562 Address func_so_addr;
563
564 bool is_indirect = IsIndirect();
565 if (GetType() == eSymbolTypeReExported) {
566 Symbol *reexported_symbol = ResolveReExportedSymbol(target);
567 if (reexported_symbol) {
568 func_so_addr = reexported_symbol->GetAddress();
569 is_indirect = reexported_symbol->IsIndirect();
570 }
571 } else {
572 func_so_addr = GetAddress();
573 is_indirect = IsIndirect();
574 }
575
576 if (func_so_addr.IsValid()) {
577 if (!target.GetProcessSP() && is_indirect) {
578 // can't resolve indirect symbols without calling a function...
579 return LLDB_INVALID_ADDRESS;
580 }
581
582 lldb::addr_t load_addr =
583 func_so_addr.GetCallableLoadAddress(target: &target, is_indirect);
584
585 if (load_addr != LLDB_INVALID_ADDRESS) {
586 return load_addr;
587 }
588 }
589
590 return LLDB_INVALID_ADDRESS;
591}
592
593lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,
594 const char *flavor,
595 bool prefer_file_cache) {
596 ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule());
597 if (module_sp && exe_ctx.HasTargetScope()) {
598 return Disassembler::DisassembleRange(arch: module_sp->GetArchitecture(), plugin_name: nullptr,
599 flavor, target&: exe_ctx.GetTargetRef(),
600 disasm_range: m_addr_range, force_live_memory: !prefer_file_cache);
601 }
602 return lldb::DisassemblerSP();
603}
604
605bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor,
606 bool prefer_file_cache, Stream &strm) {
607 lldb::DisassemblerSP disassembler_sp =
608 GetInstructions(exe_ctx, flavor, prefer_file_cache);
609 if (disassembler_sp) {
610 const bool show_address = true;
611 const bool show_bytes = false;
612 const bool show_control_flow_kind = false;
613 disassembler_sp->GetInstructionList().Dump(
614 s: &strm, show_address, show_bytes, show_control_flow_kind, exe_ctx: &exe_ctx);
615 return true;
616 }
617 return false;
618}
619
620bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {
621 return m_addr_range.ContainsFileAddress(file_addr);
622}
623
624bool Symbol::IsSyntheticWithAutoGeneratedName() const {
625 if (!IsSynthetic())
626 return false;
627 if (!m_mangled)
628 return true;
629 ConstString demangled = m_mangled.GetDemangledName();
630 return demangled.GetStringRef().starts_with(Prefix: GetSyntheticSymbolPrefix());
631}
632
633void Symbol::SynthesizeNameIfNeeded() const {
634 if (m_is_synthetic && !m_mangled) {
635 // Synthetic symbol names don't mean anything, but they do uniquely
636 // identify individual symbols so we give them a unique name. The name
637 // starts with the synthetic symbol prefix, followed by a unique number.
638 // Typically the UserID of a real symbol is the symbol table index of the
639 // symbol in the object file's symbol table(s), so it will be the same
640 // every time you read in the object file. We want the same persistence for
641 // synthetic symbols so that users can identify them across multiple debug
642 // sessions, to understand crashes in those symbols and to reliably set
643 // breakpoints on them.
644 llvm::SmallString<256> name;
645 llvm::raw_svector_ostream os(name);
646 os << GetSyntheticSymbolPrefix() << GetID();
647 m_mangled.SetDemangledName(ConstString(os.str()));
648 }
649}
650
651bool Symbol::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
652 const SectionList *section_list,
653 const StringTableReader &strtab) {
654 if (!data.ValidOffsetForDataOfSize(offset: *offset_ptr, length: 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: *offset_ptr, length: 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(addr: value,
678 sections: section_list);
679 } else {
680 m_addr_range.GetBaseAddress().Clear();
681 m_addr_range.GetBaseAddress().SetOffset(value);
682 }
683 m_addr_range.SetByteSize(data.GetU64(offset_ptr));
684 m_flags = data.GetU32(offset_ptr);
685 return true;
686}
687
688/// The encoding format for the symbol is as follows:
689///
690/// uint32_t m_uid;
691/// uint16_t m_type_data;
692/// uint16_t bitfield_data;
693/// Mangled mangled;
694/// uint8_t is_addr;
695/// uint64_t file_addr_or_value;
696/// uint64_t size;
697/// uint32_t flags;
698///
699/// The only tricky thing in this encoding is encoding all of the bits in the
700/// bitfields. We use a trick to store all bitfields as a 16 bit value and we
701/// do the same thing when decoding the symbol. There are test that ensure this
702/// encoding works for each individual bit. Everything else is very easy to
703/// store.
704void Symbol::Encode(DataEncoder &file, ConstStringTable &strtab) const {
705 file.AppendU32(value: m_uid);
706 file.AppendU16(value: 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(value: bitfields);
729 m_mangled.Encode(encoder&: 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(value: is_addr);
736 file.AppendU64(value: m_addr_range.GetBaseAddress().GetFileAddress());
737 file.AppendU64(value: m_addr_range.GetByteSize());
738 file.AppendU32(value: m_flags);
739}
740
741bool Symbol::operator==(const Symbol &rhs) const {
742 if (m_uid != rhs.m_uid)
743 return false;
744 if (m_type_data != rhs.m_type_data)
745 return false;
746 if (m_type_data_resolved != rhs.m_type_data_resolved)
747 return false;
748 if (m_is_synthetic != rhs.m_is_synthetic)
749 return false;
750 if (m_is_debug != rhs.m_is_debug)
751 return false;
752 if (m_is_external != rhs.m_is_external)
753 return false;
754 if (m_size_is_sibling != rhs.m_size_is_sibling)
755 return false;
756 if (m_size_is_synthesized != rhs.m_size_is_synthesized)
757 return false;
758 if (m_size_is_valid != rhs.m_size_is_valid)
759 return false;
760 if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)
761 return false;
762 if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)
763 return false;
764 if (m_is_weak != rhs.m_is_weak)
765 return false;
766 if (m_type != rhs.m_type)
767 return false;
768 if (m_mangled != rhs.m_mangled)
769 return false;
770 if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())
771 return false;
772 if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())
773 return false;
774 if (m_flags != rhs.m_flags)
775 return false;
776 return true;
777}
778
779namespace llvm {
780namespace json {
781
782bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,
783 llvm::json::Path path) {
784 llvm::json::ObjectMapper o(value, path);
785 const bool mapped = o && o.map(Prop: "value", Out&: symbol.value) &&
786 o.map(Prop: "address", Out&: symbol.address) &&
787 o.map(Prop: "size", Out&: symbol.size) && o.map(Prop: "id", Out&: symbol.id) &&
788 o.map(Prop: "type", Out&: symbol.type) && o.map(Prop: "name", Out&: symbol.name);
789
790 if (!mapped)
791 return false;
792
793 if (!symbol.value && !symbol.address) {
794 path.report(Message: "symbol must have either a value or an address");
795 return false;
796 }
797
798 if (symbol.value && symbol.address) {
799 path.report(Message: "symbol cannot have both a value and an address");
800 return false;
801 }
802
803 return true;
804}
805
806bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,
807 llvm::json::Path path) {
808 if (auto str = value.getAsString()) {
809 type = llvm::StringSwitch<lldb::SymbolType>(*str)
810 .Case(S: "absolute", Value: eSymbolTypeAbsolute)
811 .Case(S: "code", Value: eSymbolTypeCode)
812 .Case(S: "resolver", Value: eSymbolTypeResolver)
813 .Case(S: "data", Value: eSymbolTypeData)
814 .Case(S: "trampoline", Value: eSymbolTypeTrampoline)
815 .Case(S: "runtime", Value: eSymbolTypeRuntime)
816 .Case(S: "exception", Value: eSymbolTypeException)
817 .Case(S: "sourcefile", Value: eSymbolTypeSourceFile)
818 .Case(S: "headerfile", Value: eSymbolTypeHeaderFile)
819 .Case(S: "objectfile", Value: eSymbolTypeObjectFile)
820 .Case(S: "commonblock", Value: eSymbolTypeCommonBlock)
821 .Case(S: "block", Value: eSymbolTypeBlock)
822 .Case(S: "local", Value: eSymbolTypeLocal)
823 .Case(S: "param", Value: eSymbolTypeParam)
824 .Case(S: "variable", Value: eSymbolTypeVariable)
825 .Case(S: "variableType", Value: eSymbolTypeVariableType)
826 .Case(S: "lineentry", Value: eSymbolTypeLineEntry)
827 .Case(S: "lineheader", Value: eSymbolTypeLineHeader)
828 .Case(S: "scopebegin", Value: eSymbolTypeScopeBegin)
829 .Case(S: "scopeend", Value: eSymbolTypeScopeEnd)
830 .Case(S: "additional,", Value: eSymbolTypeAdditional)
831 .Case(S: "compiler", Value: eSymbolTypeCompiler)
832 .Case(S: "instrumentation", Value: eSymbolTypeInstrumentation)
833 .Case(S: "undefined", Value: eSymbolTypeUndefined)
834 .Case(S: "objcclass", Value: eSymbolTypeObjCClass)
835 .Case(S: "objcmetaClass", Value: eSymbolTypeObjCMetaClass)
836 .Case(S: "objcivar", Value: eSymbolTypeObjCIVar)
837 .Case(S: "reexporte", Value: eSymbolTypeReExported)
838 .Default(Value: eSymbolTypeInvalid);
839
840 if (type == eSymbolTypeInvalid) {
841 path.report(Message: "invalid symbol type");
842 return false;
843 }
844
845 return true;
846 }
847 path.report(Message: "expected string");
848 return false;
849}
850} // namespace json
851} // namespace llvm
852

source code of lldb/source/Symbol/Symbol.cpp