1 //===-- DYLDRendezvous.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 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 #include "lldb/Core/ArchSpec.h" 14 #include "lldb/Core/Error.h" 15 #include "lldb/Core/Log.h" 16 #include "lldb/Core/Module.h" 17 #include "lldb/Symbol/ObjectFile.h" 18 #include "lldb/Symbol/Symbol.h" 19 #include "lldb/Symbol/SymbolContext.h" 20 #include "lldb/Target/Platform.h" 21 #include "lldb/Target/Process.h" 22 #include "lldb/Target/Target.h" 23 24 #include "llvm/Support/Path.h" 25 26 #include "DYLDRendezvous.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 /// Locates the address of the rendezvous structure. Returns the address on 32 /// success and LLDB_INVALID_ADDRESS on failure. 33 static addr_t 34 ResolveRendezvousAddress(Process *process) 35 { 36 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 37 addr_t info_location; 38 addr_t info_addr; 39 Error error; 40 41 if (!process) 42 { 43 if (log) 44 log->Printf ("%s null process provided", __FUNCTION__); 45 return LLDB_INVALID_ADDRESS; 46 } 47 48 // Try to get it from our process. This might be a remote process and might 49 // grab it via some remote-specific mechanism. 50 info_location = process->GetImageInfoAddress(); 51 if (log) 52 log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); 53 54 // If the process fails to return an address, fall back to seeing if the local object file can help us find it. 55 if (info_location == LLDB_INVALID_ADDRESS) 56 { 57 Target *target = &process->GetTarget(); 58 if (target) 59 { 60 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); 61 Address addr = obj_file->GetImageInfoAddress(target); 62 63 if (addr.IsValid()) 64 { 65 info_location = addr.GetLoadAddress(target); 66 if (log) 67 log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location); 68 } 69 else 70 { 71 if (log) 72 log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__); 73 } 74 } 75 } 76 77 if (info_location == LLDB_INVALID_ADDRESS) 78 { 79 if (log) 80 log->Printf ("%s FAILED - invalid info address", __FUNCTION__); 81 return LLDB_INVALID_ADDRESS; 82 } 83 84 if (log) 85 log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location); 86 87 info_addr = process->ReadPointerFromMemory(info_location, error); 88 if (error.Fail()) 89 { 90 if (log) 91 log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ()); 92 return LLDB_INVALID_ADDRESS; 93 } 94 95 if (info_addr == 0) 96 { 97 if (log) 98 log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location); 99 return LLDB_INVALID_ADDRESS; 100 } 101 102 return info_addr; 103 } 104 105 DYLDRendezvous::DYLDRendezvous(Process *process) 106 : m_process(process), 107 m_rendezvous_addr(LLDB_INVALID_ADDRESS), 108 m_current(), 109 m_previous(), 110 m_loaded_modules(), 111 m_soentries(), 112 m_added_soentries(), 113 m_removed_soentries() 114 { 115 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 116 117 m_thread_info.valid = false; 118 119 // Cache a copy of the executable path 120 if (m_process) 121 { 122 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); 123 if (exe_mod) 124 { 125 m_exe_file_spec = exe_mod->GetPlatformFileSpec(); 126 if (log) 127 log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", 128 __FUNCTION__, m_exe_file_spec.GetCString()); 129 } 130 else 131 { 132 if (log) 133 log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__); 134 } 135 } 136 } 137 138 bool 139 DYLDRendezvous::Resolve() 140 { 141 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 142 143 const size_t word_size = 4; 144 Rendezvous info; 145 size_t address_size; 146 size_t padding; 147 addr_t info_addr; 148 addr_t cursor; 149 150 address_size = m_process->GetAddressByteSize(); 151 padding = address_size - word_size; 152 if (log) 153 log->Printf ("DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64, __FUNCTION__, uint64_t(address_size), uint64_t(padding)); 154 155 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) 156 cursor = info_addr = ResolveRendezvousAddress(m_process); 157 else 158 cursor = info_addr = m_rendezvous_addr; 159 if (log) 160 log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor); 161 162 if (cursor == LLDB_INVALID_ADDRESS) 163 return false; 164 165 if (!(cursor = ReadWord(cursor, &info.version, word_size))) 166 return false; 167 168 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) 169 return false; 170 171 if (!(cursor = ReadPointer(cursor, &info.brk))) 172 return false; 173 174 if (!(cursor = ReadWord(cursor, &info.state, word_size))) 175 return false; 176 177 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) 178 return false; 179 180 // The rendezvous was successfully read. Update our internal state. 181 m_rendezvous_addr = info_addr; 182 m_previous = m_current; 183 m_current = info; 184 185 if (UpdateSOEntries (true)) 186 return true; 187 188 return UpdateSOEntries(); 189 } 190 191 bool 192 DYLDRendezvous::IsValid() 193 { 194 return m_rendezvous_addr != LLDB_INVALID_ADDRESS; 195 } 196 197 bool 198 DYLDRendezvous::UpdateSOEntries(bool fromRemote) 199 { 200 SOEntry entry; 201 LoadedModuleInfoList module_list; 202 203 // If we can't get the SO info from the remote, return failure. 204 if (fromRemote && m_process->LoadModules (module_list) == 0) 205 return false; 206 207 if (!fromRemote && m_current.map_addr == 0) 208 return false; 209 210 // When the previous and current states are consistent this is the first 211 // time we have been asked to update. Just take a snapshot of the currently 212 // loaded modules. 213 if (m_previous.state == eConsistent && m_current.state == eConsistent) 214 return fromRemote ? SaveSOEntriesFromRemote(module_list) : TakeSnapshot(m_soentries); 215 216 // If we are about to add or remove a shared object clear out the current 217 // state and take a snapshot of the currently loaded images. 218 if (m_current.state == eAdd || m_current.state == eDelete) 219 { 220 // Some versions of the android dynamic linker might send two 221 // notifications with state == eAdd back to back. Ignore them 222 // until we get an eConsistent notification. 223 if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete))) 224 return false; 225 226 m_soentries.clear(); 227 if (fromRemote) 228 return SaveSOEntriesFromRemote(module_list); 229 230 m_added_soentries.clear(); 231 m_removed_soentries.clear(); 232 return TakeSnapshot(m_soentries); 233 } 234 assert(m_current.state == eConsistent); 235 236 // Otherwise check the previous state to determine what to expect and update 237 // accordingly. 238 if (m_previous.state == eAdd) 239 return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries(); 240 else if (m_previous.state == eDelete) 241 return fromRemote ? RemoveSOEntriesFromRemote(module_list) : RemoveSOEntries(); 242 243 return false; 244 } 245 246 bool 247 DYLDRendezvous::FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, 248 SOEntry &entry) 249 { 250 addr_t link_map_addr; 251 addr_t base_addr; 252 addr_t dyn_addr; 253 std::string name; 254 255 if (!modInfo.get_link_map (link_map_addr) || 256 !modInfo.get_base (base_addr) || 257 !modInfo.get_dynamic (dyn_addr) || 258 !modInfo.get_name (name)) 259 return false; 260 261 entry.link_addr = link_map_addr; 262 entry.base_addr = base_addr; 263 entry.dyn_addr = dyn_addr; 264 265 entry.file_spec.SetFile(name, false); 266 267 UpdateBaseAddrIfNecessary(entry, name); 268 269 // not needed if we're using ModuleInfos 270 entry.next = 0; 271 entry.prev = 0; 272 entry.path_addr = 0; 273 274 return true; 275 } 276 277 bool 278 DYLDRendezvous::SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list) 279 { 280 for (auto const & modInfo : module_list.m_list) 281 { 282 SOEntry entry; 283 if (!FillSOEntryFromModuleInfo(modInfo, entry)) 284 return false; 285 286 // Only add shared libraries and not the executable. 287 if (!SOEntryIsMainExecutable(entry)) 288 m_soentries.push_back(entry); 289 } 290 291 m_loaded_modules = module_list; 292 return true; 293 294 } 295 296 bool 297 DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) 298 { 299 for (auto const & modInfo : module_list.m_list) 300 { 301 bool found = false; 302 for (auto const & existing : m_loaded_modules.m_list) 303 { 304 if (modInfo == existing) 305 { 306 found = true; 307 break; 308 } 309 } 310 311 if (found) 312 continue; 313 314 SOEntry entry; 315 if (!FillSOEntryFromModuleInfo(modInfo, entry)) 316 return false; 317 318 // Only add shared libraries and not the executable. 319 if (!SOEntryIsMainExecutable(entry)) 320 m_soentries.push_back(entry); 321 } 322 323 m_loaded_modules = module_list; 324 return true; 325 } 326 327 bool 328 DYLDRendezvous::RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list) 329 { 330 for (auto const & existing : m_loaded_modules.m_list) 331 { 332 bool found = false; 333 for (auto const & modInfo : module_list.m_list) 334 { 335 if (modInfo == existing) 336 { 337 found = true; 338 break; 339 } 340 } 341 342 if (found) 343 continue; 344 345 SOEntry entry; 346 if (!FillSOEntryFromModuleInfo(existing, entry)) 347 return false; 348 349 // Only add shared libraries and not the executable. 350 if (!SOEntryIsMainExecutable(entry)) 351 { 352 auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry); 353 if (pos == m_soentries.end()) 354 return false; 355 356 m_soentries.erase(pos); 357 } 358 } 359 360 m_loaded_modules = module_list; 361 return true; 362 } 363 364 bool 365 DYLDRendezvous::AddSOEntries() 366 { 367 SOEntry entry; 368 iterator pos; 369 370 assert(m_previous.state == eAdd); 371 372 if (m_current.map_addr == 0) 373 return false; 374 375 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) 376 { 377 if (!ReadSOEntryFromMemory(cursor, entry)) 378 return false; 379 380 // Only add shared libraries and not the executable. 381 if (SOEntryIsMainExecutable(entry)) 382 continue; 383 384 pos = std::find(m_soentries.begin(), m_soentries.end(), entry); 385 if (pos == m_soentries.end()) 386 { 387 m_soentries.push_back(entry); 388 m_added_soentries.push_back(entry); 389 } 390 } 391 392 return true; 393 } 394 395 bool 396 DYLDRendezvous::RemoveSOEntries() 397 { 398 SOEntryList entry_list; 399 iterator pos; 400 401 assert(m_previous.state == eDelete); 402 403 if (!TakeSnapshot(entry_list)) 404 return false; 405 406 for (iterator I = begin(); I != end(); ++I) 407 { 408 pos = std::find(entry_list.begin(), entry_list.end(), *I); 409 if (pos == entry_list.end()) 410 m_removed_soentries.push_back(*I); 411 } 412 413 m_soentries = entry_list; 414 return true; 415 } 416 417 bool 418 DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) 419 { 420 // On Linux the executable is indicated by an empty path in the entry. On 421 // FreeBSD and on Android it is the full path to the executable. 422 423 auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); 424 switch (triple.getOS()) 425 { 426 case llvm::Triple::FreeBSD: 427 return entry.file_spec == m_exe_file_spec; 428 case llvm::Triple::Linux: 429 if (triple.isAndroid()) 430 return entry.file_spec == m_exe_file_spec; 431 return !entry.file_spec; 432 default: 433 return false; 434 } 435 } 436 437 bool 438 DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) 439 { 440 SOEntry entry; 441 442 if (m_current.map_addr == 0) 443 return false; 444 445 // Clear previous entries since we are about to obtain an up to date list. 446 entry_list.clear(); 447 448 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) 449 { 450 if (!ReadSOEntryFromMemory(cursor, entry)) 451 return false; 452 453 // Only add shared libraries and not the executable. 454 if (SOEntryIsMainExecutable(entry)) 455 continue; 456 457 entry_list.push_back(entry); 458 } 459 460 return true; 461 } 462 463 addr_t 464 DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) 465 { 466 Error error; 467 468 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); 469 if (error.Fail()) 470 return 0; 471 472 return addr + size; 473 } 474 475 addr_t 476 DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) 477 { 478 Error error; 479 480 *dst = m_process->ReadPointerFromMemory(addr, error); 481 if (error.Fail()) 482 return 0; 483 484 return addr + m_process->GetAddressByteSize(); 485 } 486 487 std::string 488 DYLDRendezvous::ReadStringFromMemory(addr_t addr) 489 { 490 std::string str; 491 Error error; 492 493 if (addr == LLDB_INVALID_ADDRESS) 494 return std::string(); 495 496 m_process->ReadCStringFromMemory(addr, str, error); 497 498 return str; 499 } 500 501 // Returns true if the load bias reported by the linker is incorrect for the given entry. This 502 // function is used to handle cases where we want to work around a bug in the system linker. 503 static bool 504 isLoadBiasIncorrect(Target& target, const std::string& file_path) 505 { 506 // On Android L (API 21, 22) the load address of the "/system/bin/linker" isn't filled in 507 // correctly. 508 uint32_t os_major = 0, os_minor = 0, os_update = 0; 509 if (target.GetArchitecture().GetTriple().isAndroid() && 510 target.GetPlatform()->GetOSVersion(os_major, os_minor, os_update) && 511 (os_major == 21 || os_major == 22) && 512 (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64")) 513 { 514 return true; 515 } 516 517 return false; 518 } 519 520 void 521 DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path) 522 { 523 // If the load bias reported by the linker is incorrect then fetch the load address of the file 524 // from the proc file system. 525 if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) 526 { 527 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 528 bool is_loaded = false; 529 Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); 530 if (error.Success() && is_loaded) 531 entry.base_addr = load_addr; 532 } 533 } 534 535 bool 536 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) 537 { 538 entry.clear(); 539 540 entry.link_addr = addr; 541 542 if (!(addr = ReadPointer(addr, &entry.base_addr))) 543 return false; 544 545 // mips adds an extra load offset field to the link map struct on 546 // FreeBSD and NetBSD (need to validate other OSes). 547 // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57 548 const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); 549 if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD 550 || arch.GetTriple().getOS() == llvm::Triple::NetBSD) && 551 (arch.GetMachine() == llvm::Triple::mips || arch.GetMachine() == llvm::Triple::mipsel 552 || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::mips64el)) 553 { 554 addr_t mips_l_offs; 555 if (!(addr = ReadPointer(addr, &mips_l_offs))) 556 return false; 557 if (mips_l_offs != 0 && mips_l_offs != entry.base_addr) 558 return false; 559 } 560 561 if (!(addr = ReadPointer(addr, &entry.path_addr))) 562 return false; 563 564 if (!(addr = ReadPointer(addr, &entry.dyn_addr))) 565 return false; 566 567 if (!(addr = ReadPointer(addr, &entry.next))) 568 return false; 569 570 if (!(addr = ReadPointer(addr, &entry.prev))) 571 return false; 572 573 std::string file_path = ReadStringFromMemory(entry.path_addr); 574 entry.file_spec.SetFile(file_path, false); 575 576 UpdateBaseAddrIfNecessary(entry, file_path); 577 578 return true; 579 } 580 581 582 bool 583 DYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value) 584 { 585 Target& target = m_process->GetTarget(); 586 587 SymbolContextList list; 588 if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list)) 589 return false; 590 591 Address address = list[0].symbol->GetAddress(); 592 addr_t addr = address.GetLoadAddress (&target); 593 if (addr == LLDB_INVALID_ADDRESS) 594 return false; 595 596 Error error; 597 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error); 598 if (error.Fail()) 599 return false; 600 601 if (field == eSize) 602 value /= 8; // convert bits to bytes 603 604 return true; 605 } 606 607 const DYLDRendezvous::ThreadInfo& 608 DYLDRendezvous::GetThreadInfo() 609 { 610 if (!m_thread_info.valid) 611 { 612 bool ok = true; 613 614 ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset); 615 ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); 616 ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset); 617 ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset); 618 619 if (ok) 620 m_thread_info.valid = true; 621 } 622 623 return m_thread_info; 624 } 625 626 void 627 DYLDRendezvous::DumpToLog(Log *log) const 628 { 629 int state = GetState(); 630 631 if (!log) 632 return; 633 634 log->PutCString("DYLDRendezvous:"); 635 log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); 636 log->Printf(" Version: %" PRIu64, GetVersion()); 637 log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); 638 log->Printf(" Break : %" PRIx64, GetBreakAddress()); 639 log->Printf(" LDBase : %" PRIx64, GetLDBase()); 640 log->Printf(" State : %s", 641 (state == eConsistent) ? "consistent" : 642 (state == eAdd) ? "add" : 643 (state == eDelete) ? "delete" : "unknown"); 644 645 iterator I = begin(); 646 iterator E = end(); 647 648 if (I != E) 649 log->PutCString("DYLDRendezvous SOEntries:"); 650 651 for (int i = 1; I != E; ++I, ++i) 652 { 653 log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString()); 654 log->Printf(" Base : %" PRIx64, I->base_addr); 655 log->Printf(" Path : %" PRIx64, I->path_addr); 656 log->Printf(" Dyn : %" PRIx64, I->dyn_addr); 657 log->Printf(" Next : %" PRIx64, I->next); 658 log->Printf(" Prev : %" PRIx64, I->prev); 659 } 660 } 661