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