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