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 #include "lldb/Target/Process.h"
30 
31 
32 #include "SystemRuntimeMacOSX.h"
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 
37 //----------------------------------------------------------------------
38 // Create an instance of this class. This function is filled into
39 // the plugin info class that gets handed out by the plugin factory and
40 // allows the lldb to instantiate an instance of this class.
41 //----------------------------------------------------------------------
42 SystemRuntime *
43 SystemRuntimeMacOSX::CreateInstance (Process* process)
44 {
45     bool create = false;
46     if (!create)
47     {
48         create = true;
49         Module* exe_module = process->GetTarget().GetExecutableModulePointer();
50         if (exe_module)
51         {
52             ObjectFile *object_file = exe_module->GetObjectFile();
53             if (object_file)
54             {
55                 create = (object_file->GetStrata() == ObjectFile::eStrataUser);
56             }
57         }
58 
59         if (create)
60         {
61             const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
62             switch (triple_ref.getOS())
63             {
64                 case llvm::Triple::Darwin:
65                 case llvm::Triple::MacOSX:
66                 case llvm::Triple::IOS:
67                     create = triple_ref.getVendor() == llvm::Triple::Apple;
68                     break;
69                 default:
70                     create = false;
71                     break;
72             }
73         }
74     }
75 
76     if (create)
77         return new SystemRuntimeMacOSX (process);
78     return NULL;
79 }
80 
81 //----------------------------------------------------------------------
82 // Constructor
83 //----------------------------------------------------------------------
84 SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
85     SystemRuntime(process),
86     m_break_id(LLDB_INVALID_BREAK_ID),
87     m_mutex(Mutex::eMutexTypeRecursive),
88     m_get_queues_handler(process),
89     m_get_pending_items_handler(process),
90     m_get_item_info_handler(process),
91     m_get_thread_item_info_handler(process),
92     m_page_to_free(LLDB_INVALID_ADDRESS),
93     m_page_to_free_size(0),
94     m_lib_backtrace_recording_info(),
95     m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
96     m_libdispatch_offsets()
97 {
98 }
99 
100 //----------------------------------------------------------------------
101 // Destructor
102 //----------------------------------------------------------------------
103 SystemRuntimeMacOSX::~SystemRuntimeMacOSX()
104 {
105     Clear (true);
106 }
107 
108 void
109 SystemRuntimeMacOSX::Detach ()
110 {
111         m_get_queues_handler.Detach();
112         m_get_pending_items_handler.Detach();
113         m_get_item_info_handler.Detach();
114         m_get_thread_item_info_handler.Detach();
115 }
116 
117 //----------------------------------------------------------------------
118 // Clear out the state of this class.
119 //----------------------------------------------------------------------
120 void
121 SystemRuntimeMacOSX::Clear (bool clear_process)
122 {
123     Mutex::Locker locker(m_mutex);
124 
125     if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
126         m_process->ClearBreakpointSiteByID(m_break_id);
127 
128     if (clear_process)
129         m_process = NULL;
130     m_break_id = LLDB_INVALID_BREAK_ID;
131 }
132 
133 
134 std::string
135 SystemRuntimeMacOSX::GetQueueNameFromThreadQAddress (addr_t dispatch_qaddr)
136 {
137     std::string dispatch_queue_name;
138     if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
139         return "";
140 
141     ReadLibdispatchOffsets ();
142     if (m_libdispatch_offsets.IsValid ())
143     {
144         // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
145         // deref it to get the address of the dispatch_queue_t structure for this thread's
146         // queue.
147         Error error;
148         addr_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
149         if (error.Success())
150         {
151             if (m_libdispatch_offsets.dqo_version >= 4)
152             {
153                 // libdispatch versions 4+, pointer to dispatch name is in the
154                 // queue structure.
155                 addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
156                 addr_t label_addr = m_process->ReadPointerFromMemory (pointer_to_label_address, error);
157                 if (error.Success())
158                 {
159                     m_process->ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
160                 }
161             }
162             else
163             {
164                 // libdispatch versions 1-3, dispatch name is a fixed width char array
165                 // in the queue structure.
166                 addr_t label_addr = dispatch_queue_addr + m_libdispatch_offsets.dqo_label;
167                 dispatch_queue_name.resize (m_libdispatch_offsets.dqo_label_size, '\0');
168                 size_t bytes_read = m_process->ReadMemory (label_addr, &dispatch_queue_name[0], m_libdispatch_offsets.dqo_label_size, error);
169                 if (bytes_read < m_libdispatch_offsets.dqo_label_size)
170                     dispatch_queue_name.erase (bytes_read);
171             }
172         }
173     }
174     return dispatch_queue_name;
175 }
176 
177 lldb::addr_t
178 SystemRuntimeMacOSX::GetLibdispatchQueueAddressFromThreadQAddress (addr_t dispatch_qaddr)
179 {
180     addr_t libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
181     Error error;
182     libdispatch_queue_t_address = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
183     if (!error.Success())
184     {
185         libdispatch_queue_t_address = LLDB_INVALID_ADDRESS;
186     }
187     return libdispatch_queue_t_address;
188 }
189 
190 lldb::QueueKind
191 SystemRuntimeMacOSX::GetQueueKind (addr_t dispatch_queue_addr)
192 {
193     if (dispatch_queue_addr == LLDB_INVALID_ADDRESS || dispatch_queue_addr == 0)
194       return eQueueKindUnknown;
195 
196     QueueKind kind = eQueueKindUnknown;
197     ReadLibdispatchOffsets ();
198     if (m_libdispatch_offsets.IsValid () && m_libdispatch_offsets.dqo_version >= 4)
199     {
200         Error error;
201         uint64_t width = m_process->ReadUnsignedIntegerFromMemory (dispatch_queue_addr + m_libdispatch_offsets.dqo_width, m_libdispatch_offsets.dqo_width_size, 0, error);
202         if (error.Success())
203         {
204             if (width == 1)
205             {
206                 kind = eQueueKindSerial;
207             }
208             if (width > 1)
209             {
210                 kind = eQueueKindConcurrent;
211             }
212         }
213     }
214     return kind;
215 }
216 
217 lldb::queue_id_t
218 SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
219 {
220     queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
221 
222     if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
223         return queue_id;
224 
225     ReadLibdispatchOffsets ();
226     if (m_libdispatch_offsets.IsValid ())
227     {
228         // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
229         // deref it to get the address of the dispatch_queue_t structure for this thread's
230         // queue.
231         Error error;
232         uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
233         if (error.Success())
234         {
235             addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum;
236             queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error);
237             if (error.Success())
238             {
239                 queue_id = serialnum;
240             }
241         }
242     }
243 
244     return queue_id;
245 }
246 
247 
248 void
249 SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress ()
250 {
251     if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
252         return;
253 
254     static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
255     const Symbol *dispatch_queue_offsets_symbol = NULL;
256 
257     // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
258     ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
259     ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
260     if (module_sp)
261         dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
262 
263     // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
264     if (dispatch_queue_offsets_symbol == NULL)
265     {
266         ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
267         module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
268         if (module_sp)
269             dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
270     }
271     if (dispatch_queue_offsets_symbol)
272         m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
273 }
274 
275 void
276 SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
277 {
278     if (m_libdispatch_offsets.IsValid())
279         return;
280 
281     ReadLibdispatchOffsetsAddress ();
282 
283     uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
284     DataExtractor data (memory_buffer,
285                         sizeof(memory_buffer),
286                         m_process->GetByteOrder(),
287                         m_process->GetAddressByteSize());
288 
289     Error error;
290     if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
291     {
292         lldb::offset_t data_offset = 0;
293 
294         // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
295         // in one big go.
296         data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
297     }
298 }
299 
300 
301 ThreadSP
302 SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
303 {
304     ThreadSP originating_thread_sp;
305     if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch"))
306     {
307         Error error;
308 
309         // real_thread is either an actual, live thread (in which case we need to call into
310         // libBacktraceRecording to find its originator) or it is an extended backtrace itself,
311         // in which case we get the token from it and call into libBacktraceRecording to find
312         // the originator of that token.
313 
314         if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS)
315         {
316             originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken());
317         }
318         else
319         {
320             ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
321             AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler.GetThreadItemInfo (*cur_thread_sp.get(), real_thread->GetID(), m_page_to_free, m_page_to_free_size, error);
322             m_page_to_free = LLDB_INVALID_ADDRESS;
323             m_page_to_free_size = 0;
324             if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
325             {
326                 DataBufferHeap data (ret.item_buffer_size, 0);
327                 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
328                 {
329                     DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
330                     ItemInfo item = ExtractItemInfoFromBuffer (extractor);
331                     bool stop_id_is_valid = true;
332                     if (item.stop_id == 0)
333                         stop_id_is_valid = false;
334                     originating_thread_sp.reset (new HistoryThread (*m_process,
335                                                                     item.enqueuing_thread_id,
336                                                                     item.enqueuing_callstack,
337                                                                     item.stop_id,
338                                                                     stop_id_is_valid));
339                     originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
340                     originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
341                     originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
342 //                    originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
343                 }
344                 m_page_to_free = ret.item_buffer_ptr;
345                 m_page_to_free_size = ret.item_buffer_size;
346             }
347         }
348     }
349     return originating_thread_sp;
350 }
351 
352 ThreadSP
353 SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref)
354 {
355     ThreadSP return_thread_sp;
356 
357     AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
358     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
359     Error error;
360     ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
361     m_page_to_free = LLDB_INVALID_ADDRESS;
362     m_page_to_free_size = 0;
363     if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
364     {
365         DataBufferHeap data (ret.item_buffer_size, 0);
366         if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
367         {
368             DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
369             ItemInfo item = ExtractItemInfoFromBuffer (extractor);
370             bool stop_id_is_valid = true;
371             if (item.stop_id == 0)
372                 stop_id_is_valid = false;
373             return_thread_sp.reset (new HistoryThread (*m_process,
374                                                             item.enqueuing_thread_id,
375                                                             item.enqueuing_callstack,
376                                                             item.stop_id,
377                                                             stop_id_is_valid));
378             return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
379             return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
380             return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
381 //            return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
382 
383             m_page_to_free = ret.item_buffer_ptr;
384             m_page_to_free_size = ret.item_buffer_size;
385         }
386     }
387     return return_thread_sp;
388 }
389 
390 ThreadSP
391 SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type)
392 {
393     ThreadSP extended_thread_sp;
394     if (type != ConstString("libdispatch"))
395         return extended_thread_sp;
396 
397     bool stop_id_is_valid = true;
398     if (queue_item_sp->GetStopID() == 0)
399         stop_id_is_valid = false;
400 
401     extended_thread_sp.reset (new HistoryThread (*m_process,
402                                                  queue_item_sp->GetEnqueueingThreadID(),
403                                                  queue_item_sp->GetEnqueueingBacktrace(),
404                                                  queue_item_sp->GetStopID(),
405                                                  stop_id_is_valid));
406     extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis());
407     extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str());
408     extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID());
409 //    extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
410 
411     return extended_thread_sp;
412 }
413 
414 /* Returns true if we were able to get the version / offset information
415  * out of libBacktraceRecording.  false means we were unable to retrieve
416  * this; the queue_info_version field will be 0.
417  */
418 
419 bool
420 SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized ()
421 {
422     if (m_lib_backtrace_recording_info.queue_info_version != 0)
423         return true;
424 
425     addr_t queue_info_version_address = LLDB_INVALID_ADDRESS;
426     addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS;
427     addr_t item_info_version_address = LLDB_INVALID_ADDRESS;
428     addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS;
429     Target &target = m_process->GetTarget();
430 
431 
432     static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version");
433     SymbolContextList sc_list;
434     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0)
435     {
436         SymbolContext sc;
437         sc_list.GetContextAtIndex (0, sc);
438         AddressRange addr_range;
439         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
440         queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
441     }
442     sc_list.Clear();
443 
444     static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset");
445     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0)
446     {
447         SymbolContext sc;
448         sc_list.GetContextAtIndex (0, sc);
449         AddressRange addr_range;
450         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
451         queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
452     }
453     sc_list.Clear();
454 
455     static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version");
456     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0)
457     {
458         SymbolContext sc;
459         sc_list.GetContextAtIndex (0, sc);
460         AddressRange addr_range;
461         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
462         item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
463     }
464     sc_list.Clear();
465 
466     static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset");
467     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0)
468     {
469         SymbolContext sc;
470         sc_list.GetContextAtIndex (0, sc);
471         AddressRange addr_range;
472         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
473         item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
474     }
475 
476     if (queue_info_version_address != LLDB_INVALID_ADDRESS
477         && queue_info_data_offset_address != LLDB_INVALID_ADDRESS
478         && item_info_version_address != LLDB_INVALID_ADDRESS
479         && item_info_data_offset_address != LLDB_INVALID_ADDRESS)
480     {
481         Error error;
482         m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error);
483         if (error.Success())
484         {
485             m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error);
486             if (error.Success())
487             {
488                 m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error);
489                 if (error.Success())
490                 {
491                     m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error);
492                     if (!error.Success())
493                     {
494                         m_lib_backtrace_recording_info.queue_info_version = 0;
495                     }
496                 }
497                 else
498                 {
499                     m_lib_backtrace_recording_info.queue_info_version = 0;
500                 }
501             }
502             else
503             {
504                 m_lib_backtrace_recording_info.queue_info_version = 0;
505             }
506         }
507     }
508 
509     return m_lib_backtrace_recording_info.queue_info_version != 0;
510 }
511 
512 const std::vector<ConstString> &
513 SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
514 {
515     if (m_types.size () == 0)
516     {
517         m_types.push_back(ConstString("libdispatch"));
518         // We could have pthread as another type in the future if we have a way of
519         // gathering that information & it's useful to distinguish between them.
520     }
521     return m_types;
522 }
523 
524 void
525 SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
526 {
527     if (!BacktraceRecordingHeadersInitialized())
528     {
529         // We don't have libBacktraceRecording -- build the list of queues by looking at
530         // all extant threads, and the queues that they currently belong to.
531 
532         for (ThreadSP thread_sp : m_process->Threads())
533         {
534             if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
535             {
536                 if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
537                 {
538                     QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
539                     queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress()));
540                     queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
541                     queue_list.AddQueue (queue_sp);
542                 }
543             }
544         }
545     }
546     else
547     {
548         AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer;
549         ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
550         if (cur_thread_sp)
551         {
552             Error error;
553             queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error);
554             m_page_to_free = LLDB_INVALID_ADDRESS;
555             m_page_to_free_size = 0;
556             if (error.Success())
557             {
558 
559                 if (queue_info_pointer.count > 0
560                     && queue_info_pointer.queues_buffer_size > 0
561                     && queue_info_pointer.queues_buffer_ptr != 0
562                     && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS)
563                 {
564                     PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list);
565                 }
566             }
567         }
568     }
569 }
570 
571 // Returns either an array of introspection_dispatch_item_info_ref's for the pending items on
572 // a queue or an array introspection_dispatch_item_info_ref's and code addresses for the
573 // pending items on a queue.  The information about each of these pending items then needs to
574 // be fetched individually by passing the ref to libBacktraceRecording.
575 
576 SystemRuntimeMacOSX::PendingItemsForQueue
577 SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue)
578 {
579     PendingItemsForQueue pending_item_refs;
580     AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer;
581     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
582     if (cur_thread_sp)
583     {
584         Error error;
585         pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error);
586         m_page_to_free = LLDB_INVALID_ADDRESS;
587         m_page_to_free_size = 0;
588         if (error.Success())
589         {
590             if (pending_items_pointer.count > 0
591                 && pending_items_pointer.items_buffer_size > 0
592                 && pending_items_pointer.items_buffer_ptr != 0
593                 && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS)
594             {
595                 DataBufferHeap data (pending_items_pointer.items_buffer_size, 0);
596                 if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error))
597                 {
598                     DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
599 
600                     // We either have an array of
601                     //    void* item_ref
602                     // (old style) or we have a structure returned which looks like
603                     //
604                     // struct introspection_dispatch_pending_item_info_s {
605                     //   void *item_ref;
606                     //   void *function_or_block;
607                     // };
608                     //
609                     // struct introspection_dispatch_pending_items_array_s {
610                     //   uint32_t version;
611                     //   uint32_t size_of_item_info;
612                     //   introspection_dispatch_pending_item_info_s items[];
613                     //   }
614 
615                     offset_t offset = 0;
616                     int i = 0;
617                     uint32_t version = extractor.GetU32(&offset);
618                     if (version == 1)
619                     {
620                         pending_item_refs.new_style = true;
621                         uint32_t item_size = extractor.GetU32(&offset);
622                         uint32_t start_of_array_offset = offset;
623                         while (offset < pending_items_pointer.items_buffer_size && i < pending_items_pointer.count)
624                         {
625                             offset = start_of_array_offset + (i * item_size);
626                             ItemRefAndCodeAddress item;
627                             item.item_ref = extractor.GetPointer (&offset);
628                             item.code_address = extractor.GetPointer (&offset);
629                             pending_item_refs.item_refs_and_code_addresses.push_back (item);
630                             i++;
631                         }
632                     }
633                     else
634                     {
635                         offset = 0;
636                         pending_item_refs.new_style = false;
637                         while (offset < pending_items_pointer.items_buffer_size && i < pending_items_pointer.count)
638                         {
639                             ItemRefAndCodeAddress item;
640                             item.item_ref = extractor.GetPointer (&offset);
641                             item.code_address = LLDB_INVALID_ADDRESS;
642                             pending_item_refs.item_refs_and_code_addresses.push_back (item);
643                             i++;
644                         }
645                     }
646                 }
647                 m_page_to_free = pending_items_pointer.items_buffer_ptr;
648                 m_page_to_free_size = pending_items_pointer.items_buffer_size;
649             }
650         }
651     }
652     return pending_item_refs;
653 }
654 
655 
656 
657 void
658 SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue)
659 {
660     if (BacktraceRecordingHeadersInitialized())
661     {
662         PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress());
663         for (ItemRefAndCodeAddress pending_item : pending_item_refs.item_refs_and_code_addresses)
664         {
665             Address addr;
666             m_process->GetTarget().ResolveLoadAddress (pending_item.code_address, addr);
667             QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this(), m_process->shared_from_this(), pending_item.item_ref, addr));
668             queue->PushPendingQueueItem (queue_item_sp);
669         }
670     }
671 }
672 
673 void
674 SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref)
675 {
676     AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
677 
678     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
679     Error error;
680     ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
681     m_page_to_free = LLDB_INVALID_ADDRESS;
682     m_page_to_free_size = 0;
683     if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
684     {
685         DataBufferHeap data (ret.item_buffer_size, 0);
686         if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
687         {
688             DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
689             ItemInfo item = ExtractItemInfoFromBuffer (extractor);
690             queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this);
691             queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id);
692             queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum);
693             queue_item->SetStopID (item.stop_id);
694             queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack);
695             queue_item->SetThreadLabel (item.enqueuing_thread_label);
696             queue_item->SetQueueLabel (item.enqueuing_queue_label);
697             queue_item->SetTargetQueueLabel (item.target_queue_label);
698         }
699         m_page_to_free = ret.item_buffer_ptr;
700         m_page_to_free_size = ret.item_buffer_size;
701     }
702 }
703 
704 void
705 SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size,
706                                                 uint64_t count, lldb_private::QueueList &queue_list)
707 {
708     Error error;
709     DataBufferHeap data (queues_buffer_size, 0);
710     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
711     if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success())
712     {
713         // We've read the information out of inferior memory; free it on the next call we make
714         m_page_to_free = queues_buffer;
715         m_page_to_free_size = queues_buffer_size;
716 
717         DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
718         offset_t offset = 0;
719         uint64_t queues_read = 0;
720 
721         // The information about the queues is stored in this format (v1):
722         // typedef struct introspection_dispatch_queue_info_s {
723         //     uint32_t offset_to_next;
724         //     dispatch_queue_t queue;
725         //     uint64_t serialnum;     // queue's serialnum in the process, as provided by libdispatch
726         //     uint32_t running_work_items_count;
727         //     uint32_t pending_work_items_count;
728         //
729         //     char data[];     // Starting here, we have variable-length data:
730         //     // char queue_label[];
731         // } introspection_dispatch_queue_info_s;
732 
733         while (queues_read < count && offset < queues_buffer_size)
734         {
735             offset_t    start_of_this_item = offset;
736 
737             uint32_t    offset_to_next = extractor.GetU32 (&offset);
738 
739             offset += 4; // Skip over the 4 bytes of reserved space
740             addr_t      queue = extractor.GetPointer (&offset);
741             uint64_t    serialnum = extractor.GetU64 (&offset);
742             uint32_t    running_work_items_count = extractor.GetU32 (&offset);
743             uint32_t    pending_work_items_count = extractor.GetU32 (&offset);
744 
745             // Read the first field of the variable length data
746             offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset;
747             const char *queue_label = extractor.GetCStr (&offset);
748             if (queue_label == NULL)
749                 queue_label = "";
750 
751             offset_t    start_of_next_item = start_of_this_item + offset_to_next;
752             offset = start_of_next_item;
753 
754             if (log)
755                 log->Printf ("SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added queue with dispatch_queue_t 0x%" PRIx64 ", serial number 0x%" PRIx64 ", running items %d, pending items %d, name '%s'", queue, serialnum, running_work_items_count, pending_work_items_count, queue_label);
756 
757             QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label));
758             queue_sp->SetNumRunningWorkItems (running_work_items_count);
759             queue_sp->SetNumPendingWorkItems (pending_work_items_count);
760             queue_sp->SetLibdispatchQueueAddress (queue);
761             queue_sp->SetKind (GetQueueKind (queue));
762             queue_list.AddQueue (queue_sp);
763             queues_read++;
764         }
765     }
766 }
767 
768 SystemRuntimeMacOSX::ItemInfo
769 SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor)
770 {
771     ItemInfo item;
772 
773     offset_t offset = 0;
774 
775     item.item_that_enqueued_this = extractor.GetPointer (&offset);
776     item.function_or_block = extractor.GetPointer (&offset);
777     item.enqueuing_thread_id = extractor.GetU64 (&offset);
778     item.enqueuing_queue_serialnum = extractor.GetU64 (&offset);
779     item.target_queue_serialnum = extractor.GetU64 (&offset);
780     item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset);
781     item.stop_id = extractor.GetU32 (&offset);
782 
783     offset = m_lib_backtrace_recording_info.item_info_data_offset;
784 
785     for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++)
786     {
787         item.enqueuing_callstack.push_back (extractor.GetPointer (&offset));
788     }
789     item.enqueuing_thread_label = extractor.GetCStr (&offset);
790     item.enqueuing_queue_label = extractor.GetCStr (&offset);
791     item.target_queue_label = extractor.GetCStr (&offset);
792 
793     return item;
794 }
795 
796 void
797 SystemRuntimeMacOSX::Initialize()
798 {
799     PluginManager::RegisterPlugin (GetPluginNameStatic(),
800                                    GetPluginDescriptionStatic(),
801                                    CreateInstance);
802 }
803 
804 void
805 SystemRuntimeMacOSX::Terminate()
806 {
807     PluginManager::UnregisterPlugin (CreateInstance);
808 }
809 
810 
811 lldb_private::ConstString
812 SystemRuntimeMacOSX::GetPluginNameStatic()
813 {
814     static ConstString g_name("systemruntime-macosx");
815     return g_name;
816 }
817 
818 const char *
819 SystemRuntimeMacOSX::GetPluginDescriptionStatic()
820 {
821     return "System runtime plugin for Mac OS X native libraries.";
822 }
823 
824 
825 //------------------------------------------------------------------
826 // PluginInterface protocol
827 //------------------------------------------------------------------
828 lldb_private::ConstString
829 SystemRuntimeMacOSX::GetPluginName()
830 {
831     return GetPluginNameStatic();
832 }
833 
834 uint32_t
835 SystemRuntimeMacOSX::GetPluginVersion()
836 {
837     return 1;
838 }
839