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