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