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