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