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