| 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 | |
| 26 | using namespace lldb; |
| 27 | using namespace lldb_private; |
| 28 | |
| 29 | Symbol::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 | |
| 37 | Symbol::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 §ion_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 | |
| 51 | Symbol::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 | |
| 66 | Symbol::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 | |
| 78 | const 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 | |
| 101 | llvm::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 | |
| 146 | void 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 | |
| 165 | bool Symbol::ValueIsAddress() const { |
| 166 | return (bool)m_addr_range.GetBaseAddress().GetSection(); |
| 167 | } |
| 168 | |
| 169 | ConstString Symbol::GetDisplayName() const { |
| 170 | return GetMangled().GetDisplayDemangledName(); |
| 171 | } |
| 172 | |
| 173 | ConstString 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 | |
| 187 | FileSpec 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 | |
| 199 | void 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 | |
| 206 | bool 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 | |
| 217 | uint32_t Symbol::GetSiblingIndex() const { |
| 218 | return m_size_is_sibling ? m_addr_range.GetByteSize() : UINT32_MAX; |
| 219 | } |
| 220 | |
| 221 | bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; } |
| 222 | |
| 223 | bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; } |
| 224 | |
| 225 | void 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 | |
| 266 | void 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 | |
| 313 | uint32_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 | |
| 386 | bool 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 | |
| 399 | const 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 | |
| 436 | void 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 | |
| 445 | ModuleSP Symbol::CalculateSymbolContextModule() { |
| 446 | if (ValueIsAddress()) |
| 447 | return GetAddressRef().GetModule(); |
| 448 | return ModuleSP(); |
| 449 | } |
| 450 | |
| 451 | Symbol *Symbol::CalculateSymbolContextSymbol() { return this; } |
| 452 | |
| 453 | void 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 | |
| 468 | lldb::addr_t Symbol::GetByteSize() const { return m_addr_range.GetByteSize(); } |
| 469 | |
| 470 | Symbol *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 | |
| 520 | Symbol *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 | |
| 534 | lldb::addr_t Symbol::GetFileAddress() const { |
| 535 | if (ValueIsAddress()) |
| 536 | return GetAddressRef().GetFileAddress(); |
| 537 | else |
| 538 | return LLDB_INVALID_ADDRESS; |
| 539 | } |
| 540 | |
| 541 | lldb::addr_t Symbol::GetLoadAddress(Target *target) const { |
| 542 | if (ValueIsAddress()) |
| 543 | return GetAddressRef().GetLoadAddress(target); |
| 544 | else |
| 545 | return LLDB_INVALID_ADDRESS; |
| 546 | } |
| 547 | |
| 548 | ConstString Symbol::GetName() const { return GetMangled().GetName(); } |
| 549 | |
| 550 | ConstString Symbol::GetNameNoArguments() const { |
| 551 | return GetMangled().GetName(preference: Mangled::ePreferDemangledWithoutArguments); |
| 552 | } |
| 553 | |
| 554 | lldb::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 | |
| 589 | lldb::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 | |
| 601 | bool 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 | |
| 616 | bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const { |
| 617 | return m_addr_range.ContainsFileAddress(file_addr); |
| 618 | } |
| 619 | |
| 620 | bool 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 | |
| 629 | void 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 | |
| 649 | bool Symbol::(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. |
| 702 | void 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 | |
| 739 | bool 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 | |
| 777 | namespace llvm { |
| 778 | namespace json { |
| 779 | |
| 780 | bool 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 | |
| 804 | bool 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 | |