1 //===-- DynamicLoaderMacOS.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/Breakpoint/StoppointCallbackContext.h" 10 #include "lldb/Core/Debugger.h" 11 #include "lldb/Core/Module.h" 12 #include "lldb/Core/PluginManager.h" 13 #include "lldb/Core/Section.h" 14 #include "lldb/Symbol/ObjectFile.h" 15 #include "lldb/Symbol/SymbolVendor.h" 16 #include "lldb/Target/ABI.h" 17 #include "lldb/Target/SectionLoadList.h" 18 #include "lldb/Target/StackFrame.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Target/Thread.h" 21 #include "lldb/Utility/LLDBLog.h" 22 #include "lldb/Utility/Log.h" 23 #include "lldb/Utility/State.h" 24 25 #include "DynamicLoaderDarwin.h" 26 #include "DynamicLoaderMacOS.h" 27 28 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 29 30 using namespace lldb; 31 using namespace lldb_private; 32 33 // Create an instance of this class. This function is filled into the plugin 34 // info class that gets handed out by the plugin factory and allows the lldb to 35 // instantiate an instance of this class. 36 DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, 37 bool force) { 38 bool create = force; 39 if (!create) { 40 create = true; 41 Module *exe_module = process->GetTarget().GetExecutableModulePointer(); 42 if (exe_module) { 43 ObjectFile *object_file = exe_module->GetObjectFile(); 44 if (object_file) { 45 create = (object_file->GetStrata() == ObjectFile::eStrataUser); 46 } 47 } 48 49 if (create) { 50 const llvm::Triple &triple_ref = 51 process->GetTarget().GetArchitecture().GetTriple(); 52 switch (triple_ref.getOS()) { 53 case llvm::Triple::Darwin: 54 case llvm::Triple::MacOSX: 55 case llvm::Triple::IOS: 56 case llvm::Triple::TvOS: 57 case llvm::Triple::WatchOS: 58 case llvm::Triple::XROS: 59 case llvm::Triple::BridgeOS: 60 create = triple_ref.getVendor() == llvm::Triple::Apple; 61 break; 62 default: 63 create = false; 64 break; 65 } 66 } 67 } 68 69 if (!UseDYLDSPI(process)) { 70 create = false; 71 } 72 73 if (create) 74 return new DynamicLoaderMacOS(process); 75 return nullptr; 76 } 77 78 // Constructor 79 DynamicLoaderMacOS::DynamicLoaderMacOS(Process *process) 80 : DynamicLoaderDarwin(process), m_image_infos_stop_id(UINT32_MAX), 81 m_break_id(LLDB_INVALID_BREAK_ID), 82 m_dyld_handover_break_id(LLDB_INVALID_BREAK_ID), m_mutex(), 83 m_maybe_image_infos_address(LLDB_INVALID_ADDRESS), 84 m_libsystem_fully_initalized(false) {} 85 86 // Destructor 87 DynamicLoaderMacOS::~DynamicLoaderMacOS() { 88 if (LLDB_BREAK_ID_IS_VALID(m_break_id)) 89 m_process->GetTarget().RemoveBreakpointByID(m_break_id); 90 if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id)) 91 m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id); 92 } 93 94 bool DynamicLoaderMacOS::ProcessDidExec() { 95 std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); 96 bool did_exec = false; 97 if (m_process) { 98 // If we are stopped after an exec, we will have only one thread... 99 if (m_process->GetThreadList().GetSize() == 1) { 100 // Maybe we still have an image infos address around? If so see 101 // if that has changed, and if so we have exec'ed. 102 if (m_maybe_image_infos_address != LLDB_INVALID_ADDRESS) { 103 lldb::addr_t image_infos_address = m_process->GetImageInfoAddress(); 104 if (image_infos_address != m_maybe_image_infos_address) { 105 // We don't really have to reset this here, since we are going to 106 // call DoInitialImageFetch right away to handle the exec. But in 107 // case anybody looks at it in the meantime, it can't hurt. 108 m_maybe_image_infos_address = image_infos_address; 109 did_exec = true; 110 } 111 } 112 113 if (!did_exec) { 114 // See if we are stopped at '_dyld_start' 115 ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); 116 if (thread_sp) { 117 lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); 118 if (frame_sp) { 119 const Symbol *symbol = 120 frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; 121 if (symbol) { 122 if (symbol->GetName() == "_dyld_start") 123 did_exec = true; 124 } 125 } 126 } 127 } 128 } 129 } 130 131 if (did_exec) { 132 m_libpthread_module_wp.reset(); 133 m_pthread_getspecific_addr.Clear(); 134 m_libsystem_fully_initalized = false; 135 } 136 return did_exec; 137 } 138 139 // Clear out the state of this class. 140 void DynamicLoaderMacOS::DoClear() { 141 std::lock_guard<std::recursive_mutex> guard(m_mutex); 142 143 if (LLDB_BREAK_ID_IS_VALID(m_break_id)) 144 m_process->GetTarget().RemoveBreakpointByID(m_break_id); 145 if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id)) 146 m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id); 147 148 m_break_id = LLDB_INVALID_BREAK_ID; 149 m_dyld_handover_break_id = LLDB_INVALID_BREAK_ID; 150 m_libsystem_fully_initalized = false; 151 } 152 153 bool DynamicLoaderMacOS::IsFullyInitialized() { 154 if (m_libsystem_fully_initalized) 155 return true; 156 157 StructuredData::ObjectSP process_state_sp( 158 m_process->GetDynamicLoaderProcessState()); 159 if (!process_state_sp) 160 return true; 161 if (process_state_sp->GetAsDictionary()->HasKey("error")) 162 return true; 163 if (!process_state_sp->GetAsDictionary()->HasKey("process_state string")) 164 return true; 165 std::string proc_state = process_state_sp->GetAsDictionary() 166 ->GetValueForKey("process_state string") 167 ->GetAsString() 168 ->GetValue() 169 .str(); 170 if (proc_state == "dyld_process_state_not_started" || 171 proc_state == "dyld_process_state_dyld_initialized" || 172 proc_state == "dyld_process_state_terminated_before_inits") { 173 return false; 174 } 175 m_libsystem_fully_initalized = true; 176 return true; 177 } 178 179 // Check if we have found DYLD yet 180 bool DynamicLoaderMacOS::DidSetNotificationBreakpoint() { 181 return LLDB_BREAK_ID_IS_VALID(m_break_id); 182 } 183 184 void DynamicLoaderMacOS::ClearNotificationBreakpoint() { 185 if (LLDB_BREAK_ID_IS_VALID(m_break_id)) { 186 m_process->GetTarget().RemoveBreakpointByID(m_break_id); 187 m_break_id = LLDB_INVALID_BREAK_ID; 188 } 189 } 190 191 // Try and figure out where dyld is by first asking the Process if it knows 192 // (which currently calls down in the lldb::Process to get the DYLD info 193 // (available on SnowLeopard only). If that fails, then check in the default 194 // addresses. 195 void DynamicLoaderMacOS::DoInitialImageFetch() { 196 Log *log = GetLog(LLDBLog::DynamicLoader); 197 198 // Remove any binaries we pre-loaded in the Target before 199 // launching/attaching. If the same binaries are present in the process, 200 // we'll get them from the shared module cache, we won't need to re-load them 201 // from disk. 202 UnloadAllImages(); 203 204 StructuredData::ObjectSP all_image_info_json_sp( 205 m_process->GetLoadedDynamicLibrariesInfos()); 206 ImageInfo::collection image_infos; 207 if (all_image_info_json_sp.get() && 208 all_image_info_json_sp->GetAsDictionary() && 209 all_image_info_json_sp->GetAsDictionary()->HasKey("images") && 210 all_image_info_json_sp->GetAsDictionary() 211 ->GetValueForKey("images") 212 ->GetAsArray()) { 213 if (JSONImageInformationIntoImageInfo(all_image_info_json_sp, 214 image_infos)) { 215 LLDB_LOGF(log, "Initial module fetch: Adding %" PRId64 " modules.\n", 216 (uint64_t)image_infos.size()); 217 218 auto images = PreloadModulesFromImageInfos(image_infos); 219 UpdateSpecialBinariesFromPreloadedModules(images); 220 AddModulesUsingPreloadedModules(images); 221 } 222 } 223 224 m_dyld_image_infos_stop_id = m_process->GetStopID(); 225 m_maybe_image_infos_address = m_process->GetImageInfoAddress(); 226 } 227 228 bool DynamicLoaderMacOS::NeedToDoInitialImageFetch() { return true; } 229 230 // Static callback function that gets called when our DYLD notification 231 // breakpoint gets hit. We update all of our image infos and then let our super 232 // class DynamicLoader class decide if we should stop or not (based on global 233 // preference). 234 bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, 235 StoppointCallbackContext *context, 236 lldb::user_id_t break_id, 237 lldb::user_id_t break_loc_id) { 238 // 239 // Our breakpoint on 240 // 241 // void lldb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, 242 // const dyld_image_info info[]) 243 // 244 // has been hit. We need to read the arguments. 245 246 DynamicLoaderMacOS *dyld_instance = (DynamicLoaderMacOS *)baton; 247 248 ExecutionContext exe_ctx(context->exe_ctx_ref); 249 Process *process = exe_ctx.GetProcessPtr(); 250 251 // This is a sanity check just in case this dyld_instance is an old dyld 252 // plugin's breakpoint still lying around. 253 if (process != dyld_instance->m_process) 254 return false; 255 256 if (dyld_instance->m_image_infos_stop_id != UINT32_MAX && 257 process->GetStopID() < dyld_instance->m_image_infos_stop_id) { 258 return false; 259 } 260 261 const lldb::ABISP &abi = process->GetABI(); 262 if (abi) { 263 // Build up the value array to store the three arguments given above, then 264 // get the values from the ABI: 265 266 TypeSystemClangSP scratch_ts_sp = 267 ScratchTypeSystemClang::GetForTarget(process->GetTarget()); 268 if (!scratch_ts_sp) 269 return false; 270 271 ValueList argument_values; 272 273 Value mode_value; // enum dyld_notify_mode { dyld_notify_adding=0, 274 // dyld_notify_removing=1, dyld_notify_remove_all=2, 275 // dyld_notify_dyld_moved=3 }; 276 Value count_value; // uint32_t 277 Value headers_value; // struct dyld_image_info machHeaders[] 278 279 CompilerType clang_void_ptr_type = 280 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType(); 281 CompilerType clang_uint32_type = 282 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 283 32); 284 CompilerType clang_uint64_type = 285 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 286 32); 287 288 mode_value.SetValueType(Value::ValueType::Scalar); 289 mode_value.SetCompilerType(clang_uint32_type); 290 291 count_value.SetValueType(Value::ValueType::Scalar); 292 count_value.SetCompilerType(clang_uint32_type); 293 294 headers_value.SetValueType(Value::ValueType::Scalar); 295 headers_value.SetCompilerType(clang_void_ptr_type); 296 297 argument_values.PushValue(mode_value); 298 argument_values.PushValue(count_value); 299 argument_values.PushValue(headers_value); 300 301 if (abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values)) { 302 uint32_t dyld_mode = 303 argument_values.GetValueAtIndex(0)->GetScalar().UInt(-1); 304 if (dyld_mode != static_cast<uint32_t>(-1)) { 305 // Okay the mode was right, now get the number of elements, and the 306 // array of new elements... 307 uint32_t image_infos_count = 308 argument_values.GetValueAtIndex(1)->GetScalar().UInt(-1); 309 if (image_infos_count != static_cast<uint32_t>(-1)) { 310 addr_t header_array = 311 argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(-1); 312 if (header_array != static_cast<uint64_t>(-1)) { 313 std::vector<addr_t> image_load_addresses; 314 // header_array points to an array of image_infos_count elements, 315 // each is 316 // struct dyld_image_info { 317 // const struct mach_header* imageLoadAddress; 318 // const char* imageFilePath; 319 // uintptr_t imageFileModDate; 320 // }; 321 // 322 // and we only need the imageLoadAddress fields. 323 324 const int addrsize = 325 process->GetTarget().GetArchitecture().GetAddressByteSize(); 326 for (uint64_t i = 0; i < image_infos_count; i++) { 327 Status error; 328 addr_t dyld_image_info = header_array + (addrsize * 3 * i); 329 addr_t addr = 330 process->ReadPointerFromMemory(dyld_image_info, error); 331 if (error.Success()) { 332 image_load_addresses.push_back(addr); 333 } else { 334 Debugger::ReportWarning( 335 "DynamicLoaderMacOS::NotifyBreakpointHit unable " 336 "to read binary mach-o load address at 0x%" PRIx64, 337 addr); 338 } 339 } 340 if (dyld_mode == 0) { 341 // dyld_notify_adding 342 if (process->GetTarget().GetImages().GetSize() == 0) { 343 // When all images have been removed, we're doing the 344 // dyld handover from a launch-dyld to a shared-cache-dyld, 345 // and we've just hit our one-shot address breakpoint in 346 // the sc-dyld. Note that the image addresses passed to 347 // this function are inferior sizeof(void*) not uint64_t's 348 // like our normal notification, so don't even look at 349 // image_load_addresses. 350 351 dyld_instance->ClearDYLDHandoverBreakpoint(); 352 353 dyld_instance->DoInitialImageFetch(); 354 dyld_instance->SetNotificationBreakpoint(); 355 } else { 356 dyld_instance->AddBinaries(image_load_addresses); 357 } 358 } else if (dyld_mode == 1) { 359 // dyld_notify_removing 360 dyld_instance->UnloadImages(image_load_addresses); 361 } else if (dyld_mode == 2) { 362 // dyld_notify_remove_all 363 dyld_instance->UnloadAllImages(); 364 } else if (dyld_mode == 3 && image_infos_count == 1) { 365 // dyld_image_dyld_moved 366 367 dyld_instance->ClearNotificationBreakpoint(); 368 dyld_instance->UnloadAllImages(); 369 dyld_instance->ClearDYLDModule(); 370 process->GetTarget().GetImages().Clear(); 371 process->GetTarget().ClearSectionLoadList(); 372 373 addr_t all_image_infos = process->GetImageInfoAddress(); 374 int addr_size = 375 process->GetTarget().GetArchitecture().GetAddressByteSize(); 376 addr_t notification_location = all_image_infos + 4 + // version 377 4 + // infoArrayCount 378 addr_size; // infoArray 379 Status error; 380 addr_t notification_addr = 381 process->ReadPointerFromMemory(notification_location, error); 382 if (!error.Success()) { 383 Debugger::ReportWarning( 384 "DynamicLoaderMacOS::NotifyBreakpointHit unable " 385 "to read address of dyld-handover notification function at " 386 "0x%" PRIx64, 387 notification_location); 388 } else { 389 notification_addr = process->FixCodeAddress(notification_addr); 390 dyld_instance->SetDYLDHandoverBreakpoint(notification_addr); 391 } 392 } 393 } 394 } 395 } 396 } 397 } else { 398 Target &target = process->GetTarget(); 399 Debugger::ReportWarning( 400 "no ABI plugin located for triple " + 401 target.GetArchitecture().GetTriple().getTriple() + 402 ": shared libraries will not be registered", 403 target.GetDebugger().GetID()); 404 } 405 406 // Return true to stop the target, false to just let the target run 407 return dyld_instance->GetStopWhenImagesChange(); 408 } 409 410 void DynamicLoaderMacOS::AddBinaries( 411 const std::vector<lldb::addr_t> &load_addresses) { 412 Log *log = GetLog(LLDBLog::DynamicLoader); 413 ImageInfo::collection image_infos; 414 415 LLDB_LOGF(log, "Adding %" PRId64 " modules.", 416 (uint64_t)load_addresses.size()); 417 StructuredData::ObjectSP binaries_info_sp = 418 m_process->GetLoadedDynamicLibrariesInfos(load_addresses); 419 if (binaries_info_sp.get() && binaries_info_sp->GetAsDictionary() && 420 binaries_info_sp->GetAsDictionary()->HasKey("images") && 421 binaries_info_sp->GetAsDictionary() 422 ->GetValueForKey("images") 423 ->GetAsArray() && 424 binaries_info_sp->GetAsDictionary() 425 ->GetValueForKey("images") 426 ->GetAsArray() 427 ->GetSize() == load_addresses.size()) { 428 if (JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) { 429 auto images = PreloadModulesFromImageInfos(image_infos); 430 UpdateSpecialBinariesFromPreloadedModules(images); 431 AddModulesUsingPreloadedModules(images); 432 } 433 m_dyld_image_infos_stop_id = m_process->GetStopID(); 434 } 435 } 436 437 // Dump the _dyld_all_image_infos members and all current image infos that we 438 // have parsed to the file handle provided. 439 void DynamicLoaderMacOS::PutToLog(Log *log) const { 440 if (log == nullptr) 441 return; 442 } 443 444 // Look in dyld's dyld_all_image_infos structure for the address 445 // of the notification function. 446 // We can find the address of dyld_all_image_infos by a system 447 // call, even if we don't have a dyld binary registered in lldb's 448 // image list. 449 // At process launch time - before dyld has executed any instructions - 450 // the address of the notification function is not a resolved vm address 451 // yet. dyld_all_image_infos also has a field with its own address 452 // in it, and this will also be unresolved when we're at this state. 453 // So we can compare the address of the object with this field and if 454 // they differ, dyld hasn't started executing yet and we can't get the 455 // notification address this way. 456 addr_t DynamicLoaderMacOS::GetNotificationFuncAddrFromImageInfos() { 457 addr_t notification_addr = LLDB_INVALID_ADDRESS; 458 if (!m_process) 459 return notification_addr; 460 461 addr_t all_image_infos_addr = m_process->GetImageInfoAddress(); 462 if (all_image_infos_addr == LLDB_INVALID_ADDRESS) 463 return notification_addr; 464 465 const uint32_t addr_size = 466 m_process->GetTarget().GetArchitecture().GetAddressByteSize(); 467 offset_t registered_infos_addr_offset = 468 sizeof(uint32_t) + // version 469 sizeof(uint32_t) + // infoArrayCount 470 addr_size + // infoArray 471 addr_size + // notification 472 addr_size + // processDetachedFromSharedRegion + 473 // libSystemInitialized + pad 474 addr_size + // dyldImageLoadAddress 475 addr_size + // jitInfo 476 addr_size + // dyldVersion 477 addr_size + // errorMessage 478 addr_size + // terminationFlags 479 addr_size + // coreSymbolicationShmPage 480 addr_size + // systemOrderFlag 481 addr_size + // uuidArrayCount 482 addr_size; // uuidArray 483 // dyldAllImageInfosAddress 484 485 // If the dyldAllImageInfosAddress does not match 486 // the actual address of this struct, dyld has not started 487 // executing yet. The 'notification' field can't be used by 488 // lldb until it's resolved to an actual address. 489 Status error; 490 addr_t registered_infos_addr = m_process->ReadPointerFromMemory( 491 all_image_infos_addr + registered_infos_addr_offset, error); 492 if (!error.Success()) 493 return notification_addr; 494 if (registered_infos_addr != all_image_infos_addr) 495 return notification_addr; 496 497 offset_t notification_fptr_offset = sizeof(uint32_t) + // version 498 sizeof(uint32_t) + // infoArrayCount 499 addr_size; // infoArray 500 501 addr_t notification_fptr = m_process->ReadPointerFromMemory( 502 all_image_infos_addr + notification_fptr_offset, error); 503 if (error.Success()) 504 notification_addr = m_process->FixCodeAddress(notification_fptr); 505 return notification_addr; 506 } 507 508 // We want to put a breakpoint on dyld's lldb_image_notifier() 509 // but we may have attached to the process during the 510 // transition from on-disk-dyld to shared-cache-dyld, so there's 511 // officially no dyld binary loaded in the process (libdyld will 512 // report none when asked), but the kernel can find the dyld_all_image_infos 513 // struct and the function pointer for lldb_image_notifier is in 514 // that struct. 515 bool DynamicLoaderMacOS::SetNotificationBreakpoint() { 516 517 // First try to find the notification breakpoint function by name 518 if (m_break_id == LLDB_INVALID_BREAK_ID) { 519 ModuleSP dyld_sp(GetDYLDModule()); 520 if (dyld_sp) { 521 bool internal = true; 522 bool hardware = false; 523 LazyBool skip_prologue = eLazyBoolNo; 524 FileSpecList *source_files = nullptr; 525 FileSpecList dyld_filelist; 526 dyld_filelist.Append(dyld_sp->GetFileSpec()); 527 528 Breakpoint *breakpoint = 529 m_process->GetTarget() 530 .CreateBreakpoint(&dyld_filelist, source_files, 531 "lldb_image_notifier", eFunctionNameTypeFull, 532 eLanguageTypeUnknown, 0, skip_prologue, 533 internal, hardware) 534 .get(); 535 breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, 536 true); 537 breakpoint->SetBreakpointKind("shared-library-event"); 538 if (breakpoint->HasResolvedLocations()) 539 m_break_id = breakpoint->GetID(); 540 else 541 m_process->GetTarget().RemoveBreakpointByID(breakpoint->GetID()); 542 543 if (m_break_id == LLDB_INVALID_BREAK_ID) { 544 Breakpoint *breakpoint = 545 m_process->GetTarget() 546 .CreateBreakpoint(&dyld_filelist, source_files, 547 "gdb_image_notifier", eFunctionNameTypeFull, 548 eLanguageTypeUnknown, 0, skip_prologue, 549 internal, hardware) 550 .get(); 551 breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, 552 true); 553 breakpoint->SetBreakpointKind("shared-library-event"); 554 if (breakpoint->HasResolvedLocations()) 555 m_break_id = breakpoint->GetID(); 556 else 557 m_process->GetTarget().RemoveBreakpointByID(breakpoint->GetID()); 558 } 559 } 560 } 561 562 // Failing that, find dyld_all_image_infos struct in memory, 563 // read the notification function pointer at the offset. 564 if (m_break_id == LLDB_INVALID_BREAK_ID) { 565 addr_t notification_addr = GetNotificationFuncAddrFromImageInfos(); 566 if (notification_addr != LLDB_INVALID_ADDRESS) { 567 Address so_addr; 568 // We may not have a dyld binary mapped to this address yet; 569 // don't try to express the Address object as section+offset, 570 // only as a raw load address. 571 so_addr.SetRawAddress(notification_addr); 572 Breakpoint *dyld_break = 573 m_process->GetTarget().CreateBreakpoint(so_addr, true, false).get(); 574 dyld_break->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, 575 true); 576 dyld_break->SetBreakpointKind("shared-library-event"); 577 if (dyld_break->HasResolvedLocations()) 578 m_break_id = dyld_break->GetID(); 579 else 580 m_process->GetTarget().RemoveBreakpointByID(dyld_break->GetID()); 581 } 582 } 583 return m_break_id != LLDB_INVALID_BREAK_ID; 584 } 585 586 bool DynamicLoaderMacOS::SetDYLDHandoverBreakpoint( 587 addr_t notification_address) { 588 if (m_dyld_handover_break_id == LLDB_INVALID_BREAK_ID) { 589 BreakpointSP dyld_handover_bp = m_process->GetTarget().CreateBreakpoint( 590 notification_address, true, false); 591 dyld_handover_bp->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, 592 true); 593 dyld_handover_bp->SetOneShot(true); 594 m_dyld_handover_break_id = dyld_handover_bp->GetID(); 595 return true; 596 } 597 return false; 598 } 599 600 void DynamicLoaderMacOS::ClearDYLDHandoverBreakpoint() { 601 if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id)) 602 m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id); 603 m_dyld_handover_break_id = LLDB_INVALID_BREAK_ID; 604 } 605 606 addr_t 607 DynamicLoaderMacOS::GetDyldLockVariableAddressFromModule(Module *module) { 608 SymbolContext sc; 609 Target &target = m_process->GetTarget(); 610 if (Symtab *symtab = module->GetSymtab()) { 611 std::vector<uint32_t> match_indexes; 612 ConstString g_symbol_name("_dyld_global_lock_held"); 613 uint32_t num_matches = 0; 614 num_matches = 615 symtab->AppendSymbolIndexesWithName(g_symbol_name, match_indexes); 616 if (num_matches == 1) { 617 Symbol *symbol = symtab->SymbolAtIndex(match_indexes[0]); 618 if (symbol && 619 (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) { 620 return symbol->GetAddressRef().GetOpcodeLoadAddress(&target); 621 } 622 } 623 } 624 return LLDB_INVALID_ADDRESS; 625 } 626 627 // Look for this symbol: 628 // 629 // int __attribute__((visibility("hidden"))) _dyld_global_lock_held = 630 // 0; 631 // 632 // in libdyld.dylib. 633 Status DynamicLoaderMacOS::CanLoadImage() { 634 Status error; 635 addr_t symbol_address = LLDB_INVALID_ADDRESS; 636 ConstString g_libdyld_name("libdyld.dylib"); 637 Target &target = m_process->GetTarget(); 638 const ModuleList &target_modules = target.GetImages(); 639 std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); 640 641 // Find any modules named "libdyld.dylib" and look for the symbol there first 642 for (ModuleSP module_sp : target.GetImages().ModulesNoLocking()) { 643 if (module_sp) { 644 if (module_sp->GetFileSpec().GetFilename() == g_libdyld_name) { 645 symbol_address = GetDyldLockVariableAddressFromModule(module_sp.get()); 646 if (symbol_address != LLDB_INVALID_ADDRESS) 647 break; 648 } 649 } 650 } 651 652 // Search through all modules looking for the symbol in them 653 if (symbol_address == LLDB_INVALID_ADDRESS) { 654 for (ModuleSP module_sp : target.GetImages().Modules()) { 655 if (module_sp) { 656 addr_t symbol_address = 657 GetDyldLockVariableAddressFromModule(module_sp.get()); 658 if (symbol_address != LLDB_INVALID_ADDRESS) 659 break; 660 } 661 } 662 } 663 664 // Default assumption is that it is OK to load images. Only say that we 665 // cannot load images if we find the symbol in libdyld and it indicates that 666 // we cannot. 667 668 if (symbol_address != LLDB_INVALID_ADDRESS) { 669 { 670 int lock_held = 671 m_process->ReadUnsignedIntegerFromMemory(symbol_address, 4, 0, error); 672 if (lock_held != 0) { 673 error = 674 Status::FromErrorString("dyld lock held - unsafe to load images."); 675 } 676 } 677 } else { 678 // If we were unable to find _dyld_global_lock_held in any modules, or it 679 // is not loaded into memory yet, we may be at process startup (sitting at 680 // _dyld_start) - so we should not allow dlopen calls. But if we found more 681 // than one module then we are clearly past _dyld_start so in that case 682 // we'll default to "it's safe". 683 if (target.GetImages().GetSize() <= 1) 684 error = Status::FromErrorString("could not find the dyld library or " 685 "the dyld lock symbol"); 686 } 687 return error; 688 } 689 690 bool DynamicLoaderMacOS::GetSharedCacheInformation( 691 lldb::addr_t &base_address, UUID &uuid, LazyBool &using_shared_cache, 692 LazyBool &private_shared_cache) { 693 base_address = LLDB_INVALID_ADDRESS; 694 uuid.Clear(); 695 using_shared_cache = eLazyBoolCalculate; 696 private_shared_cache = eLazyBoolCalculate; 697 698 if (m_process) { 699 StructuredData::ObjectSP info = m_process->GetSharedCacheInfo(); 700 StructuredData::Dictionary *info_dict = nullptr; 701 if (info.get() && info->GetAsDictionary()) { 702 info_dict = info->GetAsDictionary(); 703 } 704 705 // {"shared_cache_base_address":140735683125248,"shared_cache_uuid 706 // ":"DDB8D70C- 707 // C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false} 708 709 if (info_dict && info_dict->HasKey("shared_cache_uuid") && 710 info_dict->HasKey("no_shared_cache") && 711 info_dict->HasKey("shared_cache_base_address")) { 712 base_address = info_dict->GetValueForKey("shared_cache_base_address") 713 ->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS); 714 std::string uuid_str = std::string( 715 info_dict->GetValueForKey("shared_cache_uuid")->GetStringValue()); 716 if (!uuid_str.empty()) 717 uuid.SetFromStringRef(uuid_str); 718 if (!info_dict->GetValueForKey("no_shared_cache")->GetBooleanValue()) 719 using_shared_cache = eLazyBoolYes; 720 else 721 using_shared_cache = eLazyBoolNo; 722 if (info_dict->GetValueForKey("shared_cache_private_cache") 723 ->GetBooleanValue()) 724 private_shared_cache = eLazyBoolYes; 725 else 726 private_shared_cache = eLazyBoolNo; 727 728 return true; 729 } 730 } 731 return false; 732 } 733 734 void DynamicLoaderMacOS::Initialize() { 735 PluginManager::RegisterPlugin(GetPluginNameStatic(), 736 GetPluginDescriptionStatic(), CreateInstance); 737 } 738 739 void DynamicLoaderMacOS::Terminate() { 740 PluginManager::UnregisterPlugin(CreateInstance); 741 } 742 743 llvm::StringRef DynamicLoaderMacOS::GetPluginDescriptionStatic() { 744 return "Dynamic loader plug-in that watches for shared library loads/unloads " 745 "in MacOSX user processes."; 746 } 747