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