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"
24 using namespace lldb_private
;
27 : SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false),
28 m_is_debug(false), m_is_external(false), m_size_is_sibling(false),
29 m_size_is_synthesized(false), m_size_is_valid(false),
30 m_demangled_is_synthesized(false), m_contains_linker_annotations(false),
31 m_is_weak(false), m_type(eSymbolTypeInvalid
), m_mangled(),
34 Symbol::Symbol(uint32_t symID
, llvm::StringRef name
, SymbolType type
, bool external
,
35 bool is_debug
, bool is_trampoline
, bool is_artificial
,
36 const lldb::SectionSP
§ion_sp
, addr_t offset
, addr_t size
,
37 bool size_is_valid
, bool contains_linker_annotations
,
39 : SymbolContextScope(), m_uid(symID
), m_type_data(0),
40 m_type_data_resolved(false), m_is_synthetic(is_artificial
),
41 m_is_debug(is_debug
), m_is_external(external
), m_size_is_sibling(false),
42 m_size_is_synthesized(false), m_size_is_valid(size_is_valid
|| size
> 0),
43 m_demangled_is_synthesized(false),
44 m_contains_linker_annotations(contains_linker_annotations
),
45 m_is_weak(false), m_type(type
),
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(0),
55 m_type_data_resolved(false), m_is_synthetic(is_artificial
),
56 m_is_debug(is_debug
), 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 void Symbol::Clear() {
103 m_type_data_resolved
= false;
104 m_is_synthetic
= false;
106 m_is_external
= false;
107 m_size_is_sibling
= false;
108 m_size_is_synthesized
= false;
109 m_size_is_valid
= false;
110 m_demangled_is_synthesized
= false;
111 m_contains_linker_annotations
= false;
113 m_type
= eSymbolTypeInvalid
;
115 m_addr_range
.Clear();
118 bool Symbol::ValueIsAddress() const {
119 return m_addr_range
.GetBaseAddress().GetSection().get() != nullptr ||
120 m_type
== eSymbolTypeAbsolute
;
123 ConstString
Symbol::GetDisplayName() const {
124 return GetMangled().GetDisplayDemangledName();
127 ConstString
Symbol::GetReExportedSymbolName() const {
128 if (m_type
== eSymbolTypeReExported
) {
129 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
130 // as the offset in the address range base address. We can then make this
131 // back into a string that is the re-exported name.
132 intptr_t str_ptr
= m_addr_range
.GetBaseAddress().GetOffset();
134 return ConstString((const char *)str_ptr
);
138 return ConstString();
141 FileSpec
Symbol::GetReExportedSymbolSharedLibrary() const {
142 if (m_type
== eSymbolTypeReExported
) {
143 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
144 // as the offset in the address range base address. We can then make this
145 // back into a string that is the re-exported name.
146 intptr_t str_ptr
= m_addr_range
.GetByteSize();
148 return FileSpec((const char *)str_ptr
);
153 void Symbol::SetReExportedSymbolName(ConstString name
) {
154 SetType(eSymbolTypeReExported
);
155 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
156 // as the offset in the address range base address.
157 m_addr_range
.GetBaseAddress().SetOffset((uintptr_t)name
.GetCString());
160 bool Symbol::SetReExportedSymbolSharedLibrary(const FileSpec
&fspec
) {
161 if (m_type
== eSymbolTypeReExported
) {
162 // For eSymbolTypeReExported, the "const char *" from a ConstString is used
163 // as the offset in the address range base address.
164 m_addr_range
.SetByteSize(
165 (uintptr_t)ConstString(fspec
.GetPath().c_str()).GetCString());
171 uint32_t Symbol::GetSiblingIndex() const {
172 return m_size_is_sibling
? m_addr_range
.GetByteSize() : UINT32_MAX
;
175 bool Symbol::IsTrampoline() const { return m_type
== eSymbolTypeTrampoline
; }
177 bool Symbol::IsIndirect() const { return m_type
== eSymbolTypeResolver
; }
179 void Symbol::GetDescription(Stream
*s
, lldb::DescriptionLevel level
,
180 Target
*target
) const {
181 s
->Printf("id = {0x%8.8x}", m_uid
);
183 if (m_addr_range
.GetBaseAddress().GetSection()) {
184 if (ValueIsAddress()) {
185 const lldb::addr_t byte_size
= GetByteSize();
187 s
->PutCString(", range = ");
188 m_addr_range
.Dump(s
, target
, Address::DumpStyleLoadAddress
,
189 Address::DumpStyleFileAddress
);
191 s
->PutCString(", address = ");
192 m_addr_range
.GetBaseAddress().Dump(s
, target
,
193 Address::DumpStyleLoadAddress
,
194 Address::DumpStyleFileAddress
);
197 s
->Printf(", value = 0x%16.16" PRIx64
,
198 m_addr_range
.GetBaseAddress().GetOffset());
200 if (m_size_is_sibling
)
201 s
->Printf(", sibling = %5" PRIu64
,
202 m_addr_range
.GetBaseAddress().GetOffset());
204 s
->Printf(", value = 0x%16.16" PRIx64
,
205 m_addr_range
.GetBaseAddress().GetOffset());
207 ConstString demangled
= GetMangled().GetDemangledName();
209 s
->Printf(", name=\"%s\"", demangled
.AsCString());
210 if (m_mangled
.GetMangledName())
211 s
->Printf(", mangled=\"%s\"", m_mangled
.GetMangledName().AsCString());
214 void Symbol::Dump(Stream
*s
, Target
*target
, uint32_t index
,
215 Mangled::NamePreference name_preference
) const {
216 s
->Printf("[%5u] %6u %c%c%c %-15s ", index
, GetID(), m_is_debug
? 'D' : ' ',
217 m_is_synthetic
? 'S' : ' ', m_is_external
? 'X' : ' ',
220 // Make sure the size of the symbol is up to date before dumping
223 ConstString name
= GetMangled().GetName(name_preference
);
224 if (ValueIsAddress()) {
225 if (!m_addr_range
.GetBaseAddress().Dump(s
, nullptr,
226 Address::DumpStyleFileAddress
))
227 s
->Printf("%*s", 18, "");
231 if (!m_addr_range
.GetBaseAddress().Dump(s
, target
,
232 Address::DumpStyleLoadAddress
))
233 s
->Printf("%*s", 18, "");
235 const char *format
= m_size_is_sibling
? " Sibling -> [%5llu] 0x%8.8x %s\n"
236 : " 0x%16.16" PRIx64
" 0x%8.8x %s\n";
237 s
->Printf(format
, GetByteSize(), m_flags
, name
.AsCString(""));
238 } else if (m_type
== eSymbolTypeReExported
) {
241 m_flags
, name
.AsCString(""));
243 ConstString reexport_name
= GetReExportedSymbolName();
244 intptr_t shlib
= m_addr_range
.GetByteSize();
246 s
->Printf(" -> %s`%s\n", (const char *)shlib
, reexport_name
.GetCString());
248 s
->Printf(" -> %s\n", reexport_name
.GetCString());
253 " Sibling -> [%5llu] 0x%8.8x %s\n"
254 : "0x%16.16" PRIx64
" 0x%16.16" PRIx64
256 s
->Printf(format
, m_addr_range
.GetBaseAddress().GetOffset(), GetByteSize(),
257 m_flags
, name
.AsCString(""));
261 uint32_t Symbol::GetPrologueByteSize() {
262 if (m_type
== eSymbolTypeCode
|| m_type
== eSymbolTypeResolver
) {
263 if (!m_type_data_resolved
) {
264 m_type_data_resolved
= true;
266 const Address
&base_address
= m_addr_range
.GetBaseAddress();
267 Function
*function
= base_address
.CalculateSymbolContextFunction();
269 // Functions have line entries which can also potentially have end of
270 // prologue information. So if this symbol points to a function, use
271 // the prologue information from there.
272 m_type_data
= function
->GetPrologueByteSize();
274 ModuleSP
module_sp(base_address
.GetModule());
277 uint32_t resolved_flags
= module_sp
->ResolveSymbolContextForAddress(
278 base_address
, eSymbolContextLineEntry
, sc
);
279 if (resolved_flags
& eSymbolContextLineEntry
) {
280 // Default to the end of the first line entry.
281 m_type_data
= sc
.line_entry
.range
.GetByteSize();
283 // Set address for next line.
284 Address
addr(base_address
);
285 addr
.Slide(m_type_data
);
287 // Check the first few instructions and look for one that has a
288 // line number that is different than the first entry. This is also
289 // done in Function::GetPrologueByteSize().
290 uint16_t total_offset
= m_type_data
;
291 for (int idx
= 0; idx
< 6; ++idx
) {
292 SymbolContext sc_temp
;
293 resolved_flags
= module_sp
->ResolveSymbolContextForAddress(
294 addr
, eSymbolContextLineEntry
, sc_temp
);
295 // Make sure we got line number information...
296 if (!(resolved_flags
& eSymbolContextLineEntry
))
299 // If this line number is different than our first one, use it
301 if (sc_temp
.line_entry
.line
!= sc
.line_entry
.line
) {
302 m_type_data
= total_offset
;
306 // Slide addr up to the next line address.
307 addr
.Slide(sc_temp
.line_entry
.range
.GetByteSize());
308 total_offset
+= sc_temp
.line_entry
.range
.GetByteSize();
309 // If we've gone too far, bail out.
310 if (total_offset
>= m_addr_range
.GetByteSize())
314 // Sanity check - this may be a function in the middle of code that
315 // has debug information, but not for this symbol. So the line
316 // entries surrounding us won't lie inside our function. In that
317 // case, the line entry will be bigger than we are, so we do that
318 // quick check and if that is true, we just return 0.
319 if (m_type_data
>= m_addr_range
.GetByteSize())
322 // TODO: expose something in Process to figure out the
323 // size of a function prologue.
334 bool Symbol::Compare(ConstString name
, SymbolType type
) const {
335 if (type
== eSymbolTypeAny
|| m_type
== type
) {
336 const Mangled
&mangled
= GetMangled();
337 return mangled
.GetMangledName() == name
||
338 mangled
.GetDemangledName() == name
;
343 #define ENUM_TO_CSTRING(x) \
344 case eSymbolType##x: \
347 const char *Symbol::GetTypeAsString() const {
349 ENUM_TO_CSTRING(Invalid
);
350 ENUM_TO_CSTRING(Absolute
);
351 ENUM_TO_CSTRING(Code
);
352 ENUM_TO_CSTRING(Resolver
);
353 ENUM_TO_CSTRING(Data
);
354 ENUM_TO_CSTRING(Trampoline
);
355 ENUM_TO_CSTRING(Runtime
);
356 ENUM_TO_CSTRING(Exception
);
357 ENUM_TO_CSTRING(SourceFile
);
358 ENUM_TO_CSTRING(HeaderFile
);
359 ENUM_TO_CSTRING(ObjectFile
);
360 ENUM_TO_CSTRING(CommonBlock
);
361 ENUM_TO_CSTRING(Block
);
362 ENUM_TO_CSTRING(Local
);
363 ENUM_TO_CSTRING(Param
);
364 ENUM_TO_CSTRING(Variable
);
365 ENUM_TO_CSTRING(VariableType
);
366 ENUM_TO_CSTRING(LineEntry
);
367 ENUM_TO_CSTRING(LineHeader
);
368 ENUM_TO_CSTRING(ScopeBegin
);
369 ENUM_TO_CSTRING(ScopeEnd
);
370 ENUM_TO_CSTRING(Additional
);
371 ENUM_TO_CSTRING(Compiler
);
372 ENUM_TO_CSTRING(Instrumentation
);
373 ENUM_TO_CSTRING(Undefined
);
374 ENUM_TO_CSTRING(ObjCClass
);
375 ENUM_TO_CSTRING(ObjCMetaClass
);
376 ENUM_TO_CSTRING(ObjCIVar
);
377 ENUM_TO_CSTRING(ReExported
);
381 return "<unknown SymbolType>";
384 void Symbol::CalculateSymbolContext(SymbolContext
*sc
) {
385 // Symbols can reconstruct the symbol and the module in the symbol context
387 if (ValueIsAddress())
388 sc
->module_sp
= GetAddressRef().GetModule();
390 sc
->module_sp
.reset();
393 ModuleSP
Symbol::CalculateSymbolContextModule() {
394 if (ValueIsAddress())
395 return GetAddressRef().GetModule();
399 Symbol
*Symbol::CalculateSymbolContextSymbol() { return this; }
401 void Symbol::DumpSymbolContext(Stream
*s
) {
402 bool dumped_module
= false;
403 if (ValueIsAddress()) {
404 ModuleSP
module_sp(GetAddressRef().GetModule());
406 dumped_module
= true;
407 module_sp
->DumpSymbolContext(s
);
413 s
->Printf("Symbol{0x%8.8x}", GetID());
416 lldb::addr_t
Symbol::GetByteSize() const { return m_addr_range
.GetByteSize(); }
418 Symbol
*Symbol::ResolveReExportedSymbolInModuleSpec(
419 Target
&target
, ConstString
&reexport_name
, ModuleSpec
&module_spec
,
420 ModuleList
&seen_modules
) const {
422 if (module_spec
.GetFileSpec()) {
423 // Try searching for the module file spec first using the full path
424 module_sp
= target
.GetImages().FindFirstModule(module_spec
);
426 // Next try and find the module by basename in case environment variables
427 // or other runtime trickery causes shared libraries to be loaded from
429 module_spec
.GetFileSpec().GetDirectory().Clear();
430 module_sp
= target
.GetImages().FindFirstModule(module_spec
);
435 // There should not be cycles in the reexport list, but we don't want to
436 // crash if there are so make sure we haven't seen this before:
437 if (!seen_modules
.AppendIfNeeded(module_sp
))
440 lldb_private::SymbolContextList sc_list
;
441 module_sp
->FindSymbolsWithNameAndType(reexport_name
, eSymbolTypeAny
,
443 const size_t num_scs
= sc_list
.GetSize();
445 for (size_t i
= 0; i
< num_scs
; ++i
) {
446 lldb_private::SymbolContext sc
;
447 if (sc_list
.GetContextAtIndex(i
, sc
)) {
448 if (sc
.symbol
->IsExternal())
453 // If we didn't find the symbol in this module, it may be because this
454 // module re-exports some whole other library. We have to search those as
456 seen_modules
.Append(module_sp
);
458 FileSpecList reexported_libraries
=
459 module_sp
->GetObjectFile()->GetReExportedLibraries();
460 size_t num_reexported_libraries
= reexported_libraries
.GetSize();
461 for (size_t idx
= 0; idx
< num_reexported_libraries
; idx
++) {
462 ModuleSpec reexported_module_spec
;
463 reexported_module_spec
.GetFileSpec() =
464 reexported_libraries
.GetFileSpecAtIndex(idx
);
465 Symbol
*result_symbol
= ResolveReExportedSymbolInModuleSpec(
466 target
, reexport_name
, reexported_module_spec
, seen_modules
);
468 return result_symbol
;
474 Symbol
*Symbol::ResolveReExportedSymbol(Target
&target
) const {
475 ConstString
reexport_name(GetReExportedSymbolName());
477 ModuleSpec module_spec
;
478 ModuleList seen_modules
;
479 module_spec
.GetFileSpec() = GetReExportedSymbolSharedLibrary();
480 if (module_spec
.GetFileSpec()) {
481 return ResolveReExportedSymbolInModuleSpec(target
, reexport_name
,
482 module_spec
, seen_modules
);
488 lldb::addr_t
Symbol::GetFileAddress() const {
489 if (ValueIsAddress())
490 return GetAddressRef().GetFileAddress();
492 return LLDB_INVALID_ADDRESS
;
495 lldb::addr_t
Symbol::GetLoadAddress(Target
*target
) const {
496 if (ValueIsAddress())
497 return GetAddressRef().GetLoadAddress(target
);
499 return LLDB_INVALID_ADDRESS
;
502 ConstString
Symbol::GetName() const { return GetMangled().GetName(); }
504 ConstString
Symbol::GetNameNoArguments() const {
505 return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments
);
508 lldb::addr_t
Symbol::ResolveCallableAddress(Target
&target
) const {
509 if (GetType() == lldb::eSymbolTypeUndefined
)
510 return LLDB_INVALID_ADDRESS
;
512 Address func_so_addr
;
514 bool is_indirect
= IsIndirect();
515 if (GetType() == eSymbolTypeReExported
) {
516 Symbol
*reexported_symbol
= ResolveReExportedSymbol(target
);
517 if (reexported_symbol
) {
518 func_so_addr
= reexported_symbol
->GetAddress();
519 is_indirect
= reexported_symbol
->IsIndirect();
522 func_so_addr
= GetAddress();
523 is_indirect
= IsIndirect();
526 if (func_so_addr
.IsValid()) {
527 if (!target
.GetProcessSP() && is_indirect
) {
528 // can't resolve indirect symbols without calling a function...
529 return LLDB_INVALID_ADDRESS
;
532 lldb::addr_t load_addr
=
533 func_so_addr
.GetCallableLoadAddress(&target
, is_indirect
);
535 if (load_addr
!= LLDB_INVALID_ADDRESS
) {
540 return LLDB_INVALID_ADDRESS
;
543 lldb::DisassemblerSP
Symbol::GetInstructions(const ExecutionContext
&exe_ctx
,
545 bool prefer_file_cache
) {
546 ModuleSP
module_sp(m_addr_range
.GetBaseAddress().GetModule());
547 if (module_sp
&& exe_ctx
.HasTargetScope()) {
548 return Disassembler::DisassembleRange(module_sp
->GetArchitecture(), nullptr,
549 flavor
, exe_ctx
.GetTargetRef(),
550 m_addr_range
, !prefer_file_cache
);
552 return lldb::DisassemblerSP();
555 bool Symbol::GetDisassembly(const ExecutionContext
&exe_ctx
, const char *flavor
,
556 bool prefer_file_cache
, Stream
&strm
) {
557 lldb::DisassemblerSP disassembler_sp
=
558 GetInstructions(exe_ctx
, flavor
, prefer_file_cache
);
559 if (disassembler_sp
) {
560 const bool show_address
= true;
561 const bool show_bytes
= false;
562 disassembler_sp
->GetInstructionList().Dump(&strm
, show_address
, show_bytes
,
569 bool Symbol::ContainsFileAddress(lldb::addr_t file_addr
) const {
570 return m_addr_range
.ContainsFileAddress(file_addr
);
573 bool Symbol::IsSyntheticWithAutoGeneratedName() const {
578 ConstString demangled
= m_mangled
.GetDemangledName();
579 return demangled
.GetStringRef().startswith(GetSyntheticSymbolPrefix());
582 void Symbol::SynthesizeNameIfNeeded() const {
583 if (m_is_synthetic
&& !m_mangled
) {
584 // Synthetic symbol names don't mean anything, but they do uniquely
585 // identify individual symbols so we give them a unique name. The name
586 // starts with the synthetic symbol prefix, followed by a unique number.
587 // Typically the UserID of a real symbol is the symbol table index of the
588 // symbol in the object file's symbol table(s), so it will be the same
589 // every time you read in the object file. We want the same persistence for
590 // synthetic symbols so that users can identify them across multiple debug
591 // sessions, to understand crashes in those symbols and to reliably set
592 // breakpoints on them.
593 llvm::SmallString
<256> name
;
594 llvm::raw_svector_ostream
os(name
);
595 os
<< GetSyntheticSymbolPrefix() << GetID();
596 m_mangled
.SetDemangledName(ConstString(os
.str()));
600 bool Symbol::Decode(const DataExtractor
&data
, lldb::offset_t
*offset_ptr
,
601 const SectionList
*section_list
,
602 const StringTableReader
&strtab
) {
603 if (!data
.ValidOffsetForDataOfSize(*offset_ptr
, 8))
605 m_uid
= data
.GetU32(offset_ptr
);
606 m_type_data
= data
.GetU16(offset_ptr
);
607 const uint16_t bitfields
= data
.GetU16(offset_ptr
);
608 m_type_data_resolved
= (1u << 15 & bitfields
) != 0;
609 m_is_synthetic
= (1u << 14 & bitfields
) != 0;
610 m_is_debug
= (1u << 13 & bitfields
) != 0;
611 m_is_external
= (1u << 12 & bitfields
) != 0;
612 m_size_is_sibling
= (1u << 11 & bitfields
) != 0;
613 m_size_is_synthesized
= (1u << 10 & bitfields
) != 0;
614 m_size_is_valid
= (1u << 9 & bitfields
) != 0;
615 m_demangled_is_synthesized
= (1u << 8 & bitfields
) != 0;
616 m_contains_linker_annotations
= (1u << 7 & bitfields
) != 0;
617 m_is_weak
= (1u << 6 & bitfields
) != 0;
618 m_type
= bitfields
& 0x003f;
619 if (!m_mangled
.Decode(data
, offset_ptr
, strtab
))
621 if (!data
.ValidOffsetForDataOfSize(*offset_ptr
, 20))
623 const bool is_addr
= data
.GetU8(offset_ptr
) != 0;
624 const uint64_t value
= data
.GetU64(offset_ptr
);
626 m_addr_range
.GetBaseAddress().ResolveAddressUsingFileSections(
627 value
, section_list
);
629 m_addr_range
.GetBaseAddress().Clear();
630 m_addr_range
.GetBaseAddress().SetOffset(value
);
632 m_addr_range
.SetByteSize(data
.GetU64(offset_ptr
));
633 m_flags
= data
.GetU32(offset_ptr
);
637 /// The encoding format for the symbol is as follows:
640 /// uint16_t m_type_data;
641 /// uint16_t bitfield_data;
644 /// uint64_t file_addr_or_value;
648 /// The only tricky thing in this encoding is encoding all of the bits in the
649 /// bitfields. We use a trick to store all bitfields as a 16 bit value and we
650 /// do the same thing when decoding the symbol. There are test that ensure this
651 /// encoding works for each individual bit. Everything else is very easy to
653 void Symbol::Encode(DataEncoder
&file
, ConstStringTable
&strtab
) const {
654 file
.AppendU32(m_uid
);
655 file
.AppendU16(m_type_data
);
656 uint16_t bitfields
= m_type
;
657 if (m_type_data_resolved
)
658 bitfields
|= 1u << 15;
660 bitfields
|= 1u << 14;
662 bitfields
|= 1u << 13;
664 bitfields
|= 1u << 12;
665 if (m_size_is_sibling
)
666 bitfields
|= 1u << 11;
667 if (m_size_is_synthesized
)
668 bitfields
|= 1u << 10;
670 bitfields
|= 1u << 9;
671 if (m_demangled_is_synthesized
)
672 bitfields
|= 1u << 8;
673 if (m_contains_linker_annotations
)
674 bitfields
|= 1u << 7;
676 bitfields
|= 1u << 6;
677 file
.AppendU16(bitfields
);
678 m_mangled
.Encode(file
, strtab
);
679 // A symbol's value might be an address, or it might be a constant. If the
680 // symbol's base address doesn't have a section, then it is a constant value.
681 // If it does have a section, we will encode the file address and re-resolve
682 // the address when we decode it.
683 bool is_addr
= m_addr_range
.GetBaseAddress().GetSection().get() != nullptr;
684 file
.AppendU8(is_addr
);
685 file
.AppendU64(m_addr_range
.GetBaseAddress().GetFileAddress());
686 file
.AppendU64(m_addr_range
.GetByteSize());
687 file
.AppendU32(m_flags
);
690 bool Symbol::operator==(const Symbol
&rhs
) const {
691 if (m_uid
!= rhs
.m_uid
)
693 if (m_type_data
!= rhs
.m_type_data
)
695 if (m_type_data_resolved
!= rhs
.m_type_data_resolved
)
697 if (m_is_synthetic
!= rhs
.m_is_synthetic
)
699 if (m_is_debug
!= rhs
.m_is_debug
)
701 if (m_is_external
!= rhs
.m_is_external
)
703 if (m_size_is_sibling
!= rhs
.m_size_is_sibling
)
705 if (m_size_is_synthesized
!= rhs
.m_size_is_synthesized
)
707 if (m_size_is_valid
!= rhs
.m_size_is_valid
)
709 if (m_demangled_is_synthesized
!= rhs
.m_demangled_is_synthesized
)
711 if (m_contains_linker_annotations
!= rhs
.m_contains_linker_annotations
)
713 if (m_is_weak
!= rhs
.m_is_weak
)
715 if (m_type
!= rhs
.m_type
)
717 if (m_mangled
!= rhs
.m_mangled
)
719 if (m_addr_range
.GetBaseAddress() != rhs
.m_addr_range
.GetBaseAddress())
721 if (m_addr_range
.GetByteSize() != rhs
.m_addr_range
.GetByteSize())
723 if (m_flags
!= rhs
.m_flags
)