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