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 bool
218 SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread (ThreadSP thread_sp)
219 {
220     if (thread_sp && thread_sp->GetStackFrameCount() > 0 && thread_sp->GetFrameWithConcreteFrameIndex(0))
221     {
222         const SymbolContext sym_ctx (thread_sp->GetFrameWithConcreteFrameIndex(0)->GetSymbolContext (eSymbolContextSymbol));
223         static ConstString g_select_symbol ("__select");
224         if (sym_ctx.GetFunctionName() == g_select_symbol)
225         {
226             return false;
227         }
228     }
229     return true;
230 }
231 
232 lldb::queue_id_t
233 SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
234 {
235     queue_id_t queue_id = LLDB_INVALID_QUEUE_ID;
236 
237     if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0)
238         return queue_id;
239 
240     ReadLibdispatchOffsets ();
241     if (m_libdispatch_offsets.IsValid ())
242     {
243         // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
244         // deref it to get the address of the dispatch_queue_t structure for this thread's
245         // queue.
246         Error error;
247         uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error);
248         if (error.Success())
249         {
250             addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum;
251             queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error);
252             if (error.Success())
253             {
254                 queue_id = serialnum;
255             }
256         }
257     }
258 
259     return queue_id;
260 }
261 
262 
263 void
264 SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress ()
265 {
266     if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS)
267         return;
268 
269     static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
270     const Symbol *dispatch_queue_offsets_symbol = NULL;
271 
272     // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
273     ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
274     ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
275     if (module_sp)
276         dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
277 
278     // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
279     if (dispatch_queue_offsets_symbol == NULL)
280     {
281         ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
282         module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
283         if (module_sp)
284             dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
285     }
286     if (dispatch_queue_offsets_symbol)
287         m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
288 }
289 
290 void
291 SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
292 {
293     if (m_libdispatch_offsets.IsValid())
294         return;
295 
296     ReadLibdispatchOffsetsAddress ();
297 
298     uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)];
299     DataExtractor data (memory_buffer,
300                         sizeof(memory_buffer),
301                         m_process->GetByteOrder(),
302                         m_process->GetAddressByteSize());
303 
304     Error error;
305     if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
306     {
307         lldb::offset_t data_offset = 0;
308 
309         // The struct LibdispatchOffsets is a series of uint16_t's - extract them all
310         // in one big go.
311         data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t));
312     }
313 }
314 
315 
316 ThreadSP
317 SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
318 {
319     ThreadSP originating_thread_sp;
320     if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch"))
321     {
322         Error error;
323 
324         // real_thread is either an actual, live thread (in which case we need to call into
325         // libBacktraceRecording to find its originator) or it is an extended backtrace itself,
326         // in which case we get the token from it and call into libBacktraceRecording to find
327         // the originator of that token.
328 
329         if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS)
330         {
331             originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken());
332         }
333         else
334         {
335             ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
336             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);
337             m_page_to_free = LLDB_INVALID_ADDRESS;
338             m_page_to_free_size = 0;
339             if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
340             {
341                 DataBufferHeap data (ret.item_buffer_size, 0);
342                 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
343                 {
344                     DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
345                     ItemInfo item = ExtractItemInfoFromBuffer (extractor);
346                     bool stop_id_is_valid = true;
347                     if (item.stop_id == 0)
348                         stop_id_is_valid = false;
349                     originating_thread_sp.reset (new HistoryThread (*m_process,
350                                                                     item.enqueuing_thread_id,
351                                                                     item.enqueuing_callstack,
352                                                                     item.stop_id,
353                                                                     stop_id_is_valid));
354                     originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
355                     originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
356                     originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
357 //                    originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
358                 }
359                 m_page_to_free = ret.item_buffer_ptr;
360                 m_page_to_free_size = ret.item_buffer_size;
361             }
362         }
363     }
364     return originating_thread_sp;
365 }
366 
367 ThreadSP
368 SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref)
369 {
370     ThreadSP return_thread_sp;
371 
372     AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
373     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
374     Error error;
375     ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
376     m_page_to_free = LLDB_INVALID_ADDRESS;
377     m_page_to_free_size = 0;
378     if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
379     {
380         DataBufferHeap data (ret.item_buffer_size, 0);
381         if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
382         {
383             DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
384             ItemInfo item = ExtractItemInfoFromBuffer (extractor);
385             bool stop_id_is_valid = true;
386             if (item.stop_id == 0)
387                 stop_id_is_valid = false;
388             return_thread_sp.reset (new HistoryThread (*m_process,
389                                                             item.enqueuing_thread_id,
390                                                             item.enqueuing_callstack,
391                                                             item.stop_id,
392                                                             stop_id_is_valid));
393             return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this);
394             return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str());
395             return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum);
396 //            return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
397 
398             m_page_to_free = ret.item_buffer_ptr;
399             m_page_to_free_size = ret.item_buffer_size;
400         }
401     }
402     return return_thread_sp;
403 }
404 
405 ThreadSP
406 SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type)
407 {
408     ThreadSP extended_thread_sp;
409     if (type != ConstString("libdispatch"))
410         return extended_thread_sp;
411 
412     bool stop_id_is_valid = true;
413     if (queue_item_sp->GetStopID() == 0)
414         stop_id_is_valid = false;
415 
416     extended_thread_sp.reset (new HistoryThread (*m_process,
417                                                  queue_item_sp->GetEnqueueingThreadID(),
418                                                  queue_item_sp->GetEnqueueingBacktrace(),
419                                                  queue_item_sp->GetStopID(),
420                                                  stop_id_is_valid));
421     extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis());
422     extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str());
423     extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID());
424 //    extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
425 
426     return extended_thread_sp;
427 }
428 
429 /* Returns true if we were able to get the version / offset information
430  * out of libBacktraceRecording.  false means we were unable to retrieve
431  * this; the queue_info_version field will be 0.
432  */
433 
434 bool
435 SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized ()
436 {
437     if (m_lib_backtrace_recording_info.queue_info_version != 0)
438         return true;
439 
440     addr_t queue_info_version_address = LLDB_INVALID_ADDRESS;
441     addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS;
442     addr_t item_info_version_address = LLDB_INVALID_ADDRESS;
443     addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS;
444     Target &target = m_process->GetTarget();
445 
446 
447     static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version");
448     SymbolContextList sc_list;
449     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0)
450     {
451         SymbolContext sc;
452         sc_list.GetContextAtIndex (0, sc);
453         AddressRange addr_range;
454         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
455         queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
456     }
457     sc_list.Clear();
458 
459     static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset");
460     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0)
461     {
462         SymbolContext sc;
463         sc_list.GetContextAtIndex (0, sc);
464         AddressRange addr_range;
465         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
466         queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
467     }
468     sc_list.Clear();
469 
470     static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version");
471     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0)
472     {
473         SymbolContext sc;
474         sc_list.GetContextAtIndex (0, sc);
475         AddressRange addr_range;
476         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
477         item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
478     }
479     sc_list.Clear();
480 
481     static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset");
482     if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0)
483     {
484         SymbolContext sc;
485         sc_list.GetContextAtIndex (0, sc);
486         AddressRange addr_range;
487         sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range);
488         item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target);
489     }
490 
491     if (queue_info_version_address != LLDB_INVALID_ADDRESS
492         && queue_info_data_offset_address != LLDB_INVALID_ADDRESS
493         && item_info_version_address != LLDB_INVALID_ADDRESS
494         && item_info_data_offset_address != LLDB_INVALID_ADDRESS)
495     {
496         Error error;
497         m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error);
498         if (error.Success())
499         {
500             m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error);
501             if (error.Success())
502             {
503                 m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error);
504                 if (error.Success())
505                 {
506                     m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error);
507                     if (!error.Success())
508                     {
509                         m_lib_backtrace_recording_info.queue_info_version = 0;
510                     }
511                 }
512                 else
513                 {
514                     m_lib_backtrace_recording_info.queue_info_version = 0;
515                 }
516             }
517             else
518             {
519                 m_lib_backtrace_recording_info.queue_info_version = 0;
520             }
521         }
522     }
523 
524     return m_lib_backtrace_recording_info.queue_info_version != 0;
525 }
526 
527 const std::vector<ConstString> &
528 SystemRuntimeMacOSX::GetExtendedBacktraceTypes ()
529 {
530     if (m_types.size () == 0)
531     {
532         m_types.push_back(ConstString("libdispatch"));
533         // We could have pthread as another type in the future if we have a way of
534         // gathering that information & it's useful to distinguish between them.
535     }
536     return m_types;
537 }
538 
539 void
540 SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list)
541 {
542     if (BacktraceRecordingHeadersInitialized())
543     {
544         AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer;
545         ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
546         if (cur_thread_sp)
547         {
548             Error error;
549             queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error);
550             m_page_to_free = LLDB_INVALID_ADDRESS;
551             m_page_to_free_size = 0;
552             if (error.Success())
553             {
554 
555                 if (queue_info_pointer.count > 0
556                     && queue_info_pointer.queues_buffer_size > 0
557                     && queue_info_pointer.queues_buffer_ptr != 0
558                     && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS)
559                 {
560                     PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list);
561                 }
562             }
563         }
564     }
565 
566     // We either didn't have libBacktraceRecording (and need to create the queues list based on threads)
567     // or we did get the queues list from libBacktraceRecording but some special queues may not be
568     // included in its information.  This is needed because libBacktraceRecording
569     // will only list queues with pending or running items by default - but the magic com.apple.main-thread
570     // queue on thread 1 is always around.
571 
572     for (ThreadSP thread_sp : m_process->Threads())
573     {
574         if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID)
575         {
576             if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL)
577             {
578                 QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName()));
579                 queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress()));
580                 queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress());
581                 queue_list.AddQueue (queue_sp);
582             }
583         }
584     }
585 }
586 
587 // Returns either an array of introspection_dispatch_item_info_ref's for the pending items on
588 // a queue or an array introspection_dispatch_item_info_ref's and code addresses for the
589 // pending items on a queue.  The information about each of these pending items then needs to
590 // be fetched individually by passing the ref to libBacktraceRecording.
591 
592 SystemRuntimeMacOSX::PendingItemsForQueue
593 SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue)
594 {
595     PendingItemsForQueue pending_item_refs;
596     AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer;
597     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
598     if (cur_thread_sp)
599     {
600         Error error;
601         pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error);
602         m_page_to_free = LLDB_INVALID_ADDRESS;
603         m_page_to_free_size = 0;
604         if (error.Success())
605         {
606             if (pending_items_pointer.count > 0
607                 && pending_items_pointer.items_buffer_size > 0
608                 && pending_items_pointer.items_buffer_ptr != 0
609                 && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS)
610             {
611                 DataBufferHeap data (pending_items_pointer.items_buffer_size, 0);
612                 if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error))
613                 {
614                     DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
615 
616                     // We either have an array of
617                     //    void* item_ref
618                     // (old style) or we have a structure returned which looks like
619                     //
620                     // struct introspection_dispatch_pending_item_info_s {
621                     //   void *item_ref;
622                     //   void *function_or_block;
623                     // };
624                     //
625                     // struct introspection_dispatch_pending_items_array_s {
626                     //   uint32_t version;
627                     //   uint32_t size_of_item_info;
628                     //   introspection_dispatch_pending_item_info_s items[];
629                     //   }
630 
631                     offset_t offset = 0;
632                     int i = 0;
633                     uint32_t version = extractor.GetU32(&offset);
634                     if (version == 1)
635                     {
636                         pending_item_refs.new_style = true;
637                         uint32_t item_size = extractor.GetU32(&offset);
638                         uint32_t start_of_array_offset = offset;
639                         while (offset < pending_items_pointer.items_buffer_size &&
640                                static_cast<size_t>(i) < pending_items_pointer.count)
641                         {
642                             offset = start_of_array_offset + (i * item_size);
643                             ItemRefAndCodeAddress item;
644                             item.item_ref = extractor.GetPointer (&offset);
645                             item.code_address = extractor.GetPointer (&offset);
646                             pending_item_refs.item_refs_and_code_addresses.push_back (item);
647                             i++;
648                         }
649                     }
650                     else
651                     {
652                         offset = 0;
653                         pending_item_refs.new_style = false;
654                         while (offset < pending_items_pointer.items_buffer_size &&
655                                static_cast<size_t>(i) < pending_items_pointer.count)
656                         {
657                             ItemRefAndCodeAddress item;
658                             item.item_ref = extractor.GetPointer (&offset);
659                             item.code_address = LLDB_INVALID_ADDRESS;
660                             pending_item_refs.item_refs_and_code_addresses.push_back (item);
661                             i++;
662                         }
663                     }
664                 }
665                 m_page_to_free = pending_items_pointer.items_buffer_ptr;
666                 m_page_to_free_size = pending_items_pointer.items_buffer_size;
667             }
668         }
669     }
670     return pending_item_refs;
671 }
672 
673 
674 
675 void
676 SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue)
677 {
678     if (BacktraceRecordingHeadersInitialized())
679     {
680         PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress());
681         for (ItemRefAndCodeAddress pending_item : pending_item_refs.item_refs_and_code_addresses)
682         {
683             Address addr;
684             m_process->GetTarget().ResolveLoadAddress (pending_item.code_address, addr);
685             QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this(), m_process->shared_from_this(), pending_item.item_ref, addr));
686             queue->PushPendingQueueItem (queue_item_sp);
687         }
688     }
689 }
690 
691 void
692 SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref)
693 {
694     AppleGetItemInfoHandler::GetItemInfoReturnInfo ret;
695 
696     ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread());
697     Error error;
698     ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error);
699     m_page_to_free = LLDB_INVALID_ADDRESS;
700     m_page_to_free_size = 0;
701     if (ret.item_buffer_ptr != 0 &&  ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0)
702     {
703         DataBufferHeap data (ret.item_buffer_size, 0);
704         if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success())
705         {
706             DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
707             ItemInfo item = ExtractItemInfoFromBuffer (extractor);
708             queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this);
709             queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id);
710             queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum);
711             queue_item->SetStopID (item.stop_id);
712             queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack);
713             queue_item->SetThreadLabel (item.enqueuing_thread_label);
714             queue_item->SetQueueLabel (item.enqueuing_queue_label);
715             queue_item->SetTargetQueueLabel (item.target_queue_label);
716         }
717         m_page_to_free = ret.item_buffer_ptr;
718         m_page_to_free_size = ret.item_buffer_size;
719     }
720 }
721 
722 void
723 SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size,
724                                                 uint64_t count, lldb_private::QueueList &queue_list)
725 {
726     Error error;
727     DataBufferHeap data (queues_buffer_size, 0);
728     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME));
729     if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success())
730     {
731         // We've read the information out of inferior memory; free it on the next call we make
732         m_page_to_free = queues_buffer;
733         m_page_to_free_size = queues_buffer_size;
734 
735         DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize());
736         offset_t offset = 0;
737         uint64_t queues_read = 0;
738 
739         // The information about the queues is stored in this format (v1):
740         // typedef struct introspection_dispatch_queue_info_s {
741         //     uint32_t offset_to_next;
742         //     dispatch_queue_t queue;
743         //     uint64_t serialnum;     // queue's serialnum in the process, as provided by libdispatch
744         //     uint32_t running_work_items_count;
745         //     uint32_t pending_work_items_count;
746         //
747         //     char data[];     // Starting here, we have variable-length data:
748         //     // char queue_label[];
749         // } introspection_dispatch_queue_info_s;
750 
751         while (queues_read < count && offset < queues_buffer_size)
752         {
753             offset_t    start_of_this_item = offset;
754 
755             uint32_t    offset_to_next = extractor.GetU32 (&offset);
756 
757             offset += 4; // Skip over the 4 bytes of reserved space
758             addr_t      queue = extractor.GetPointer (&offset);
759             uint64_t    serialnum = extractor.GetU64 (&offset);
760             uint32_t    running_work_items_count = extractor.GetU32 (&offset);
761             uint32_t    pending_work_items_count = extractor.GetU32 (&offset);
762 
763             // Read the first field of the variable length data
764             offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset;
765             const char *queue_label = extractor.GetCStr (&offset);
766             if (queue_label == NULL)
767                 queue_label = "";
768 
769             offset_t    start_of_next_item = start_of_this_item + offset_to_next;
770             offset = start_of_next_item;
771 
772             if (log)
773                 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);
774 
775             QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label));
776             queue_sp->SetNumRunningWorkItems (running_work_items_count);
777             queue_sp->SetNumPendingWorkItems (pending_work_items_count);
778             queue_sp->SetLibdispatchQueueAddress (queue);
779             queue_sp->SetKind (GetQueueKind (queue));
780             queue_list.AddQueue (queue_sp);
781             queues_read++;
782         }
783     }
784 }
785 
786 SystemRuntimeMacOSX::ItemInfo
787 SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor)
788 {
789     ItemInfo item;
790 
791     offset_t offset = 0;
792 
793     item.item_that_enqueued_this = extractor.GetPointer (&offset);
794     item.function_or_block = extractor.GetPointer (&offset);
795     item.enqueuing_thread_id = extractor.GetU64 (&offset);
796     item.enqueuing_queue_serialnum = extractor.GetU64 (&offset);
797     item.target_queue_serialnum = extractor.GetU64 (&offset);
798     item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset);
799     item.stop_id = extractor.GetU32 (&offset);
800 
801     offset = m_lib_backtrace_recording_info.item_info_data_offset;
802 
803     for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++)
804     {
805         item.enqueuing_callstack.push_back (extractor.GetPointer (&offset));
806     }
807     item.enqueuing_thread_label = extractor.GetCStr (&offset);
808     item.enqueuing_queue_label = extractor.GetCStr (&offset);
809     item.target_queue_label = extractor.GetCStr (&offset);
810 
811     return item;
812 }
813 
814 void
815 SystemRuntimeMacOSX::Initialize()
816 {
817     PluginManager::RegisterPlugin (GetPluginNameStatic(),
818                                    GetPluginDescriptionStatic(),
819                                    CreateInstance);
820 }
821 
822 void
823 SystemRuntimeMacOSX::Terminate()
824 {
825     PluginManager::UnregisterPlugin (CreateInstance);
826 }
827 
828 
829 lldb_private::ConstString
830 SystemRuntimeMacOSX::GetPluginNameStatic()
831 {
832     static ConstString g_name("systemruntime-macosx");
833     return g_name;
834 }
835 
836 const char *
837 SystemRuntimeMacOSX::GetPluginDescriptionStatic()
838 {
839     return "System runtime plugin for Mac OS X native libraries.";
840 }
841 
842 
843 //------------------------------------------------------------------
844 // PluginInterface protocol
845 //------------------------------------------------------------------
846 lldb_private::ConstString
847 SystemRuntimeMacOSX::GetPluginName()
848 {
849     return GetPluginNameStatic();
850 }
851 
852 uint32_t
853 SystemRuntimeMacOSX::GetPluginVersion()
854 {
855     return 1;
856 }
857