Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Symbol / Symbol.cpp
blob26b4c4d62ad9c24667c1279c19983324da7a7aff
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 //===----------------------------------------------------------------------===//
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"
24 using namespace lldb;
25 using namespace lldb_private;
27 Symbol::Symbol()
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(),
33 m_addr_range() {}
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 &section_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,
53 uint32_t flags)
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),
62 m_flags(flags) {}
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) {
77 if (this != &rhs) {
78 SymbolContextScope::operator=(rhs);
79 m_uid = rhs.m_uid;
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;
91 m_type = rhs.m_type;
92 m_mangled = rhs.m_mangled;
93 m_addr_range = rhs.m_addr_range;
94 m_flags = rhs.m_flags;
96 return *this;
99 llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol,
100 SectionList *section_list) {
101 if (!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() {
149 m_uid = UINT32_MAX;
150 m_mangled.Clear();
151 m_type_data = 0;
152 m_type_data_resolved = false;
153 m_is_synthetic = false;
154 m_is_debug = 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;
161 m_is_weak = false;
162 m_type = eSymbolTypeInvalid;
163 m_flags = 0;
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();
181 if (str_ptr != 0)
182 return ConstString((const char *)str_ptr);
183 else
184 return GetName();
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();
195 if (str_ptr != 0)
196 return FileSpec((const char *)str_ptr);
198 return FileSpec();
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());
214 return true;
216 return false;
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();
234 if (byte_size > 0) {
235 s->PutCString(", range = ");
236 m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress,
237 Address::DumpStyleFileAddress);
238 } else {
239 s->PutCString(", address = ");
240 m_addr_range.GetBaseAddress().Dump(s, target,
241 Address::DumpStyleLoadAddress,
242 Address::DumpStyleFileAddress);
244 } else
245 s->Printf(", value = 0x%16.16" PRIx64,
246 m_addr_range.GetBaseAddress().GetOffset());
247 } else {
248 if (m_size_is_sibling)
249 s->Printf(", sibling = %5" PRIu64,
250 m_addr_range.GetBaseAddress().GetOffset());
251 else
252 s->Printf(", value = 0x%16.16" PRIx64,
253 m_addr_range.GetBaseAddress().GetOffset());
255 ConstString demangled = GetMangled().GetDemangledName();
256 if (demangled)
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' : ' ',
266 GetTypeAsString());
268 // Make sure the size of the symbol is up to date before dumping
269 GetByteSize();
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, "");
277 s->PutChar(' ');
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) {
287 s->Printf(
288 " 0x%8.8x %s",
289 m_flags, name.AsCString(""));
291 ConstString reexport_name = GetReExportedSymbolName();
292 intptr_t shlib = m_addr_range.GetByteSize();
293 if (shlib)
294 s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString());
295 else
296 s->Printf(" -> %s\n", reexport_name.GetCString());
297 } else {
298 const char *format =
299 m_size_is_sibling
300 ? "0x%16.16" PRIx64
301 " Sibling -> [%5llu] 0x%8.8x %s\n"
302 : "0x%16.16" PRIx64 " 0x%16.16" PRIx64
303 " 0x%8.8x %s\n";
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();
316 if (function) {
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();
321 } else {
322 ModuleSP module_sp(base_address.GetModule());
323 SymbolContext sc;
324 if (module_sp) {
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))
345 break;
347 // If this line number is different than our first one, use it
348 // and we're done.
349 if (sc_temp.line_entry.line != sc.line_entry.line) {
350 m_type_data = total_offset;
351 break;
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())
359 break;
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())
368 m_type_data = 0;
369 } else {
370 // TODO: expose something in Process to figure out the
371 // size of a function prologue.
372 m_type_data = 0;
377 return m_type_data;
379 return 0;
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;
388 return false;
391 #define ENUM_TO_CSTRING(x) \
392 case eSymbolType##x: \
393 return #x;
395 const char *Symbol::GetTypeAsString() const {
396 switch (m_type) {
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);
426 default:
427 break;
429 return "<unknown SymbolType>";
432 void Symbol::CalculateSymbolContext(SymbolContext *sc) {
433 // Symbols can reconstruct the symbol and the module in the symbol context
434 sc->symbol = this;
435 if (ValueIsAddress())
436 sc->module_sp = GetAddressRef().GetModule();
437 else
438 sc->module_sp.reset();
441 ModuleSP Symbol::CalculateSymbolContextModule() {
442 if (ValueIsAddress())
443 return GetAddressRef().GetModule();
444 return ModuleSP();
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());
453 if (module_sp) {
454 dumped_module = true;
455 module_sp->DumpSymbolContext(s);
458 if (dumped_module)
459 s->PutCString(", ");
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 {
469 ModuleSP module_sp;
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);
473 if (!module_sp) {
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
476 // alternate paths
477 module_spec.GetFileSpec().ClearDirectory();
478 module_sp = target.GetImages().FindFirstModule(module_spec);
482 if (module_sp) {
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))
486 return nullptr;
488 lldb_private::SymbolContextList sc_list;
489 module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny,
490 sc_list);
491 for (const SymbolContext &sc : sc_list) {
492 if (sc.symbol->IsExternal())
493 return sc.symbol;
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
497 // well:
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);
509 if (result_symbol)
510 return result_symbol;
513 return nullptr;
516 Symbol *Symbol::ResolveReExportedSymbol(Target &target) const {
517 ConstString reexport_name(GetReExportedSymbolName());
518 if (reexport_name) {
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);
527 return nullptr;
530 lldb::addr_t Symbol::GetFileAddress() const {
531 if (ValueIsAddress())
532 return GetAddressRef().GetFileAddress();
533 else
534 return LLDB_INVALID_ADDRESS;
537 lldb::addr_t Symbol::GetLoadAddress(Target *target) const {
538 if (ValueIsAddress())
539 return GetAddressRef().GetLoadAddress(target);
540 else
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();
563 } else {
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) {
578 return load_addr;
582 return LLDB_INVALID_ADDRESS;
585 lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx,
586 const char *flavor,
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);
607 return true;
609 return false;
612 bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const {
613 return m_addr_range.ContainsFileAddress(file_addr);
616 bool Symbol::IsSyntheticWithAutoGeneratedName() const {
617 if (!IsSynthetic())
618 return false;
619 if (!m_mangled)
620 return true;
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))
647 return false;
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))
663 return false;
664 if (!data.ValidOffsetForDataOfSize(*offset_ptr, 20))
665 return false;
666 const bool is_addr = data.GetU8(offset_ptr) != 0;
667 const uint64_t value = data.GetU64(offset_ptr);
668 if (is_addr) {
669 m_addr_range.GetBaseAddress().ResolveAddressUsingFileSections(value,
670 section_list);
671 } else {
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);
677 return true;
680 /// The encoding format for the symbol is as follows:
682 /// uint32_t m_uid;
683 /// uint16_t m_type_data;
684 /// uint16_t bitfield_data;
685 /// Mangled mangled;
686 /// uint8_t is_addr;
687 /// uint64_t file_addr_or_value;
688 /// uint64_t size;
689 /// uint32_t flags;
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
695 /// store.
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;
702 if (m_is_synthetic)
703 bitfields |= 1u << 14;
704 if (m_is_debug)
705 bitfields |= 1u << 13;
706 if (m_is_external)
707 bitfields |= 1u << 12;
708 if (m_size_is_sibling)
709 bitfields |= 1u << 11;
710 if (m_size_is_synthesized)
711 bitfields |= 1u << 10;
712 if (m_size_is_valid)
713 bitfields |= 1u << 9;
714 if (m_demangled_is_synthesized)
715 bitfields |= 1u << 8;
716 if (m_contains_linker_annotations)
717 bitfields |= 1u << 7;
718 if (m_is_weak)
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)
735 return false;
736 if (m_type_data != rhs.m_type_data)
737 return false;
738 if (m_type_data_resolved != rhs.m_type_data_resolved)
739 return false;
740 if (m_is_synthetic != rhs.m_is_synthetic)
741 return false;
742 if (m_is_debug != rhs.m_is_debug)
743 return false;
744 if (m_is_external != rhs.m_is_external)
745 return false;
746 if (m_size_is_sibling != rhs.m_size_is_sibling)
747 return false;
748 if (m_size_is_synthesized != rhs.m_size_is_synthesized)
749 return false;
750 if (m_size_is_valid != rhs.m_size_is_valid)
751 return false;
752 if (m_demangled_is_synthesized != rhs.m_demangled_is_synthesized)
753 return false;
754 if (m_contains_linker_annotations != rhs.m_contains_linker_annotations)
755 return false;
756 if (m_is_weak != rhs.m_is_weak)
757 return false;
758 if (m_type != rhs.m_type)
759 return false;
760 if (m_mangled != rhs.m_mangled)
761 return false;
762 if (m_addr_range.GetBaseAddress() != rhs.m_addr_range.GetBaseAddress())
763 return false;
764 if (m_addr_range.GetByteSize() != rhs.m_addr_range.GetByteSize())
765 return false;
766 if (m_flags != rhs.m_flags)
767 return false;
768 return true;
771 namespace llvm {
772 namespace json {
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);
782 if (!mapped)
783 return false;
785 if (!symbol.value && !symbol.address) {
786 path.report("symbol must have either a value or an address");
787 return false;
790 if (symbol.value && symbol.address) {
791 path.report("symbol cannot have both a value and an address");
792 return false;
795 return true;
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");
834 return false;
837 return true;
839 path.report("expected string");
840 return false;
842 } // namespace json
843 } // namespace llvm