1 //===-- DynamicLoaderMacOS.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 #include "lldb/Breakpoint/StoppointCallbackContext.h" 11 #include "lldb/Core/Debugger.h" 12 #include "lldb/Core/Log.h" 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/Section.h" 16 #include "lldb/Core/State.h" 17 #include "lldb/Symbol/ClangASTContext.h" 18 #include "lldb/Symbol/SymbolVendor.h" 19 #include "lldb/Symbol/ObjectFile.h" 20 #include "lldb/Target/ABI.h" 21 #include "lldb/Target/Target.h" 22 #include "lldb/Target/Thread.h" 23 #include "lldb/Target/StackFrame.h" 24 25 #include "DynamicLoaderMacOS.h" 26 #include "DynamicLoaderDarwin.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 32 //---------------------------------------------------------------------- 33 // Create an instance of this class. This function is filled into 34 // the plugin info class that gets handed out by the plugin factory and 35 // allows the lldb to instantiate an instance of this class. 36 //---------------------------------------------------------------------- 37 DynamicLoader * 38 DynamicLoaderMacOS::CreateInstance (Process* process, bool force) 39 { 40 bool create = force; 41 if (!create) 42 { 43 create = true; 44 Module* exe_module = process->GetTarget().GetExecutableModulePointer(); 45 if (exe_module) 46 { 47 ObjectFile *object_file = exe_module->GetObjectFile(); 48 if (object_file) 49 { 50 create = (object_file->GetStrata() == ObjectFile::eStrataUser); 51 } 52 } 53 54 if (create) 55 { 56 const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); 57 switch (triple_ref.getOS()) 58 { 59 case llvm::Triple::Darwin: 60 case llvm::Triple::MacOSX: 61 case llvm::Triple::IOS: 62 case llvm::Triple::TvOS: 63 case llvm::Triple::WatchOS: 64 create = triple_ref.getVendor() == llvm::Triple::Apple; 65 break; 66 default: 67 create = false; 68 break; 69 } 70 } 71 } 72 73 if (UseDYLDSPI (process) == false) 74 { 75 create = false; 76 } 77 78 if (create) 79 return new DynamicLoaderMacOS (process); 80 return NULL; 81 } 82 83 //---------------------------------------------------------------------- 84 // Constructor 85 //---------------------------------------------------------------------- 86 DynamicLoaderMacOS::DynamicLoaderMacOS (Process* process) : 87 DynamicLoaderDarwin(process), 88 m_image_infos_stop_id (UINT32_MAX), 89 m_break_id(LLDB_INVALID_BREAK_ID), 90 m_mutex() 91 { 92 } 93 94 //---------------------------------------------------------------------- 95 // Destructor 96 //---------------------------------------------------------------------- 97 DynamicLoaderMacOS::~DynamicLoaderMacOS() 98 { 99 if (LLDB_BREAK_ID_IS_VALID(m_break_id)) 100 m_process->GetTarget().RemoveBreakpointByID (m_break_id); 101 } 102 103 bool 104 DynamicLoaderMacOS::ProcessDidExec () 105 { 106 std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); 107 bool did_exec = false; 108 if (m_process) 109 { 110 // If we are stopped after an exec, we will have only one thread... 111 if (m_process->GetThreadList().GetSize() == 1) 112 { 113 // See if we are stopped at '_dyld_start' 114 ThreadSP thread_sp (m_process->GetThreadList().GetThreadAtIndex(0)); 115 if (thread_sp) 116 { 117 lldb::StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex(0)); 118 if (frame_sp) 119 { 120 const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; 121 if (symbol) 122 { 123 if (symbol->GetName() == ConstString("_dyld_start")) 124 did_exec = true; 125 } 126 } 127 } 128 129 } 130 } 131 132 if (did_exec) 133 { 134 m_libpthread_module_wp.reset(); 135 m_pthread_getspecific_addr.Clear(); 136 } 137 return did_exec; 138 } 139 140 //---------------------------------------------------------------------- 141 // Clear out the state of this class. 142 //---------------------------------------------------------------------- 143 void 144 DynamicLoaderMacOS::DoClear () 145 { 146 std::lock_guard<std::recursive_mutex> guard(m_mutex); 147 148 if (LLDB_BREAK_ID_IS_VALID(m_break_id)) 149 m_process->GetTarget().RemoveBreakpointByID (m_break_id); 150 151 m_break_id = LLDB_INVALID_BREAK_ID; 152 } 153 154 //---------------------------------------------------------------------- 155 // Check if we have found DYLD yet 156 //---------------------------------------------------------------------- 157 bool 158 DynamicLoaderMacOS::DidSetNotificationBreakpoint() 159 { 160 return LLDB_BREAK_ID_IS_VALID (m_break_id); 161 } 162 163 void 164 DynamicLoaderMacOS::ClearNotificationBreakpoint () 165 { 166 if (LLDB_BREAK_ID_IS_VALID (m_break_id)) 167 { 168 m_process->GetTarget().RemoveBreakpointByID (m_break_id); 169 } 170 } 171 172 //---------------------------------------------------------------------- 173 // Try and figure out where dyld is by first asking the Process 174 // if it knows (which currently calls down in the lldb::Process 175 // to get the DYLD info (available on SnowLeopard only). If that fails, 176 // then check in the default addresses. 177 //---------------------------------------------------------------------- 178 void 179 DynamicLoaderMacOS::DoInitialImageFetch() 180 { 181 Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); 182 183 StructuredData::ObjectSP all_image_info_json_sp (m_process->GetLoadedDynamicLibrariesInfos ()); 184 ImageInfo::collection image_infos; 185 if (all_image_info_json_sp.get() 186 && all_image_info_json_sp->GetAsDictionary() 187 && all_image_info_json_sp->GetAsDictionary()->HasKey("images") 188 && all_image_info_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()) 189 { 190 if (JSONImageInformationIntoImageInfo (all_image_info_json_sp, image_infos)) 191 { 192 if (log) 193 log->Printf ("Initial module fetch: Adding %" PRId64 " modules.\n", (uint64_t) image_infos.size()); 194 195 UpdateSpecialBinariesFromNewImageInfos (image_infos); 196 AddModulesUsingImageInfos (image_infos); 197 } 198 } 199 200 m_dyld_image_infos_stop_id = m_process->GetStopID(); 201 } 202 203 bool 204 DynamicLoaderMacOS::NeedToDoInitialImageFetch () 205 { 206 return true; 207 } 208 209 //---------------------------------------------------------------------- 210 // Static callback function that gets called when our DYLD notification 211 // breakpoint gets hit. We update all of our image infos and then 212 // let our super class DynamicLoader class decide if we should stop 213 // or not (based on global preference). 214 //---------------------------------------------------------------------- 215 bool 216 DynamicLoaderMacOS::NotifyBreakpointHit (void *baton, 217 StoppointCallbackContext *context, 218 lldb::user_id_t break_id, 219 lldb::user_id_t break_loc_id) 220 { 221 // Let the event know that the images have changed 222 // DYLD passes three arguments to the notification breakpoint. 223 // Arg1: enum dyld_notify_mode mode - 0 = adding, 1 = removing, 2 = remove all 224 // Arg2: unsigned long icount - Number of shared libraries added/removed 225 // Arg3: uint64_t mach_headers[] - Array of load addresses of binaries added/removed 226 227 DynamicLoaderMacOS* dyld_instance = (DynamicLoaderMacOS*) baton; 228 229 ExecutionContext exe_ctx (context->exe_ctx_ref); 230 Process *process = exe_ctx.GetProcessPtr(); 231 232 // This is a sanity check just in case this dyld_instance is an old dyld plugin's breakpoint still lying around. 233 if (process != dyld_instance->m_process) 234 return false; 235 236 if (dyld_instance->m_image_infos_stop_id != UINT32_MAX 237 && process->GetStopID() < dyld_instance->m_image_infos_stop_id) 238 { 239 return false; 240 } 241 242 const lldb::ABISP &abi = process->GetABI(); 243 if (abi) 244 { 245 // Build up the value array to store the three arguments given above, then get the values from the ABI: 246 247 ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); 248 ValueList argument_values; 249 250 Value mode_value; // enum dyld_notify_mode { dyld_notify_adding=0, dyld_notify_removing=1, dyld_notify_remove_all=2 }; 251 Value count_value; // unsigned long count 252 Value headers_value; // uint64_t machHeaders[] (aka void*) 253 254 CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); 255 CompilerType clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 32); 256 CompilerType clang_uint64_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 32); 257 258 mode_value.SetValueType (Value::eValueTypeScalar); 259 mode_value.SetCompilerType (clang_uint32_type); 260 261 if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 4) 262 { 263 count_value.SetValueType (Value::eValueTypeScalar); 264 count_value.SetCompilerType (clang_uint32_type); 265 } 266 else 267 { 268 count_value.SetValueType (Value::eValueTypeScalar); 269 count_value.SetCompilerType (clang_uint64_type); 270 } 271 272 headers_value.SetValueType (Value::eValueTypeScalar); 273 headers_value.SetCompilerType (clang_void_ptr_type); 274 275 argument_values.PushValue (mode_value); 276 argument_values.PushValue (count_value); 277 argument_values.PushValue (headers_value); 278 279 if (abi->GetArgumentValues (exe_ctx.GetThreadRef(), argument_values)) 280 { 281 uint32_t dyld_mode = argument_values.GetValueAtIndex(0)->GetScalar().UInt (-1); 282 if (dyld_mode != static_cast<uint32_t>(-1)) 283 { 284 // Okay the mode was right, now get the number of elements, and the array of new elements... 285 uint32_t image_infos_count = argument_values.GetValueAtIndex(1)->GetScalar().UInt (-1); 286 if (image_infos_count != static_cast<uint32_t>(-1)) 287 { 288 addr_t header_array = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(-1); 289 if (header_array != static_cast<uint64_t>(-1)) 290 { 291 std::vector<addr_t> image_load_addresses; 292 for (uint64_t i = 0; i < image_infos_count ; i++) 293 { 294 Error error; 295 addr_t addr = process->ReadUnsignedIntegerFromMemory (header_array + (8 * i), 8, LLDB_INVALID_ADDRESS, error); 296 if (addr != LLDB_INVALID_ADDRESS) 297 { 298 image_load_addresses.push_back (addr); 299 } 300 } 301 if (dyld_mode == 0) 302 { 303 // dyld_notify_adding 304 dyld_instance->AddBinaries (image_load_addresses); 305 } 306 else if (dyld_mode == 1) 307 { 308 // dyld_notify_removing 309 dyld_instance->UnloadImages (image_load_addresses); 310 } 311 else if (dyld_mode == 2) 312 { 313 // dyld_notify_remove_all 314 dyld_instance->UnloadAllImages (); 315 } 316 } 317 } 318 } 319 } 320 } 321 else 322 { 323 process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf("No ABI plugin located for triple %s -- shared libraries will not be registered!\n", process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); 324 } 325 326 // Return true to stop the target, false to just let the target run 327 return dyld_instance->GetStopWhenImagesChange(); 328 } 329 330 void 331 DynamicLoaderMacOS::AddBinaries (const std::vector<lldb::addr_t> &load_addresses) 332 { 333 Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); 334 ImageInfo::collection image_infos; 335 336 if (log) 337 log->Printf ("Adding %" PRId64 " modules.", (uint64_t) load_addresses.size()); 338 StructuredData::ObjectSP binaries_info_sp = m_process->GetLoadedDynamicLibrariesInfos (load_addresses); 339 if (binaries_info_sp.get() 340 && binaries_info_sp->GetAsDictionary() 341 && binaries_info_sp->GetAsDictionary()->HasKey("images") 342 && binaries_info_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray() 343 && binaries_info_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()->GetSize() == load_addresses.size()) 344 { 345 if (JSONImageInformationIntoImageInfo (binaries_info_sp, image_infos)) 346 { 347 UpdateSpecialBinariesFromNewImageInfos (image_infos); 348 AddModulesUsingImageInfos (image_infos); 349 } 350 m_dyld_image_infos_stop_id = m_process->GetStopID(); 351 } 352 } 353 354 355 // Dump the _dyld_all_image_infos members and all current image infos 356 // that we have parsed to the file handle provided. 357 //---------------------------------------------------------------------- 358 void 359 DynamicLoaderMacOS::PutToLog(Log *log) const 360 { 361 if (log == NULL) 362 return; 363 } 364 365 bool 366 DynamicLoaderMacOS::SetNotificationBreakpoint () 367 { 368 if (m_break_id == LLDB_INVALID_BREAK_ID) 369 { 370 ConstString g_symbol_name ("_dyld_debugger_notification"); 371 const Symbol *symbol = nullptr; 372 ModuleSP dyld_sp (GetDYLDModule()); 373 if (dyld_sp) 374 { 375 symbol = dyld_sp->FindFirstSymbolWithNameAndType (g_symbol_name, eSymbolTypeCode); 376 } 377 if (symbol && (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) 378 { 379 addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&m_process->GetTarget()); 380 if (symbol_address != LLDB_INVALID_ADDRESS) 381 { 382 bool internal = true; 383 bool hardware = false; 384 Breakpoint *breakpoint = m_process->GetTarget().CreateBreakpoint(symbol_address, internal, hardware).get(); 385 breakpoint->SetCallback (DynamicLoaderMacOS::NotifyBreakpointHit, this, true); 386 breakpoint->SetBreakpointKind ("shared-library-event"); 387 m_break_id = breakpoint->GetID(); 388 } 389 } 390 } 391 return m_break_id != LLDB_INVALID_BREAK_ID; 392 } 393 394 395 addr_t 396 DynamicLoaderMacOS::GetDyldLockVariableAddressFromModule (Module *module) 397 { 398 SymbolContext sc; 399 SymbolVendor *sym_vendor = module->GetSymbolVendor (); 400 Target &target = m_process->GetTarget (); 401 if (sym_vendor) 402 { 403 Symtab *symtab = sym_vendor->GetSymtab(); 404 if (symtab) 405 { 406 std::vector<uint32_t> match_indexes; 407 ConstString g_symbol_name ("_dyld_global_lock_held"); 408 uint32_t num_matches = 0; 409 num_matches = symtab->AppendSymbolIndexesWithName (g_symbol_name, match_indexes); 410 if (num_matches == 1) 411 { 412 Symbol *symbol = symtab->SymbolAtIndex (match_indexes[0]); 413 if (symbol && (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) 414 { 415 return symbol->GetAddressRef().GetOpcodeLoadAddress(&target); 416 } 417 } 418 } 419 } 420 return LLDB_INVALID_ADDRESS; 421 } 422 423 // Look for this symbol: 424 // 425 // int __attribute__((visibility("hidden"))) _dyld_global_lock_held = 0; 426 // 427 // in libdyld.dylib. 428 Error 429 DynamicLoaderMacOS::CanLoadImage () 430 { 431 Error error; 432 addr_t symbol_address = LLDB_INVALID_ADDRESS; 433 Target &target = m_process->GetTarget (); 434 const ModuleList &target_modules = target.GetImages(); 435 std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); 436 const size_t num_modules = target_modules.GetSize(); 437 ConstString g_libdyld_name ("libdyld.dylib"); 438 439 // Find any modules named "libdyld.dylib" and look for the symbol there first 440 for (size_t i = 0; i < num_modules; i++) 441 { 442 Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked (i); 443 if (module_pointer) 444 { 445 if (module_pointer->GetFileSpec().GetFilename() == g_libdyld_name) 446 { 447 symbol_address = GetDyldLockVariableAddressFromModule (module_pointer); 448 if (symbol_address != LLDB_INVALID_ADDRESS) 449 break; 450 } 451 } 452 } 453 454 // Search through all modules looking for the symbol in them 455 if (symbol_address == LLDB_INVALID_ADDRESS) 456 { 457 for (size_t i = 0; i < num_modules; i++) 458 { 459 Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked (i); 460 if (module_pointer) 461 { 462 addr_t symbol_address = GetDyldLockVariableAddressFromModule (module_pointer); 463 if (symbol_address != LLDB_INVALID_ADDRESS) 464 break; 465 } 466 } 467 } 468 469 // Default assumption is that it is OK to load images. 470 // Only say that we cannot load images if we find the symbol in libdyld and it indicates that 471 // we cannot. 472 473 if (symbol_address != LLDB_INVALID_ADDRESS) 474 { 475 { 476 int lock_held = m_process->ReadUnsignedIntegerFromMemory (symbol_address, 4, 0, error); 477 if (lock_held != 0) 478 { 479 error.SetErrorToGenericError(); 480 } 481 } 482 } 483 else 484 { 485 // If we were unable to find _dyld_global_lock_held in any modules, or it is not loaded into 486 // memory yet, we may be at process startup (sitting at _dyld_start) - so we should not allow 487 // dlopen calls. 488 error.SetErrorToGenericError(); 489 } 490 return error; 491 } 492 493 void 494 DynamicLoaderMacOS::Initialize() 495 { 496 PluginManager::RegisterPlugin (GetPluginNameStatic(), 497 GetPluginDescriptionStatic(), 498 CreateInstance); 499 } 500 501 void 502 DynamicLoaderMacOS::Terminate() 503 { 504 PluginManager::UnregisterPlugin (CreateInstance); 505 } 506 507 508 lldb_private::ConstString 509 DynamicLoaderMacOS::GetPluginNameStatic() 510 { 511 static ConstString g_name("macos-dyld"); 512 return g_name; 513 } 514 515 const char * 516 DynamicLoaderMacOS::GetPluginDescriptionStatic() 517 { 518 return "Dynamic loader plug-in that watches for shared library loads/unloads in MacOSX user processes."; 519 } 520 521 522 //------------------------------------------------------------------ 523 // PluginInterface protocol 524 //------------------------------------------------------------------ 525 lldb_private::ConstString 526 DynamicLoaderMacOS::GetPluginName() 527 { 528 return GetPluginNameStatic(); 529 } 530 531 uint32_t 532 DynamicLoaderMacOS::GetPluginVersion() 533 { 534 return 1; 535 } 536