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