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