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