1 //===-- SystemRuntimeMacOSX.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 
11 #include "lldb/Breakpoint/StoppointCallbackContext.h"
12 #include "lldb/Core/Log.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleSpec.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/DataExtractor.h"
17 #include "lldb/Core/DataBufferHeap.h"
18 #include "lldb/Core/Section.h"
19 #include "lldb/Expression/ClangFunction.h"
20 #include "lldb/Expression/ClangUtilityFunction.h"
21 #include "lldb/Host/FileSpec.h"
22 #include "lldb/Symbol/ObjectFile.h"
23 #include "lldb/Symbol/SymbolContext.h"
24 #include "Plugins/Process/Utility/HistoryThread.h"
25 #include "lldb/Target/Queue.h"
26 #include "lldb/Target/QueueList.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Target/Thread.h"
29 
30 #include "SystemRuntimeMacOSX.h"
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 
35 //----------------------------------------------------------------------
36 // Create an instance of this class. This function is filled into
37 // the plugin info class that gets handed out by the plugin factory and
38 // allows the lldb to instantiate an instance of this class.
39 //----------------------------------------------------------------------
40 SystemRuntime *
41 SystemRuntimeMacOSX::CreateInstance (Process* process)
42 {
43     bool create = false;
44     if (!create)
45     {
46         create = true;
47         Module* exe_module = process->GetTarget().GetExecutableModulePointer();
48         if (exe_module)
49         {
50             ObjectFile *object_file = exe_module->GetObjectFile();
51             if (object_file)
52             {
53                 create = (object_file->GetStrata() == ObjectFile::eStrataUser);
54             }
55         }
56 
57         if (create)
58         {
59             const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
60             switch (triple_ref.getOS())
61             {
62                 case llvm::Triple::Darwin:
63                 case llvm::Triple::MacOSX:
64                 case llvm::Triple::IOS:
65                     create = triple_ref.getVendor() == llvm::Triple::Apple;
66                     break;
67                 default:
68                     create = false;
69                     break;
70             }
71         }
72     }
73 
74     if (create)
75         return new SystemRuntimeMacOSX (process);
76     return NULL;
77 }
78 
79 //----------------------------------------------------------------------
80 // Constructor
81 //----------------------------------------------------------------------
82 SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
83     SystemRuntime(process),
84     m_break_id(LLDB_INVALID_BREAK_ID),
85     m_mutex(Mutex::eMutexTypeRecursive)
86 {
87     m_ldi_header.initialized = 0;
88 }
89 
90 //----------------------------------------------------------------------
91 // Destructor
92 //----------------------------------------------------------------------
93 SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
94 {
95     Clear (true);
96 }
97 
98 //----------------------------------------------------------------------
99 // Clear out the state of this class.
100 //----------------------------------------------------------------------
101 void
102 SystemRuntimeMacOSX::Clear (bool clear_process)
103 {
104     Mutex::Locker locker(m_mutex);
105 
106     if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
107         m_process->ClearBreakpointSiteByID(m_break_id);
108 
109     if (clear_process)
110         m_process = NULL;
111     m_break_id = LLDB_INVALID_BREAK_ID;
112     m_ldi_header.initialized = 0;
113 }
114 
115 
116 void
117 SystemRuntimeMacOSX::DidAttach ()
118 {
119 }
120 
121 void
122 SystemRuntimeMacOSX::DidLaunch ()
123 {
124 }
125 
126 void
127 SystemRuntimeMacOSX::ModulesDidLoad (ModuleList &module_list)
128 {
129 }
130 
131 bool
132 SystemRuntimeMacOSX::LdiHeadersInitialized ()
133 {
134     ParseLdiHeaders();
135     return m_ldi_header.initialized;
136 }
137 
138 void
139 SystemRuntimeMacOSX::ParseLdiHeaders ()
140 {
141     if (m_ldi_header.initialized)
142         return;
143     static ConstString ldi_header_symbol ("ldi_infos");
144     SymbolContextList sc_list;
145     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (ldi_header_symbol, eSymbolTypeData, sc_list) > 0)
146     {
147         SymbolContext sc;
148         sc_list.GetContextAtIndex (0, sc);
149         AddressRange addr_range;
150         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
151 
152         Error error;
153         Address ldi_header_addr = addr_range.GetBaseAddress();
154         uint8_t version_buf[6];   // version, ldi_header_size, initialized fields
155         DataExtractor data (version_buf, sizeof(version_buf), m_process->GetByteOrder(), m_process->GetAddressByteSize());
156         const size_t count = sizeof (version_buf);
157         const bool prefer_file_cache = false;
158         if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, version_buf, count, error) == sizeof (version_buf))
159         {
160             int version, initialized, ldi_header_size;
161             offset_t offset = 0;
162             version = data.GetU16(&offset);
163             ldi_header_size = data.GetU16(&offset);
164             initialized = data.GetU16(&offset);
165             if (initialized)
166             {
167                 DataBufferHeap ldi_header (ldi_header_size, 0);
168                 DataExtractor ldi_extractor (ldi_header.GetBytes(), ldi_header.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
169                 if (m_process->GetTarget().ReadMemory (ldi_header_addr, prefer_file_cache, ldi_header.GetBytes(), ldi_header.GetByteSize(), error) == ldi_header.GetByteSize())
170                 {
171                     offset = 0;
172                     m_ldi_header.version = ldi_extractor.GetU16(&offset);
173                     m_ldi_header.ldi_header_size = ldi_extractor.GetU16(&offset);
174                     m_ldi_header.initialized = ldi_extractor.GetU16(&offset);
175                     m_ldi_header.queue_size = ldi_extractor.GetU16(&offset);
176                     m_ldi_header.item_size = ldi_extractor.GetU16(&offset);
177 
178                     // 6 bytes of padding here
179                     offset += 6;
180 
181                     m_ldi_header.queues_head_ptr_address = ldi_extractor.GetU64(&offset);
182                     m_ldi_header.items_head_ptr_address = ldi_extractor.GetU64(&offset);
183 
184                     m_ldi_header.queue_offsets.next = ldi_extractor.GetU16(&offset);
185                     m_ldi_header.queue_offsets.prev = ldi_extractor.GetU16(&offset);
186                     m_ldi_header.queue_offsets.queue_id = ldi_extractor.GetU16(&offset);
187                     m_ldi_header.queue_offsets.current_item_ptr = ldi_extractor.GetU16(&offset);
188 
189                     m_ldi_header.item_offsets.next = ldi_extractor.GetU16(&offset);
190                     m_ldi_header.item_offsets.prev = ldi_extractor.GetU16(&offset);
191                     m_ldi_header.item_offsets.type = ldi_extractor.GetU16(&offset);
192                     m_ldi_header.item_offsets.identifier = ldi_extractor.GetU16(&offset);
193                     m_ldi_header.item_offsets.stop_id = ldi_extractor.GetU16(&offset);
194                     m_ldi_header.item_offsets.backtrace_length = ldi_extractor.GetU16(&offset);
195                     m_ldi_header.item_offsets.backtrace_ptr = ldi_extractor.GetU16(&offset);
196                     m_ldi_header.item_offsets.thread_name_ptr = ldi_extractor.GetU16(&offset);
197                     m_ldi_header.item_offsets.queue_name_ptr = ldi_extractor.GetU16(&offset);
198                     m_ldi_header.item_offsets.unique_thread_id = ldi_extractor.GetU16(&offset);
199                     m_ldi_header.item_offsets.pthread_id = ldi_extractor.GetU16(&offset);
200                     m_ldi_header.item_offsets.enqueueing_thread_dispatch_queue_t = ldi_extractor.GetU16(&offset);
201                     m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr = ldi_extractor.GetU16(&offset);
202 
203                     if (ldi_header.GetByteSize () > offset)
204                     {
205                         m_ldi_header.item_offsets.queue_id_from_thread_info = ldi_extractor.GetU16(&offset);
206                     }
207                     else
208                     {
209                         m_ldi_header.item_offsets.queue_id_from_thread_info = 0xffff;
210                     }
211                 }
212             }
213         }
214     }
215 }
216 
217 lldb::addr_t
218 SystemRuntimeMacOSX::GetQueuesHead ()
219 {
220     if (!LdiHeadersInitialized())
221         return LLDB_INVALID_ADDRESS;
222 
223     Error error;
224     addr_t queues_head = m_process->ReadPointerFromMemory (m_ldi_header.queues_head_ptr_address, error);
225     if (error.Success() == false || queues_head == LLDB_INVALID_ADDRESS || queues_head == 0)
226         return LLDB_INVALID_ADDRESS;
227 
228     return queues_head;
229 }
230 
231 lldb::addr_t
232 SystemRuntimeMacOSX::GetItemsHead ()
233 {
234     if (!LdiHeadersInitialized())
235         return LLDB_INVALID_ADDRESS;
236 
237     Error error;
238     addr_t items_head = m_process->ReadPointerFromMemory (m_ldi_header.items_head_ptr_address, error);
239     if (error.Success() == false || items_head == LLDB_INVALID_ADDRESS || items_head == 0)
240         return LLDB_INVALID_ADDRESS;
241 
242     return items_head;
243 }
244 
245 addr_t
246 SystemRuntimeMacOSX::GetThreadCreatorItem (ThreadSP thread_sp)
247 {
248     addr_t enqueued_item_ptr = thread_sp->GetExtendedBacktraceToken();
249     if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
250     {
251         if (thread_sp->GetQueueID() == LLDB_INVALID_QUEUE_ID || thread_sp->GetQueueID() == 0)
252             return LLDB_INVALID_ADDRESS;
253 
254         Error error;
255         uint64_t this_thread_queue_id = thread_sp->GetQueueID();
256 
257         addr_t queues_head = GetQueuesHead();
258         if (queues_head == LLDB_INVALID_ADDRESS)
259             return LLDB_INVALID_ADDRESS;
260 
261         // Step through the queues_head linked list looking for a queue matching this thread, if any
262         uint64_t queue_obj_ptr = queues_head;
263         enqueued_item_ptr = LLDB_INVALID_ADDRESS;
264 
265         while (queue_obj_ptr != 0)
266         {
267             uint64_t queue_id = m_process->ReadUnsignedIntegerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.queue_id, 8, LLDB_INVALID_ADDRESS, error);
268             if (error.Success() && queue_id != LLDB_INVALID_ADDRESS)
269             {
270                 if (queue_id == this_thread_queue_id)
271                 {
272                     enqueued_item_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.current_item_ptr, error);
273                     break;
274                 }
275             }
276             queue_obj_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.next, error);
277             if (error.Success() == false || queue_obj_ptr == LLDB_INVALID_ADDRESS)
278             {
279                 break;
280             }
281         }
282     }
283 
284     return enqueued_item_ptr;
285 }
286 
287 SystemRuntimeMacOSX::ArchivedBacktrace
288 SystemRuntimeMacOSX::GetLibdispatchExtendedBacktrace (ThreadSP thread_sp)
289 {
290     ArchivedBacktrace bt;
291     bt.stop_id = 0;
292     bt.stop_id_is_valid = false;
293     bt.libdispatch_queue_id = LLDB_INVALID_QUEUE_ID;
294 
295     addr_t enqueued_item_ptr = GetThreadCreatorItem (thread_sp);
296 
297     if (enqueued_item_ptr == LLDB_INVALID_ADDRESS)
298         return bt;
299 
300     Error error;
301     uint32_t ptr_size = m_process->GetTarget().GetArchitecture().GetAddressByteSize();
302 
303     uint32_t backtrace_length = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_length, 4, 0, error);
304     addr_t pc_array_address = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.backtrace_ptr, error);
305 
306     if (backtrace_length == 0 || pc_array_address == LLDB_INVALID_ADDRESS)
307         return bt;
308 
309     for (uint32_t idx = 0; idx < backtrace_length; idx++)
310     {
311         addr_t pc_val = m_process->ReadPointerFromMemory (pc_array_address + (ptr_size * idx), error);
312         if (error.Success() && pc_val != LLDB_INVALID_ADDRESS)
313         {
314             bt.pcs.push_back (pc_val);
315         }
316     }
317 
318     return bt;
319 }
320 
321 const std::vector<ConstString> &
322 SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
323 {
324     if (m_types.size () == 0)
325     {
326         m_types.push_back(ConstString("libdispatch"));
327         m_types.push_back(ConstString("pthread"));
328     }
329     return m_types;
330 }
331 
332 void
333 SystemRuntimeMacOSX::SetNewThreadQueueName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
334 {
335     addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
336 
337     if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
338     {
339         Error error;
340         addr_t queue_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_name_ptr, error);
341         if (queue_name_ptr != LLDB_INVALID_ADDRESS && error.Success())
342         {
343             char namebuf[512];
344             if (m_process->ReadCStringFromMemory (queue_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success())
345             {
346                 new_extended_thread_sp->SetQueueName (namebuf);
347             }
348         }
349     }
350 }
351 
352 void
353 SystemRuntimeMacOSX::SetNewThreadThreadName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
354 {
355     addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
356 
357     if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
358     {
359         Error error;
360         addr_t thread_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.thread_name_ptr, error);
361         if (thread_name_ptr != LLDB_INVALID_ADDRESS && error.Success())
362         {
363             char namebuf[512];
364             if (m_process->ReadCStringFromMemory (thread_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success())
365             {
366                 new_extended_thread_sp->SetName (namebuf);
367             }
368         }
369     }
370 }
371 
372 
373 void
374 SystemRuntimeMacOSX::SetNewThreadExtendedBacktraceToken (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
375 {
376     addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
377     if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
378     {
379         Error error;
380         uint64_t further_extended_backtrace = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr, error);
381         if (error.Success() && further_extended_backtrace != 0 && further_extended_backtrace != LLDB_INVALID_ADDRESS)
382         {
383             new_extended_thread_sp->SetExtendedBacktraceToken (further_extended_backtrace);
384         }
385     }
386 }
387 
388 void
389 SystemRuntimeMacOSX::SetNewThreadQueueID (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp)
390 {
391     queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
392     addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
393     if (enqueued_item_ptr != LLDB_INVALID_ADDRESS && m_ldi_header.item_offsets.queue_id_from_thread_info != 0xffff)
394     {
395         Error error;
396         queue_id = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_id_from_thread_info, 8, LLDB_INVALID_QUEUE_ID, error);
397         if (!error.Success())
398             queue_id = LLDB_INVALID_QUEUE_ID;
399     }
400 
401     if (queue_id != LLDB_INVALID_QUEUE_ID)
402     {
403         new_extended_thread_sp->SetQueueID (queue_id);
404     }
405 }
406 
407 
408 lldb::tid_t
409 SystemRuntimeMacOSX::GetNewThreadUniqueThreadID (ThreadSP original_thread_sp)
410 {
411     tid_t ret = LLDB_INVALID_THREAD_ID;
412     addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp);
413     if (enqueued_item_ptr != LLDB_INVALID_ADDRESS)
414     {
415         Error error;
416         ret = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.unique_thread_id, 8, LLDB_INVALID_THREAD_ID, error);
417         if (!error.Success())
418             ret = LLDB_INVALID_THREAD_ID;
419     }
420     return ret;
421 }
422 
423 ThreadSP
424 SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP original_thread_sp, ConstString type)
425 {
426     ThreadSP new_extended_thread_sp;
427 
428     if (type != ConstString("libdispatch"))
429         return new_extended_thread_sp;
430 
431     ArchivedBacktrace bt = GetLibdispatchExtendedBacktrace (original_thread_sp);
432 
433     if (bt.pcs.size() == 0)
434         return new_extended_thread_sp;
435 
436     tid_t unique_thread_id = GetNewThreadUniqueThreadID (original_thread_sp);
437 
438     new_extended_thread_sp.reset (new HistoryThread (*m_process, unique_thread_id, bt.pcs, bt.stop_id, bt.stop_id_is_valid));
439 
440     SetNewThreadThreadName (original_thread_sp, new_extended_thread_sp);
441     SetNewThreadQueueName (original_thread_sp, new_extended_thread_sp);
442     SetNewThreadQueueID (original_thread_sp, new_extended_thread_sp);
443     SetNewThreadExtendedBacktraceToken (original_thread_sp, new_extended_thread_sp);
444     return new_extended_thread_sp;
445 }
446 
447 void
448 SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
449 {
450     // For now, iterate over the threads and see what queue each thread is associated with.
451     // If we haven't already added this queue, add it to the QueueList.
452     // (a single libdispatch queue may be using multiple threads simultaneously.)
453 
454     for (ThreadSP thread_sp : m_process->Threads())
455     {
456         if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
457         {
458             if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
459             {
460                 QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
461                 queue_list.AddQueue (queue_sp);
462             }
463         }
464     }
465 }
466 
467 
468 void
469 SystemRuntimeMacOSX::Initialize()
470 {
471     PluginManager::RegisterPlugin (GetPluginNameStatic(),
472                                    GetPluginDescriptionStatic(),
473                                    CreateInstance);
474 }
475 
476 void
477 SystemRuntimeMacOSX::Terminate()
478 {
479     PluginManager::UnregisterPlugin (CreateInstance);
480 }
481 
482 
483 lldb_private::ConstString
484 SystemRuntimeMacOSX::GetPluginNameStatic()
485 {
486     static ConstString g_name("systemruntime-macosx");
487     return g_name;
488 }
489 
490 const char *
491 SystemRuntimeMacOSX::GetPluginDescriptionStatic()
492 {
493     return "System runtime plugin for Mac OS X native libraries.";
494 }
495 
496 
497 //------------------------------------------------------------------
498 // PluginInterface protocol
499 //------------------------------------------------------------------
500 lldb_private::ConstString
501 SystemRuntimeMacOSX::GetPluginName()
502 {
503     return GetPluginNameStatic();
504 }
505 
506 uint32_t
507 SystemRuntimeMacOSX::GetPluginVersion()
508 {
509     return 1;
510 }
511