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