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