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::createStringError(Fmt: "no section list provided");
105
106 if (!symbol.value && !symbol.address)
107 return llvm::createStringError(
108 Fmt: "symbol must contain either a value or an address");
109
110 if (symbol.value && symbol.address)
111 return llvm::createStringError(
112 Fmt: "symbol cannot contain both a value and an address");
113
114 const uint64_t size = symbol.size.value_or(u: 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(addr: *symbol.address)) {
126 const uint64_t offset = *symbol.address - section_sp->GetFileAddress();
127 return Symbol(symbol.id.value_or(u: 0), Mangled(symbol.name),
128 symbol.type.value_or(u: 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 S: llvm::formatv(Fmt: "no section found for address: {0:x}", Vals: *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(u: 0), Mangled(symbol.name),
140 symbol.type.value_or(u: 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
146void 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
165bool Symbol::ValueIsAddress() const {
166 return (bool)m_addr_range.GetBaseAddress().GetSection();
167}
168
169ConstString Symbol::GetDisplayName() const {
170 return GetMangled().GetDisplayDemangledName();
171}
172
173ConstString 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
187FileSpec 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
199void 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
206bool 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
217uint32_t Symbol::GetSiblingIndex() const {
218 return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX;
219}
220
221bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
222
223bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
224
225void Symbol::GetDescription(
226 Stream *s, lldb::DescriptionLevel level, Target *target,
227 std::optional<Stream::HighlightSettings> settings) const {
228 s->Printf(format: "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(cstr: ", range = ");
235 m_addr_range.Dump(s, target, style: Address::DumpStyleLoadAddress,
236 fallback_style: Address::DumpStyleFileAddress);
237 } else {
238 s->PutCString(cstr: ", address = ");
239 m_addr_range.GetBaseAddress().Dump(s, exe_scope: target,
240 style: Address::DumpStyleLoadAddress,
241 fallback_style: Address::DumpStyleFileAddress);
242 }
243 } else
244 s->Printf(format: ", value = 0x%16.16" PRIx64,
245 m_addr_range.GetBaseAddress().GetOffset());
246 } else {
247 if (m_size_is_sibling)
248 s->Printf(format: ", sibling = %5" PRIu64,
249 m_addr_range.GetBaseAddress().GetOffset());
250 else
251 s->Printf(format: ", value = 0x%16.16" PRIx64,
252 m_addr_range.GetBaseAddress().GetOffset());
253 }
254 if (ConstString demangled = m_mangled.GetDemangledName()) {
255 s->PutCString(cstr: ", name=\"");
256 s->PutCStringColorHighlighted(text: demangled.GetStringRef(), settings);
257 s->PutCString(cstr: "\"");
258 }
259 if (ConstString mangled_name = m_mangled.GetMangledName()) {
260 s->PutCString(cstr: ", mangled=\"");
261 s->PutCStringColorHighlighted(text: mangled_name.GetStringRef(), settings);
262 s->PutCString(cstr: "\"");
263 }
264}
265
266void Symbol::Dump(Stream *s, Target *target, uint32_t index,
267 Mangled::NamePreference name_preference) const {
268 s->Printf(format: "[%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(preference: name_preference);
276 if (ValueIsAddress()) {
277 if (!m_addr_range.GetBaseAddress().Dump(s, exe_scope: nullptr,
278 style: Address::DumpStyleFileAddress))
279 s->Printf(format: "%*s", 18, "");
280
281 s->PutChar(ch: ' ');
282
283 if (!m_addr_range.GetBaseAddress().Dump(s, exe_scope: target,
284 style: Address::DumpStyleLoadAddress))
285 s->Printf(format: "%*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(value_if_empty: ""));
290 } else if (m_type == eSymbolTypeReExported) {
291 s->Printf(
292 format: " 0x%8.8x %s",
293 m_flags, name.AsCString(value_if_empty: ""));
294
295 ConstString reexport_name = GetReExportedSymbolName();
296 intptr_t shlib = m_addr_range.GetByteSize();
297 if (shlib)
298 s->Printf(format: " -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());
299 else
300 s->Printf(format: " -> %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(value_if_empty: ""));
310 }
311}
312
313uint32_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 so_addr: base_address, resolve_scope: 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(offset: 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 so_addr: addr, resolve_scope: eSymbolContextLineEntry, sc&: 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(offset: 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
386bool 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
399const 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
436void 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
445ModuleSP Symbol::CalculateSymbolContextModule() {
446 if (ValueIsAddress())
447 return GetAddressRef().GetModule();
448 return ModuleSP();
449}
450
451Symbol *Symbol::CalculateSymbolContextSymbol() { return this; }
452
453void 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(cstr: ", ");
464
465 s->Printf(format: "Symbol{0x%8.8x}", GetID());
466}
467
468lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); }
469
470Symbol *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(new_module: module_sp))
490 return nullptr;
491
492 lldb_private::SymbolContextList sc_list;
493 module_sp->FindSymbolsWithNameAndType(name: reexport_name, symbol_type: 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, module_spec&: reexported_module_spec, seen_modules);
513 if (result_symbol)
514 return result_symbol;
515 }
516 }
517 return nullptr;
518}
519
520Symbol *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
534lldb::addr_t Symbol::GetFileAddress() const {
535 if (ValueIsAddress())
536 return GetAddressRef().GetFileAddress();
537 else
538 return LLDB_INVALID_ADDRESS;
539}
540
541lldb::addr_t Symbol::GetLoadAddress(Target *target) const {
542 if (ValueIsAddress())
543 return GetAddressRef().GetLoadAddress(target);
544 else
545 return LLDB_INVALID_ADDRESS;
546}
547
548ConstString Symbol::GetName() const { return GetMangled().GetName(); }
549
550ConstString Symbol::GetNameNoArguments() const {
551 return GetMangled().GetName(preference: Mangled::ePreferDemangledWithoutArguments);
552}
553
554lldb::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: &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
589lldb::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(
595 arch: module_sp->GetArchitecture(), plugin_name: nullptr, flavor, cpu: nullptr, features: nullptr,
596 target&: exe_ctx.GetTargetRef(), disasm_ranges: m_addr_range, force_live_memory: !prefer_file_cache);
597 }
598 return lldb::DisassemblerSP();
599}
600
601bool 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 s: &strm, show_address, show_bytes, show_control_flow_kind, exe_ctx: &exe_ctx);
611 return true;
612 }
613 return false;
614}
615
616bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {
617 return m_addr_range.ContainsFileAddress(file_addr);
618}
619
620bool 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(Prefix: GetSyntheticSymbolPrefix());
627}
628
629void 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()
643 << llvm::format_hex_no_prefix(
644 N: m_addr_range.GetBaseAddress().GetFileAddress(), Width: 0);
645 m_mangled.SetDemangledName(ConstString(os.str()));
646 }
647}
648
649bool Symbol::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
650 const SectionList *section_list,
651 const StringTableReader &strtab) {
652 if (!data.ValidOffsetForDataOfSize(offset: *offset_ptr, length: 8))
653 return false;
654 m_uid = data.GetU32(offset_ptr);
655 m_type_data = data.GetU16(offset_ptr);
656 const uint16_t bitfields = data.GetU16(offset_ptr);
657 m_type_data_resolved = (1u << 15 & bitfields) != 0;
658 m_is_synthetic = (1u << 14 & bitfields) != 0;
659 m_is_debug = (1u << 13 & bitfields) != 0;
660 m_is_external = (1u << 12 & bitfields) != 0;
661 m_size_is_sibling = (1u << 11 & bitfields) != 0;
662 m_size_is_synthesized = (1u << 10 & bitfields) != 0;
663 m_size_is_valid = (1u << 9 & bitfields) != 0;
664 m_demangled_is_synthesized = (1u << 8 & bitfields) != 0;
665 m_contains_linker_annotations = (1u << 7 & bitfields) != 0;
666 m_is_weak = (1u << 6 & bitfields) != 0;
667 m_type = bitfields & 0x003f;
668 if (!m_mangled.Decode(data, offset_ptr, strtab))
669 return false;
670 if (!data.ValidOffsetForDataOfSize(offset: *offset_ptr, length: 20))
671 return false;
672 const bool is_addr = data.GetU8(offset_ptr) != 0;
673 const uint64_t value = data.GetU64(offset_ptr);
674 if (is_addr) {
675 m_addr_range.GetBaseAddress().ResolveAddressUsingFileSections(addr: value,
676 sections: section_list);
677 } else {
678 m_addr_range.GetBaseAddress().Clear();
679 m_addr_range.GetBaseAddress().SetOffset(value);
680 }
681 m_addr_range.SetByteSize(data.GetU64(offset_ptr));
682 m_flags = data.GetU32(offset_ptr);
683 return true;
684}
685
686/// The encoding format for the symbol is as follows:
687///
688/// uint32_t m_uid;
689/// uint16_t m_type_data;
690/// uint16_t bitfield_data;
691/// Mangled mangled;
692/// uint8_t is_addr;
693/// uint64_t file_addr_or_value;
694/// uint64_t size;
695/// uint32_t flags;
696///
697/// The only tricky thing in this encoding is encoding all of the bits in the
698/// bitfields. We use a trick to store all bitfields as a 16 bit value and we
699/// do the same thing when decoding the symbol. There are test that ensure this
700/// encoding works for each individual bit. Everything else is very easy to
701/// store.
702void Symbol::Encode(DataEncoder &file, ConstStringTable &strtab) const {
703 file.AppendU32(value: m_uid);
704 file.AppendU16(value: m_type_data);
705 uint16_t bitfields = m_type;
706 if (m_type_data_resolved)
707 bitfields |= 1u << 15;
708 if (m_is_synthetic)
709 bitfields |= 1u << 14;
710 if (m_is_debug)
711 bitfields |= 1u << 13;
712 if (m_is_external)
713 bitfields |= 1u << 12;
714 if (m_size_is_sibling)
715 bitfields |= 1u << 11;
716 if (m_size_is_synthesized)
717 bitfields |= 1u << 10;
718 if (m_size_is_valid)
719 bitfields |= 1u << 9;
720 if (m_demangled_is_synthesized)
721 bitfields |= 1u << 8;
722 if (m_contains_linker_annotations)
723 bitfields |= 1u << 7;
724 if (m_is_weak)
725 bitfields |= 1u << 6;
726 file.AppendU16(value: bitfields);
727 m_mangled.Encode(encoder&: file, strtab);
728 // A symbol's value might be an address, or it might be a constant. If the
729 // symbol's base address doesn't have a section, then it is a constant value.
730 // If it does have a section, we will encode the file address and re-resolve
731 // the address when we decode it.
732 bool is_addr = m_addr_range.GetBaseAddress().GetSection().get() != nullptr;
733 file.AppendU8(value: is_addr);
734 file.AppendU64(value: m_addr_range.GetBaseAddress().GetFileAddress());
735 file.AppendU64(value: m_addr_range.GetByteSize());
736 file.AppendU32(value: m_flags);
737}
738
739bool Symbol::operator==(const Symbol &rhs) const {
740 if (m_uid != rhs.m_uid)
741 return false;
742 if (m_type_data != rhs.m_type_data)
743 return false;
744 if (m_type_data_resolved != rhs.m_type_data_resolved)
745 return false;
746 if (m_is_synthetic != rhs.m_is_synthetic)
747 return false;
748 if (m_is_debug != rhs.m_is_debug)
749 return false;
750 if (m_is_external != rhs.m_is_external)
751 return false;
752 if (m_size_is_sibling != rhs.m_size_is_sibling)
753 return false;
754 if (m_size_is_synthesized != rhs.m_size_is_synthesized)
755 return false;
756 if (m_size_is_valid != rhs.m_size_is_valid)
757 return false;
758 if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)
759 return false;
760 if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)
761 return false;
762 if (m_is_weak != rhs.m_is_weak)
763 return false;
764 if (m_type != rhs.m_type)
765 return false;
766 if (m_mangled != rhs.m_mangled)
767 return false;
768 if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())
769 return false;
770 if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())
771 return false;
772 if (m_flags != rhs.m_flags)
773 return false;
774 return true;
775}
776
777namespace llvm {
778namespace json {
779
780bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,
781 llvm::json::Path path) {
782 llvm::json::ObjectMapper o(value, path);
783 const bool mapped = o && o.map(Prop: "value", Out&: symbol.value) &&
784 o.map(Prop: "address", Out&: symbol.address) &&
785 o.map(Prop: "size", Out&: symbol.size) && o.map(Prop: "id", Out&: symbol.id) &&
786 o.map(Prop: "type", Out&: symbol.type) && o.map(Prop: "name", Out&: symbol.name);
787
788 if (!mapped)
789 return false;
790
791 if (!symbol.value && !symbol.address) {
792 path.report(Message: "symbol must have either a value or an address");
793 return false;
794 }
795
796 if (symbol.value && symbol.address) {
797 path.report(Message: "symbol cannot have both a value and an address");
798 return false;
799 }
800
801 return true;
802}
803
804bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,
805 llvm::json::Path path) {
806 if (auto str = value.getAsString()) {
807 type = llvm::StringSwitch<lldb::SymbolType>(*str)
808 .Case(S: "absolute", Value: eSymbolTypeAbsolute)
809 .Case(S: "code", Value: eSymbolTypeCode)
810 .Case(S: "resolver", Value: eSymbolTypeResolver)
811 .Case(S: "data", Value: eSymbolTypeData)
812 .Case(S: "trampoline", Value: eSymbolTypeTrampoline)
813 .Case(S: "runtime", Value: eSymbolTypeRuntime)
814 .Case(S: "exception", Value: eSymbolTypeException)
815 .Case(S: "sourcefile", Value: eSymbolTypeSourceFile)
816 .Case(S: "headerfile", Value: eSymbolTypeHeaderFile)
817 .Case(S: "objectfile", Value: eSymbolTypeObjectFile)
818 .Case(S: "commonblock", Value: eSymbolTypeCommonBlock)
819 .Case(S: "block", Value: eSymbolTypeBlock)
820 .Case(S: "local", Value: eSymbolTypeLocal)
821 .Case(S: "param", Value: eSymbolTypeParam)
822 .Case(S: "variable", Value: eSymbolTypeVariable)
823 .Case(S: "variableType", Value: eSymbolTypeVariableType)
824 .Case(S: "lineentry", Value: eSymbolTypeLineEntry)
825 .Case(S: "lineheader", Value: eSymbolTypeLineHeader)
826 .Case(S: "scopebegin", Value: eSymbolTypeScopeBegin)
827 .Case(S: "scopeend", Value: eSymbolTypeScopeEnd)
828 .Case(S: "additional,", Value: eSymbolTypeAdditional)
829 .Case(S: "compiler", Value: eSymbolTypeCompiler)
830 .Case(S: "instrumentation", Value: eSymbolTypeInstrumentation)
831 .Case(S: "undefined", Value: eSymbolTypeUndefined)
832 .Case(S: "objcclass", Value: eSymbolTypeObjCClass)
833 .Case(S: "objcmetaClass", Value: eSymbolTypeObjCMetaClass)
834 .Case(S: "objcivar", Value: eSymbolTypeObjCIVar)
835 .Case(S: "reexporte", Value: eSymbolTypeReExported)
836 .Default(Value: eSymbolTypeInvalid);
837
838 if (type == eSymbolTypeInvalid) {
839 path.report(Message: "invalid symbol type");
840 return false;
841 }
842
843 return true;
844 }
845 path.report(Message: "expected string");
846 return false;
847}
848} // namespace json
849} // namespace llvm
850

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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