1 //===-- Symbol.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/Symbol.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/ModuleSpec.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Symbol/Function.h"
15 #include "lldb/Symbol/ObjectFile.h"
16 #include "lldb/Symbol/SymbolVendor.h"
17 #include "lldb/Symbol/Symtab.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Utility/DataEncoder.h"
21 #include "lldb/Utility/Stream.h"
22 #include "llvm/ADT/StringSwitch.h"
25 using namespace lldb_private
;
28 : SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false),
29 m_is_debug(false), m_is_external(false), m_size_is_sibling(false),
30 m_size_is_synthesized(false), m_size_is_valid(false),
31 m_demangled_is_synthesized(false), m_contains_linker_annotations(false),
32 m_is_weak(false), m_type(eSymbolTypeInvalid
), m_mangled(),
35 Symbol::Symbol(uint32_t symID
, llvm::StringRef name
, SymbolType type
,
36 bool external
, bool is_debug
, bool is_trampoline
,
37 bool is_artificial
, const lldb::SectionSP
§ion_sp
,
38 addr_t offset
, addr_t size
, bool size_is_valid
,
39 bool contains_linker_annotations
, uint32_t flags
)
40 : SymbolContextScope(), m_uid(symID
), m_type_data_resolved(false),
41 m_is_synthetic(is_artificial
), m_is_debug(is_debug
),
42 m_is_external(external
), m_size_is_sibling(false),
43 m_size_is_synthesized(false), m_size_is_valid(size_is_valid
|| size
> 0),
44 m_demangled_is_synthesized(false),
45 m_contains_linker_annotations(contains_linker_annotations
),
46 m_is_weak(false), m_type(type
), m_mangled(name
),
47 m_addr_range(section_sp
, offset
, size
), m_flags(flags
) {}
49 Symbol::Symbol(uint32_t symID
, const Mangled
&mangled
, SymbolType type
,
50 bool external
, bool is_debug
, bool is_trampoline
,
51 bool is_artificial
, const AddressRange
&range
,
52 bool size_is_valid
, bool contains_linker_annotations
,
54 : SymbolContextScope(), m_uid(symID
), m_type_data_resolved(false),
55 m_is_synthetic(is_artificial
), m_is_debug(is_debug
),
56 m_is_external(external
), m_size_is_sibling(false),
57 m_size_is_synthesized(false),
58 m_size_is_valid(size_is_valid
|| range
.GetByteSize() > 0),
59 m_demangled_is_synthesized(false),
60 m_contains_linker_annotations(contains_linker_annotations
),
61 m_is_weak(false), m_type(type
), m_mangled(mangled
), m_addr_range(range
),
64 Symbol::Symbol(const Symbol
&rhs
)
65 : SymbolContextScope(rhs
), m_uid(rhs
.m_uid
), m_type_data(rhs
.m_type_data
),
66 m_type_data_resolved(rhs
.m_type_data_resolved
),
67 m_is_synthetic(rhs
.m_is_synthetic
), m_is_debug(rhs
.m_is_debug
),
68 m_is_external(rhs
.m_is_external
),
69 m_size_is_sibling(rhs
.m_size_is_sibling
), m_size_is_synthesized(false),
70 m_size_is_valid(rhs
.m_size_is_valid
),
71 m_demangled_is_synthesized(rhs
.m_demangled_is_synthesized
),
72 m_contains_linker_annotations(rhs
.m_contains_linker_annotations
),
73 m_is_weak(rhs
.m_is_weak
), m_type(rhs
.m_type
), m_mangled(rhs
.m_mangled
),
74 m_addr_range(rhs
.m_addr_range
), m_flags(rhs
.m_flags
) {}
76 const Symbol
&Symbol::operator=(const Symbol
&rhs
) {
78 SymbolContextScope::operator=(rhs
);
80 m_type_data
= rhs
.m_type_data
;
81 m_type_data_resolved
= rhs
.m_type_data_resolved
;
82 m_is_synthetic
= rhs
.m_is_synthetic
;
83 m_is_debug
= rhs
.m_is_debug
;
84 m_is_external
= rhs
.m_is_external
;
85 m_size_is_sibling
= rhs
.m_size_is_sibling
;
86 m_size_is_synthesized
= rhs
.m_size_is_sibling
;
87 m_size_is_valid
= rhs
.m_size_is_valid
;
88 m_demangled_is_synthesized
= rhs
.m_demangled_is_synthesized
;
89 m_contains_linker_annotations
= rhs
.m_contains_linker_annotations
;
90 m_is_weak
= rhs
.m_is_weak
;
92 m_mangled
= rhs
.m_mangled
;
93 m_addr_range
= rhs
.m_addr_range
;
94 m_flags
= rhs
.m_flags
;
99 llvm::Expected
<Symbol
> Symbol::FromJSON(const JSONSymbol
&symbol
,
100 SectionList
*section_list
) {
102 return llvm::make_error
<llvm::StringError
>("no section list provided",
103 llvm::inconvertibleErrorCode());
105 if (!symbol
.value
&& !symbol
.address
)
106 return llvm::make_error
<llvm::StringError
>(
107 "symbol must contain either a value or an address",
108 llvm::inconvertibleErrorCode());
110 if (symbol
.value
&& symbol
.address
)
111 return llvm::make_error
<llvm::StringError
>(
112 "symbol cannot contain both a value and an address",
113 llvm::inconvertibleErrorCode());
115 const uint64_t size
= symbol
.size
.value_or(0);
116 const bool is_artificial
= false;
117 const bool is_trampoline
= false;
118 const bool is_debug
= false;
119 const bool external
= false;
120 const bool size_is_valid
= symbol
.size
.has_value();
121 const bool contains_linker_annotations
= false;
122 const uint32_t flags
= 0;
124 if (symbol
.address
) {
125 if (SectionSP section_sp
=
126 section_list
->FindSectionContainingFileAddress(*symbol
.address
)) {
127 const uint64_t offset
= *symbol
.address
- section_sp
->GetFileAddress();
128 return Symbol(symbol
.id
.value_or(0), Mangled(symbol
.name
),
129 symbol
.type
.value_or(eSymbolTypeAny
), external
, is_debug
,
130 is_trampoline
, is_artificial
,
131 AddressRange(section_sp
, offset
, size
), size_is_valid
,
132 contains_linker_annotations
, flags
);
134 return llvm::make_error
<llvm::StringError
>(
135 llvm::formatv("no section found for address: {0:x}", *symbol
.address
),
136 llvm::inconvertibleErrorCode());
139 // Absolute symbols encode the integer value in the m_offset of the
140 // AddressRange object and the section is set to nothing.
141 return Symbol(symbol
.id
.value_or(0), Mangled(symbol
.name
),
142 symbol
.type
.value_or(eSymbolTypeAny
), external
, is_debug
,
143 is_trampoline
, is_artificial
,
144 AddressRange(SectionSP(), *symbol
.value
, size
), size_is_valid
,
145 contains_linker_annotations
, flags
);
148 void Symbol::Clear() {
152 m_type_data_resolved
= false;
153 m_is_synthetic
= false;
155 m_is_external
= false;
156 m_size_is_sibling
= false;
157 m_size_is_synthesized
= false;
158 m_size_is_valid
= false;
159 m_demangled_is_synthesized
= false;
160 m_contains_linker_annotations
= false;
162 m_type
= eSymbolTypeInvalid
;
164 m_addr_range
.Clear();
167 bool Symbol::ValueIsAddress() const {
168 return (bool)m_addr_range
.GetBaseAddress().GetSection();
171 ConstString
Symbol::GetDisplayName() const {
172 return GetMangled().GetDisplayDemangledName();
175 ConstString
Symbol::GetReExportedSymbolName() const {
176 if (m_type
== eSymbolTypeReExported
) {
177 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
178 // as the offset in the address range base address. We can then make this
179 // back into a string that is the re-exported name.
180 intptr_t str_ptr
= m_addr_range
.GetBaseAddress().GetOffset();
182 return ConstString((const char *)str_ptr
);
186 return ConstString();
189 FileSpec
Symbol::GetReExportedSymbolSharedLibrary() const {
190 if (m_type
== eSymbolTypeReExported
) {
191 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
192 // as the offset in the address range base address. We can then make this
193 // back into a string that is the re-exported name.
194 intptr_t str_ptr
= m_addr_range
.GetByteSize();
196 return FileSpec((const char *)str_ptr
);
201 void Symbol::SetReExportedSymbolName(ConstString name
) {
202 SetType(eSymbolTypeReExported
);
203 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
204 // as the offset in the address range base address.
205 m_addr_range
.GetBaseAddress().SetOffset((uintptr_t)name
.GetCString());
208 bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec
&fspec
) {
209 if (m_type
== eSymbolTypeReExported
) {
210 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
211 // as the offset in the address range base address.
212 m_addr_range
.SetByteSize(
213 (uintptr_t)ConstString(fspec
.GetPath().c_str()).GetCString());
219 uint32_t Symbol::GetSiblingIndex() const {
220 return m_size_is_sibling
? m_addr_range
.GetByteSize() : UINT32_MAX
;
223 bool Symbol::IsTrampoline() const { return m_type
== eSymbolTypeTrampoline
; }
225 bool Symbol::IsIndirect() const { return m_type
== eSymbolTypeResolver
; }
227 void Symbol::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
228 Target
*target
) const {
229 s
->Printf("id = {0x%8.8x}", m_uid
);
231 if (m_addr_range
.GetBaseAddress().GetSection()) {
232 if (ValueIsAddress()) {
233 const lldb::addr_t byte_size
= GetByteSize();
235 s
->PutCString(", range = ");
236 m_addr_range
.Dump(s
, target
, Address::DumpStyleLoadAddress
,
237 Address::DumpStyleFileAddress
);
239 s
->PutCString(", address = ");
240 m_addr_range
.GetBaseAddress().Dump(s
, target
,
241 Address::DumpStyleLoadAddress
,
242 Address::DumpStyleFileAddress
);
245 s
->Printf(", value = 0x%16.16" PRIx64
,
246 m_addr_range
.GetBaseAddress().GetOffset());
248 if (m_size_is_sibling
)
249 s
->Printf(", sibling = %5" PRIu64
,
250 m_addr_range
.GetBaseAddress().GetOffset());
252 s
->Printf(", value = 0x%16.16" PRIx64
,
253 m_addr_range
.GetBaseAddress().GetOffset());
255 ConstString demangled
= GetMangled().GetDemangledName();
257 s
->Printf(", name=\"%s\"", demangled
.AsCString());
258 if (m_mangled
.GetMangledName())
259 s
->Printf(", mangled=\"%s\"", m_mangled
.GetMangledName().AsCString());
262 void Symbol::Dump(Stream
*s
, Target
*target
, uint32_t index
,
263 Mangled::NamePreference name_preference
) const {
264 s
->Printf("[%5u] %6u %c%c%c %-15s ", index
, GetID(), m_is_debug
? 'D' : ' ',
265 m_is_synthetic
? 'S' : ' ', m_is_external
? 'X' : ' ',
268 // Make sure the size of the symbol is up to date before dumping
271 ConstString name
= GetMangled().GetName(name_preference
);
272 if (ValueIsAddress()) {
273 if (!m_addr_range
.GetBaseAddress().Dump(s
, nullptr,
274 Address::DumpStyleFileAddress
))
275 s
->Printf("%*s", 18, "");
279 if (!m_addr_range
.GetBaseAddress().Dump(s
, target
,
280 Address::DumpStyleLoadAddress
))
281 s
->Printf("%*s", 18, "");
283 const char *format
= m_size_is_sibling
? " Sibling -> [%5llu] 0x%8.8x %s\n"
284 : " 0x%16.16" PRIx64
" 0x%8.8x %s\n";
285 s
->Printf(format
, GetByteSize(), m_flags
, name
.AsCString(""));
286 } else if (m_type
== eSymbolTypeReExported
) {
289 m_flags
, name
.AsCString(""));
291 ConstString reexport_name
= GetReExportedSymbolName();
292 intptr_t shlib
= m_addr_range
.GetByteSize();
294 s
->Printf(" -> %s`%s\n", (const char *)shlib
, reexport_name
.GetCString());
296 s
->Printf(" -> %s\n", reexport_name
.GetCString());
301 " Sibling -> [%5llu] 0x%8.8x %s\n"
302 : "0x%16.16" PRIx64
" 0x%16.16" PRIx64
304 s
->Printf(format
, m_addr_range
.GetBaseAddress().GetOffset(), GetByteSize(),
305 m_flags
, name
.AsCString(""));
309 uint32_t Symbol::GetPrologueByteSize() {
310 if (m_type
== eSymbolTypeCode
|| m_type
== eSymbolTypeResolver
) {
311 if (!m_type_data_resolved
) {
312 m_type_data_resolved
= true;
314 const Address
&base_address
= m_addr_range
.GetBaseAddress();
315 Function
*function
= base_address
.CalculateSymbolContextFunction();
317 // Functions have line entries which can also potentially have end of
318 // prologue information. So if this symbol points to a function, use
319 // the prologue information from there.
320 m_type_data
= function
->GetPrologueByteSize();
322 ModuleSP
module_sp(base_address
.GetModule());
325 uint32_t resolved_flags
= module_sp
->ResolveSymbolContextForAddress(
326 base_address
, eSymbolContextLineEntry
, sc
);
327 if (resolved_flags
& eSymbolContextLineEntry
) {
328 // Default to the end of the first line entry.
329 m_type_data
= sc
.line_entry
.range
.GetByteSize();
331 // Set address for next line.
332 Address
addr(base_address
);
333 addr
.Slide(m_type_data
);
335 // Check the first few instructions and look for one that has a
336 // line number that is different than the first entry. This is also
337 // done in Function::GetPrologueByteSize().
338 uint16_t total_offset
= m_type_data
;
339 for (int idx
= 0; idx
< 6; ++idx
) {
340 SymbolContext sc_temp
;
341 resolved_flags
= module_sp
->ResolveSymbolContextForAddress(
342 addr
, eSymbolContextLineEntry
, sc_temp
);
343 // Make sure we got line number information...
344 if (!(resolved_flags
& eSymbolContextLineEntry
))
347 // If this line number is different than our first one, use it
349 if (sc_temp
.line_entry
.line
!= sc
.line_entry
.line
) {
350 m_type_data
= total_offset
;
354 // Slide addr up to the next line address.
355 addr
.Slide(sc_temp
.line_entry
.range
.GetByteSize());
356 total_offset
+= sc_temp
.line_entry
.range
.GetByteSize();
357 // If we've gone too far, bail out.
358 if (total_offset
>= m_addr_range
.GetByteSize())
362 // Sanity check - this may be a function in the middle of code that
363 // has debug information, but not for this symbol. So the line
364 // entries surrounding us won't lie inside our function. In that
365 // case, the line entry will be bigger than we are, so we do that
366 // quick check and if that is true, we just return 0.
367 if (m_type_data
>= m_addr_range
.GetByteSize())
370 // TODO: expose something in Process to figure out the
371 // size of a function prologue.
382 bool Symbol::Compare(ConstString name
, SymbolType type
) const {
383 if (type
== eSymbolTypeAny
|| m_type
== type
) {
384 const Mangled
&mangled
= GetMangled();
385 return mangled
.GetMangledName() == name
||
386 mangled
.GetDemangledName() == name
;
391 #define ENUM_TO_CSTRING(x) \
392 case eSymbolType##x: \
395 const char *Symbol::GetTypeAsString() const {
397 ENUM_TO_CSTRING(Invalid
);
398 ENUM_TO_CSTRING(Absolute
);
399 ENUM_TO_CSTRING(Code
);
400 ENUM_TO_CSTRING(Resolver
);
401 ENUM_TO_CSTRING(Data
);
402 ENUM_TO_CSTRING(Trampoline
);
403 ENUM_TO_CSTRING(Runtime
);
404 ENUM_TO_CSTRING(Exception
);
405 ENUM_TO_CSTRING(SourceFile
);
406 ENUM_TO_CSTRING(HeaderFile
);
407 ENUM_TO_CSTRING(ObjectFile
);
408 ENUM_TO_CSTRING(CommonBlock
);
409 ENUM_TO_CSTRING(Block
);
410 ENUM_TO_CSTRING(Local
);
411 ENUM_TO_CSTRING(Param
);
412 ENUM_TO_CSTRING(Variable
);
413 ENUM_TO_CSTRING(VariableType
);
414 ENUM_TO_CSTRING(LineEntry
);
415 ENUM_TO_CSTRING(LineHeader
);
416 ENUM_TO_CSTRING(ScopeBegin
);
417 ENUM_TO_CSTRING(ScopeEnd
);
418 ENUM_TO_CSTRING(Additional
);
419 ENUM_TO_CSTRING(Compiler
);
420 ENUM_TO_CSTRING(Instrumentation
);
421 ENUM_TO_CSTRING(Undefined
);
422 ENUM_TO_CSTRING(ObjCClass
);
423 ENUM_TO_CSTRING(ObjCMetaClass
);
424 ENUM_TO_CSTRING(ObjCIVar
);
425 ENUM_TO_CSTRING(ReExported
);
429 return "<unknown SymbolType>";
432 void Symbol::CalculateSymbolContext(SymbolContext
*sc
) {
433 // Symbols can reconstruct the symbol and the module in the symbol context
435 if (ValueIsAddress())
436 sc
->module_sp
= GetAddressRef().GetModule();
438 sc
->module_sp
.reset();
441 ModuleSP
Symbol::CalculateSymbolContextModule() {
442 if (ValueIsAddress())
443 return GetAddressRef().GetModule();
447 Symbol
*Symbol::CalculateSymbolContextSymbol() { return this; }
449 void Symbol::DumpSymbolContext(Stream
*s
) {
450 bool dumped_module
= false;
451 if (ValueIsAddress()) {
452 ModuleSP
module_sp(GetAddressRef().GetModule());
454 dumped_module
= true;
455 module_sp
->DumpSymbolContext(s
);
461 s
->Printf("Symbol{0x%8.8x}", GetID());
464 lldb::addr_t
Symbol::GetByteSize() const { return m_addr_range
.GetByteSize(); }
466 Symbol
*Symbol::ResolveReExportedSymbolInModuleSpec(
467 Target
&target
, ConstString
&reexport_name
, ModuleSpec
&module_spec
,
468 ModuleList
&seen_modules
) const {
470 if (module_spec
.GetFileSpec()) {
471 // Try searching for the module file spec first using the full path
472 module_sp
= target
.GetImages().FindFirstModule(module_spec
);
474 // Next try and find the module by basename in case environment variables
475 // or other runtime trickery causes shared libraries to be loaded from
477 module_spec
.GetFileSpec().ClearDirectory();
478 module_sp
= target
.GetImages().FindFirstModule(module_spec
);
483 // There should not be cycles in the reexport list, but we don't want to
484 // crash if there are so make sure we haven't seen this before:
485 if (!seen_modules
.AppendIfNeeded(module_sp
))
488 lldb_private::SymbolContextList sc_list
;
489 module_sp
->FindSymbolsWithNameAndType(reexport_name
, eSymbolTypeAny
,
491 for (const SymbolContext
&sc
: sc_list
) {
492 if (sc
.symbol
->IsExternal())
495 // If we didn't find the symbol in this module, it may be because this
496 // module re-exports some whole other library. We have to search those as
498 seen_modules
.Append(module_sp
);
500 FileSpecList reexported_libraries
=
501 module_sp
->GetObjectFile()->GetReExportedLibraries();
502 size_t num_reexported_libraries
= reexported_libraries
.GetSize();
503 for (size_t idx
= 0; idx
< num_reexported_libraries
; idx
++) {
504 ModuleSpec reexported_module_spec
;
505 reexported_module_spec
.GetFileSpec() =
506 reexported_libraries
.GetFileSpecAtIndex(idx
);
507 Symbol
*result_symbol
= ResolveReExportedSymbolInModuleSpec(
508 target
, reexport_name
, reexported_module_spec
, seen_modules
);
510 return result_symbol
;
516 Symbol
*Symbol::ResolveReExportedSymbol(Target
&target
) const {
517 ConstString
reexport_name(GetReExportedSymbolName());
519 ModuleSpec module_spec
;
520 ModuleList seen_modules
;
521 module_spec
.GetFileSpec() = GetReExportedSymbolSharedLibrary();
522 if (module_spec
.GetFileSpec()) {
523 return ResolveReExportedSymbolInModuleSpec(target
, reexport_name
,
524 module_spec
, seen_modules
);
530 lldb::addr_t
Symbol::GetFileAddress() const {
531 if (ValueIsAddress())
532 return GetAddressRef().GetFileAddress();
534 return LLDB_INVALID_ADDRESS
;
537 lldb::addr_t
Symbol::GetLoadAddress(Target
*target
) const {
538 if (ValueIsAddress())
539 return GetAddressRef().GetLoadAddress(target
);
541 return LLDB_INVALID_ADDRESS
;
544 ConstString
Symbol::GetName() const { return GetMangled().GetName(); }
546 ConstString
Symbol::GetNameNoArguments() const {
547 return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments
);
550 lldb::addr_t
Symbol::ResolveCallableAddress(Target
&target
) const {
551 if (GetType() == lldb::eSymbolTypeUndefined
)
552 return LLDB_INVALID_ADDRESS
;
554 Address func_so_addr
;
556 bool is_indirect
= IsIndirect();
557 if (GetType() == eSymbolTypeReExported
) {
558 Symbol
*reexported_symbol
= ResolveReExportedSymbol(target
);
559 if (reexported_symbol
) {
560 func_so_addr
= reexported_symbol
->GetAddress();
561 is_indirect
= reexported_symbol
->IsIndirect();
564 func_so_addr
= GetAddress();
565 is_indirect
= IsIndirect();
568 if (func_so_addr
.IsValid()) {
569 if (!target
.GetProcessSP() && is_indirect
) {
570 // can't resolve indirect symbols without calling a function...
571 return LLDB_INVALID_ADDRESS
;
574 lldb::addr_t load_addr
=
575 func_so_addr
.GetCallableLoadAddress(&target
, is_indirect
);
577 if (load_addr
!= LLDB_INVALID_ADDRESS
) {
582 return LLDB_INVALID_ADDRESS
;
585 lldb::DisassemblerSP
Symbol::GetInstructions(const ExecutionContext
&exe_ctx
,
587 bool prefer_file_cache
) {
588 ModuleSP
module_sp(m_addr_range
.GetBaseAddress().GetModule());
589 if (module_sp
&& exe_ctx
.HasTargetScope()) {
590 return Disassembler::DisassembleRange(module_sp
->GetArchitecture(), nullptr,
591 flavor
, exe_ctx
.GetTargetRef(),
592 m_addr_range
, !prefer_file_cache
);
594 return lldb::DisassemblerSP();
597 bool Symbol::GetDisassembly(const ExecutionContext
&exe_ctx
, const char *flavor
,
598 bool prefer_file_cache
, Stream
&strm
) {
599 lldb::DisassemblerSP disassembler_sp
=
600 GetInstructions(exe_ctx
, flavor
, prefer_file_cache
);
601 if (disassembler_sp
) {
602 const bool show_address
= true;
603 const bool show_bytes
= false;
604 const bool show_control_flow_kind
= false;
605 disassembler_sp
->GetInstructionList().Dump(
606 &strm
, show_address
, show_bytes
, show_control_flow_kind
, &exe_ctx
);
612 bool Symbol::ContainsFileAddress(lldb::addr_t file_addr
) const {
613 return m_addr_range
.ContainsFileAddress(file_addr
);
616 bool Symbol::IsSyntheticWithAutoGeneratedName() const {
621 ConstString demangled
= m_mangled
.GetDemangledName();
622 return demangled
.GetStringRef().startswith(GetSyntheticSymbolPrefix());
625 void Symbol::SynthesizeNameIfNeeded() const {
626 if (m_is_synthetic
&& !m_mangled
) {
627 // Synthetic symbol names don't mean anything, but they do uniquely
628 // identify individual symbols so we give them a unique name. The name
629 // starts with the synthetic symbol prefix, followed by a unique number.
630 // Typically the UserID of a real symbol is the symbol table index of the
631 // symbol in the object file's symbol table(s), so it will be the same
632 // every time you read in the object file. We want the same persistence for
633 // synthetic symbols so that users can identify them across multiple debug
634 // sessions, to understand crashes in those symbols and to reliably set
635 // breakpoints on them.
636 llvm::SmallString
<256> name
;
637 llvm::raw_svector_ostream
os(name
);
638 os
<< GetSyntheticSymbolPrefix() << GetID();
639 m_mangled
.SetDemangledName(ConstString(os
.str()));
643 bool Symbol::Decode(const DataExtractor
&data
, lldb::offset_t
*offset_ptr
,
644 const SectionList
*section_list
,
645 const StringTableReader
&strtab
) {
646 if (!data
.ValidOffsetForDataOfSize(*offset_ptr
, 8))
648 m_uid
= data
.GetU32(offset_ptr
);
649 m_type_data
= data
.GetU16(offset_ptr
);
650 const uint16_t bitfields
= data
.GetU16(offset_ptr
);
651 m_type_data_resolved
= (1u << 15 & bitfields
) != 0;
652 m_is_synthetic
= (1u << 14 & bitfields
) != 0;
653 m_is_debug
= (1u << 13 & bitfields
) != 0;
654 m_is_external
= (1u << 12 & bitfields
) != 0;
655 m_size_is_sibling
= (1u << 11 & bitfields
) != 0;
656 m_size_is_synthesized
= (1u << 10 & bitfields
) != 0;
657 m_size_is_valid
= (1u << 9 & bitfields
) != 0;
658 m_demangled_is_synthesized
= (1u << 8 & bitfields
) != 0;
659 m_contains_linker_annotations
= (1u << 7 & bitfields
) != 0;
660 m_is_weak
= (1u << 6 & bitfields
) != 0;
661 m_type
= bitfields
& 0x003f;
662 if (!m_mangled
.Decode(data
, offset_ptr
, strtab
))
664 if (!data
.ValidOffsetForDataOfSize(*offset_ptr
, 20))
666 const bool is_addr
= data
.GetU8(offset_ptr
) != 0;
667 const uint64_t value
= data
.GetU64(offset_ptr
);
669 m_addr_range
.GetBaseAddress().ResolveAddressUsingFileSections(value
,
672 m_addr_range
.GetBaseAddress().Clear();
673 m_addr_range
.GetBaseAddress().SetOffset(value
);
675 m_addr_range
.SetByteSize(data
.GetU64(offset_ptr
));
676 m_flags
= data
.GetU32(offset_ptr
);
680 /// The encoding format for the symbol is as follows:
683 /// uint16_t m_type_data;
684 /// uint16_t bitfield_data;
687 /// uint64_t file_addr_or_value;
691 /// The only tricky thing in this encoding is encoding all of the bits in the
692 /// bitfields. We use a trick to store all bitfields as a 16 bit value and we
693 /// do the same thing when decoding the symbol. There are test that ensure this
694 /// encoding works for each individual bit. Everything else is very easy to
696 void Symbol::Encode(DataEncoder
&file
, ConstStringTable
&strtab
) const {
697 file
.AppendU32(m_uid
);
698 file
.AppendU16(m_type_data
);
699 uint16_t bitfields
= m_type
;
700 if (m_type_data_resolved
)
701 bitfields
|= 1u << 15;
703 bitfields
|= 1u << 14;
705 bitfields
|= 1u << 13;
707 bitfields
|= 1u << 12;
708 if (m_size_is_sibling
)
709 bitfields
|= 1u << 11;
710 if (m_size_is_synthesized
)
711 bitfields
|= 1u << 10;
713 bitfields
|= 1u << 9;
714 if (m_demangled_is_synthesized
)
715 bitfields
|= 1u << 8;
716 if (m_contains_linker_annotations
)
717 bitfields
|= 1u << 7;
719 bitfields
|= 1u << 6;
720 file
.AppendU16(bitfields
);
721 m_mangled
.Encode(file
, strtab
);
722 // A symbol's value might be an address, or it might be a constant. If the
723 // symbol's base address doesn't have a section, then it is a constant value.
724 // If it does have a section, we will encode the file address and re-resolve
725 // the address when we decode it.
726 bool is_addr
= m_addr_range
.GetBaseAddress().GetSection().get() != nullptr;
727 file
.AppendU8(is_addr
);
728 file
.AppendU64(m_addr_range
.GetBaseAddress().GetFileAddress());
729 file
.AppendU64(m_addr_range
.GetByteSize());
730 file
.AppendU32(m_flags
);
733 bool Symbol::operator==(const Symbol
&rhs
) const {
734 if (m_uid
!= rhs
.m_uid
)
736 if (m_type_data
!= rhs
.m_type_data
)
738 if (m_type_data_resolved
!= rhs
.m_type_data_resolved
)
740 if (m_is_synthetic
!= rhs
.m_is_synthetic
)
742 if (m_is_debug
!= rhs
.m_is_debug
)
744 if (m_is_external
!= rhs
.m_is_external
)
746 if (m_size_is_sibling
!= rhs
.m_size_is_sibling
)
748 if (m_size_is_synthesized
!= rhs
.m_size_is_synthesized
)
750 if (m_size_is_valid
!= rhs
.m_size_is_valid
)
752 if (m_demangled_is_synthesized
!= rhs
.m_demangled_is_synthesized
)
754 if (m_contains_linker_annotations
!= rhs
.m_contains_linker_annotations
)
756 if (m_is_weak
!= rhs
.m_is_weak
)
758 if (m_type
!= rhs
.m_type
)
760 if (m_mangled
!= rhs
.m_mangled
)
762 if (m_addr_range
.GetBaseAddress() != rhs
.m_addr_range
.GetBaseAddress())
764 if (m_addr_range
.GetByteSize() != rhs
.m_addr_range
.GetByteSize())
766 if (m_flags
!= rhs
.m_flags
)
774 bool fromJSON(const llvm::json::Value
&value
, lldb_private::JSONSymbol
&symbol
,
775 llvm::json::Path path
) {
776 llvm::json::ObjectMapper
o(value
, path
);
777 const bool mapped
= o
&& o
.map("value", symbol
.value
) &&
778 o
.map("address", symbol
.address
) &&
779 o
.map("size", symbol
.size
) && o
.map("id", symbol
.id
) &&
780 o
.map("type", symbol
.type
) && o
.map("name", symbol
.name
);
785 if (!symbol
.value
&& !symbol
.address
) {
786 path
.report("symbol must have either a value or an address");
790 if (symbol
.value
&& symbol
.address
) {
791 path
.report("symbol cannot have both a value and an address");
798 bool fromJSON(const llvm::json::Value
&value
, lldb::SymbolType
&type
,
799 llvm::json::Path path
) {
800 if (auto str
= value
.getAsString()) {
801 type
= llvm::StringSwitch
<lldb::SymbolType
>(*str
)
802 .Case("absolute", eSymbolTypeAbsolute
)
803 .Case("code", eSymbolTypeCode
)
804 .Case("resolver", eSymbolTypeResolver
)
805 .Case("data", eSymbolTypeData
)
806 .Case("trampoline", eSymbolTypeTrampoline
)
807 .Case("runtime", eSymbolTypeRuntime
)
808 .Case("exception", eSymbolTypeException
)
809 .Case("sourcefile", eSymbolTypeSourceFile
)
810 .Case("headerfile", eSymbolTypeHeaderFile
)
811 .Case("objectfile", eSymbolTypeObjectFile
)
812 .Case("commonblock", eSymbolTypeCommonBlock
)
813 .Case("block", eSymbolTypeBlock
)
814 .Case("local", eSymbolTypeLocal
)
815 .Case("param", eSymbolTypeParam
)
816 .Case("variable", eSymbolTypeVariable
)
817 .Case("variableType", eSymbolTypeVariableType
)
818 .Case("lineentry", eSymbolTypeLineEntry
)
819 .Case("lineheader", eSymbolTypeLineHeader
)
820 .Case("scopebegin", eSymbolTypeScopeBegin
)
821 .Case("scopeend", eSymbolTypeScopeEnd
)
822 .Case("additional,", eSymbolTypeAdditional
)
823 .Case("compiler", eSymbolTypeCompiler
)
824 .Case("instrumentation", eSymbolTypeInstrumentation
)
825 .Case("undefined", eSymbolTypeUndefined
)
826 .Case("objcclass", eSymbolTypeObjCClass
)
827 .Case("objcmetaClass", eSymbolTypeObjCMetaClass
)
828 .Case("objcivar", eSymbolTypeObjCIVar
)
829 .Case("reexporte", eSymbolTypeReExported
)
830 .Default(eSymbolTypeInvalid
);
832 if (type
== eSymbolTypeInvalid
) {
833 path
.report("invalid symbol type");
839 path
.report("expected string");