Symbol.cpp revision 263363
1//===-- Symbol.cpp ----------------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "lldb/Symbol/Symbol.h" 11 12#include "lldb/Core/Module.h" 13#include "lldb/Core/ModuleSpec.h" 14#include "lldb/Core/Section.h" 15#include "lldb/Core/Stream.h" 16#include "lldb/Symbol/ObjectFile.h" 17#include "lldb/Symbol/Symtab.h" 18#include "lldb/Symbol/Function.h" 19#include "lldb/Target/Process.h" 20#include "lldb/Target/Target.h" 21#include "lldb/Symbol/SymbolVendor.h" 22 23using namespace lldb; 24using namespace lldb_private; 25 26 27Symbol::Symbol() : 28 SymbolContextScope (), 29 m_uid (UINT32_MAX), 30 m_type_data (0), 31 m_type_data_resolved (false), 32 m_is_synthetic (false), 33 m_is_debug (false), 34 m_is_external (false), 35 m_size_is_sibling (false), 36 m_size_is_synthesized (false), 37 m_size_is_valid (false), 38 m_demangled_is_synthesized (false), 39 m_type (eSymbolTypeInvalid), 40 m_mangled (), 41 m_addr_range (), 42 m_flags () 43{ 44} 45 46Symbol::Symbol 47( 48 uint32_t symID, 49 const char *name, 50 bool name_is_mangled, 51 SymbolType type, 52 bool external, 53 bool is_debug, 54 bool is_trampoline, 55 bool is_artificial, 56 const lldb::SectionSP §ion_sp, 57 addr_t offset, 58 addr_t size, 59 bool size_is_valid, 60 uint32_t flags 61) : 62 SymbolContextScope (), 63 m_uid (symID), 64 m_type_data (0), 65 m_type_data_resolved (false), 66 m_is_synthetic (is_artificial), 67 m_is_debug (is_debug), 68 m_is_external (external), 69 m_size_is_sibling (false), 70 m_size_is_synthesized (false), 71 m_size_is_valid (size_is_valid || size > 0), 72 m_demangled_is_synthesized (false), 73 m_type (type), 74 m_mangled (ConstString(name), name_is_mangled), 75 m_addr_range (section_sp, offset, size), 76 m_flags (flags) 77{ 78} 79 80Symbol::Symbol 81( 82 uint32_t symID, 83 const char *name, 84 bool name_is_mangled, 85 SymbolType type, 86 bool external, 87 bool is_debug, 88 bool is_trampoline, 89 bool is_artificial, 90 const AddressRange &range, 91 bool size_is_valid, 92 uint32_t flags 93) : 94 SymbolContextScope (), 95 m_uid (symID), 96 m_type_data (0), 97 m_type_data_resolved (false), 98 m_is_synthetic (is_artificial), 99 m_is_debug (is_debug), 100 m_is_external (external), 101 m_size_is_sibling (false), 102 m_size_is_synthesized (false), 103 m_size_is_valid (size_is_valid || range.GetByteSize() > 0), 104 m_demangled_is_synthesized (false), 105 m_type (type), 106 m_mangled (ConstString(name), name_is_mangled), 107 m_addr_range (range), 108 m_flags (flags) 109{ 110} 111 112Symbol::Symbol(const Symbol& rhs): 113 SymbolContextScope (rhs), 114 m_uid (rhs.m_uid), 115 m_type_data (rhs.m_type_data), 116 m_type_data_resolved (rhs.m_type_data_resolved), 117 m_is_synthetic (rhs.m_is_synthetic), 118 m_is_debug (rhs.m_is_debug), 119 m_is_external (rhs.m_is_external), 120 m_size_is_sibling (rhs.m_size_is_sibling), 121 m_size_is_synthesized (false), 122 m_size_is_valid (rhs.m_size_is_valid), 123 m_demangled_is_synthesized (rhs.m_demangled_is_synthesized), 124 m_type (rhs.m_type), 125 m_mangled (rhs.m_mangled), 126 m_addr_range (rhs.m_addr_range), 127 m_flags (rhs.m_flags) 128{ 129} 130 131const Symbol& 132Symbol::operator= (const Symbol& rhs) 133{ 134 if (this != &rhs) 135 { 136 SymbolContextScope::operator= (rhs); 137 m_uid = rhs.m_uid; 138 m_type_data = rhs.m_type_data; 139 m_type_data_resolved = rhs.m_type_data_resolved; 140 m_is_synthetic = rhs.m_is_synthetic; 141 m_is_debug = rhs.m_is_debug; 142 m_is_external = rhs.m_is_external; 143 m_size_is_sibling = rhs.m_size_is_sibling; 144 m_size_is_synthesized = rhs.m_size_is_sibling; 145 m_size_is_valid = rhs.m_size_is_valid; 146 m_demangled_is_synthesized = rhs.m_demangled_is_synthesized; 147 m_type = rhs.m_type; 148 m_mangled = rhs.m_mangled; 149 m_addr_range = rhs.m_addr_range; 150 m_flags = rhs.m_flags; 151 } 152 return *this; 153} 154 155void 156Symbol::Clear() 157{ 158 m_uid = UINT32_MAX; 159 m_mangled.Clear(); 160 m_type_data = 0; 161 m_type_data_resolved = false; 162 m_is_synthetic = false; 163 m_is_debug = false; 164 m_is_external = false; 165 m_size_is_sibling = false; 166 m_size_is_synthesized = false; 167 m_size_is_valid = false; 168 m_demangled_is_synthesized = false; 169 m_type = eSymbolTypeInvalid; 170 m_flags = 0; 171 m_addr_range.Clear(); 172} 173 174bool 175Symbol::ValueIsAddress() const 176{ 177 return m_addr_range.GetBaseAddress().GetSection().get() != NULL; 178} 179 180ConstString 181Symbol::GetReExportedSymbolName() const 182{ 183 if (m_type == eSymbolTypeReExported) 184 { 185 // For eSymbolTypeReExported, the "const char *" from a ConstString 186 // is used as the offset in the address range base address. We can 187 // then make this back into a string that is the re-exported name. 188 intptr_t str_ptr = m_addr_range.GetBaseAddress().GetOffset(); 189 if (str_ptr != 0) 190 return ConstString((const char *)str_ptr); 191 else 192 return GetName(); 193 } 194 return ConstString(); 195} 196 197FileSpec 198Symbol::GetReExportedSymbolSharedLibrary() const 199{ 200 if (m_type == eSymbolTypeReExported) 201 { 202 // For eSymbolTypeReExported, the "const char *" from a ConstString 203 // is used as the offset in the address range base address. We can 204 // then make this back into a string that is the re-exported name. 205 intptr_t str_ptr = m_addr_range.GetByteSize(); 206 if (str_ptr != 0) 207 return FileSpec((const char *)str_ptr, false); 208 } 209 return FileSpec(); 210} 211 212bool 213Symbol::SetReExportedSymbolName(const ConstString &name) 214{ 215 if (m_type == eSymbolTypeReExported) 216 { 217 // For eSymbolTypeReExported, the "const char *" from a ConstString 218 // is used as the offset in the address range base address. 219 m_addr_range.GetBaseAddress().SetOffset((intptr_t)name.GetCString()); 220 return true; 221 } 222 return false; 223 224} 225 226bool 227Symbol::SetReExportedSymbolSharedLibrary(const FileSpec &fspec) 228{ 229 if (m_type == eSymbolTypeReExported) 230 { 231 // For eSymbolTypeReExported, the "const char *" from a ConstString 232 // is used as the offset in the address range base address. 233 m_addr_range.SetByteSize((intptr_t)ConstString(fspec.GetPath().c_str()).GetCString()); 234 return true; 235 } 236 return false; 237 238} 239 240uint32_t 241Symbol::GetSiblingIndex() const 242{ 243 return m_size_is_sibling ? m_addr_range.GetByteSize() : 0; 244} 245 246bool 247Symbol::IsTrampoline () const 248{ 249 return m_type == eSymbolTypeTrampoline; 250} 251 252bool 253Symbol::IsIndirect () const 254{ 255 return m_type == eSymbolTypeResolver; 256} 257 258void 259Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const 260{ 261 s->Printf("id = {0x%8.8x}", m_uid); 262 263 if (m_addr_range.GetBaseAddress().GetSection()) 264 { 265 if (ValueIsAddress()) 266 { 267 const lldb::addr_t byte_size = GetByteSize(); 268 if (byte_size > 0) 269 { 270 s->PutCString (", range = "); 271 m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 272 } 273 else 274 { 275 s->PutCString (", address = "); 276 m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 277 } 278 } 279 else 280 s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); 281 } 282 else 283 { 284 if (m_size_is_sibling) 285 s->Printf (", sibling = %5" PRIu64, m_addr_range.GetBaseAddress().GetOffset()); 286 else 287 s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); 288 } 289 if (m_mangled.GetDemangledName()) 290 s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString()); 291 if (m_mangled.GetMangledName()) 292 s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString()); 293 294} 295 296void 297Symbol::Dump(Stream *s, Target *target, uint32_t index) const 298{ 299// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); 300// s->Indent(); 301// s->Printf("Symbol[%5u] %6u %c%c %-12s ", 302 s->Printf("[%5u] %6u %c%c%c %-12s ", 303 index, 304 GetID(), 305 m_is_debug ? 'D' : ' ', 306 m_is_synthetic ? 'S' : ' ', 307 m_is_external ? 'X' : ' ', 308 GetTypeAsString()); 309 310 // Make sure the size of the symbol is up to date before dumping 311 GetByteSize(); 312 313 if (ValueIsAddress()) 314 { 315 if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress)) 316 s->Printf("%*s", 18, ""); 317 318 s->PutChar(' '); 319 320 if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress)) 321 s->Printf("%*s", 18, ""); 322 323 const char *format = m_size_is_sibling ? 324 " Sibling -> [%5llu] 0x%8.8x %s\n": 325 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 326 s->Printf( format, 327 GetByteSize(), 328 m_flags, 329 m_mangled.GetName().AsCString("")); 330 } 331 else if (m_type == eSymbolTypeReExported) 332 { 333 s->Printf (" 0x%8.8x %s", 334 m_flags, 335 m_mangled.GetName().AsCString("")); 336 337 ConstString reexport_name = GetReExportedSymbolName(); 338 intptr_t shlib = m_addr_range.GetByteSize(); 339 if (shlib) 340 s->Printf(" -> %s`%s\n", (const char *)shlib, reexport_name.GetCString()); 341 else 342 s->Printf(" -> %s\n", reexport_name.GetCString()); 343 } 344 else 345 { 346 const char *format = m_size_is_sibling ? 347 "0x%16.16" PRIx64 " Sibling -> [%5llu] 0x%8.8x %s\n": 348 "0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x %s\n"; 349 s->Printf( format, 350 m_addr_range.GetBaseAddress().GetOffset(), 351 GetByteSize(), 352 m_flags, 353 m_mangled.GetName().AsCString("")); 354 } 355} 356 357uint32_t 358Symbol::GetPrologueByteSize () 359{ 360 if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver) 361 { 362 if (!m_type_data_resolved) 363 { 364 m_type_data_resolved = true; 365 366 const Address &base_address = m_addr_range.GetBaseAddress(); 367 Function *function = base_address.CalculateSymbolContextFunction(); 368 if (function) 369 { 370 // Functions have line entries which can also potentially have end of prologue information. 371 // So if this symbol points to a function, use the prologue information from there. 372 m_type_data = function->GetPrologueByteSize(); 373 } 374 else 375 { 376 ModuleSP module_sp (base_address.GetModule()); 377 SymbolContext sc; 378 if (module_sp) 379 { 380 uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address, 381 eSymbolContextLineEntry, 382 sc); 383 if (resolved_flags & eSymbolContextLineEntry) 384 { 385 // Default to the end of the first line entry. 386 m_type_data = sc.line_entry.range.GetByteSize(); 387 388 // Set address for next line. 389 Address addr (base_address); 390 addr.Slide (m_type_data); 391 392 // Check the first few instructions and look for one that has a line number that is 393 // different than the first entry. This is also done in Function::GetPrologueByteSize(). 394 uint16_t total_offset = m_type_data; 395 for (int idx = 0; idx < 6; ++idx) 396 { 397 SymbolContext sc_temp; 398 resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp); 399 // Make sure we got line number information... 400 if (!(resolved_flags & eSymbolContextLineEntry)) 401 break; 402 403 // If this line number is different than our first one, use it and we're done. 404 if (sc_temp.line_entry.line != sc.line_entry.line) 405 { 406 m_type_data = total_offset; 407 break; 408 } 409 410 // Slide addr up to the next line address. 411 addr.Slide (sc_temp.line_entry.range.GetByteSize()); 412 total_offset += sc_temp.line_entry.range.GetByteSize(); 413 // If we've gone too far, bail out. 414 if (total_offset >= m_addr_range.GetByteSize()) 415 break; 416 } 417 418 // Sanity check - this may be a function in the middle of code that has debug information, but 419 // not for this symbol. So the line entries surrounding us won't lie inside our function. 420 // In that case, the line entry will be bigger than we are, so we do that quick check and 421 // if that is true, we just return 0. 422 if (m_type_data >= m_addr_range.GetByteSize()) 423 m_type_data = 0; 424 } 425 else 426 { 427 // TODO: expose something in Process to figure out the 428 // size of a function prologue. 429 m_type_data = 0; 430 } 431 } 432 } 433 } 434 return m_type_data; 435 } 436 return 0; 437} 438 439bool 440Symbol::Compare(const ConstString& name, SymbolType type) const 441{ 442 if (type == eSymbolTypeAny || m_type == type) 443 return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name; 444 return false; 445} 446 447#define ENUM_TO_CSTRING(x) case eSymbolType##x: return #x; 448 449const char * 450Symbol::GetTypeAsString() const 451{ 452 switch (m_type) 453 { 454 ENUM_TO_CSTRING(Invalid); 455 ENUM_TO_CSTRING(Absolute); 456 ENUM_TO_CSTRING(Code); 457 ENUM_TO_CSTRING(Resolver); 458 ENUM_TO_CSTRING(Data); 459 ENUM_TO_CSTRING(Trampoline); 460 ENUM_TO_CSTRING(Runtime); 461 ENUM_TO_CSTRING(Exception); 462 ENUM_TO_CSTRING(SourceFile); 463 ENUM_TO_CSTRING(HeaderFile); 464 ENUM_TO_CSTRING(ObjectFile); 465 ENUM_TO_CSTRING(CommonBlock); 466 ENUM_TO_CSTRING(Block); 467 ENUM_TO_CSTRING(Local); 468 ENUM_TO_CSTRING(Param); 469 ENUM_TO_CSTRING(Variable); 470 ENUM_TO_CSTRING(VariableType); 471 ENUM_TO_CSTRING(LineEntry); 472 ENUM_TO_CSTRING(LineHeader); 473 ENUM_TO_CSTRING(ScopeBegin); 474 ENUM_TO_CSTRING(ScopeEnd); 475 ENUM_TO_CSTRING(Additional); 476 ENUM_TO_CSTRING(Compiler); 477 ENUM_TO_CSTRING(Instrumentation); 478 ENUM_TO_CSTRING(Undefined); 479 ENUM_TO_CSTRING(ObjCClass); 480 ENUM_TO_CSTRING(ObjCMetaClass); 481 ENUM_TO_CSTRING(ObjCIVar); 482 ENUM_TO_CSTRING(ReExported); 483 default: 484 break; 485 } 486 return "<unknown SymbolType>"; 487} 488 489void 490Symbol::CalculateSymbolContext (SymbolContext *sc) 491{ 492 // Symbols can reconstruct the symbol and the module in the symbol context 493 sc->symbol = this; 494 if (ValueIsAddress()) 495 sc->module_sp = GetAddress().GetModule(); 496 else 497 sc->module_sp.reset(); 498} 499 500ModuleSP 501Symbol::CalculateSymbolContextModule () 502{ 503 if (ValueIsAddress()) 504 return GetAddress().GetModule(); 505 return ModuleSP(); 506} 507 508Symbol * 509Symbol::CalculateSymbolContextSymbol () 510{ 511 return this; 512} 513 514void 515Symbol::DumpSymbolContext (Stream *s) 516{ 517 bool dumped_module = false; 518 if (ValueIsAddress()) 519 { 520 ModuleSP module_sp (GetAddress().GetModule()); 521 if (module_sp) 522 { 523 dumped_module = true; 524 module_sp->DumpSymbolContext(s); 525 } 526 } 527 if (dumped_module) 528 s->PutCString(", "); 529 530 s->Printf("Symbol{0x%8.8x}", GetID()); 531} 532 533lldb::addr_t 534Symbol::GetByteSize () const 535{ 536 return m_addr_range.GetByteSize(); 537} 538 539Symbol * 540Symbol::ResolveReExportedSymbol (Target &target) 541{ 542 ConstString reexport_name (GetReExportedSymbolName()); 543 if (reexport_name) 544 { 545 ModuleSpec module_spec; 546 ModuleSP module_sp; 547 module_spec.GetFileSpec() = GetReExportedSymbolSharedLibrary(); 548 if (module_spec.GetFileSpec()) 549 { 550 // Try searching for the module file spec first using the full path 551 module_sp = target.GetImages().FindFirstModule(module_spec); 552 if (!module_sp) 553 { 554 // Next try and find the module by basename in case environment 555 // variables or other runtime trickery causes shared libraries 556 // to be loaded from alternate paths 557 module_spec.GetFileSpec().GetDirectory().Clear(); 558 module_sp = target.GetImages().FindFirstModule(module_spec); 559 } 560 } 561 562 if (module_sp) 563 { 564 lldb_private::SymbolContextList sc_list; 565 module_sp->FindSymbolsWithNameAndType(reexport_name, eSymbolTypeAny, sc_list); 566 const size_t num_scs = sc_list.GetSize(); 567 if (num_scs > 0) 568 { 569 for (size_t i=0; i<num_scs; ++i) 570 { 571 lldb_private::SymbolContext sc; 572 if (sc_list.GetContextAtIndex(i, sc)) 573 { 574 if (sc.symbol->IsExternal()) 575 return sc.symbol; 576 } 577 } 578 } 579 } 580 } 581 return NULL; 582} 583