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 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 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 94 SystemRuntimeMacOSX::~SystemRuntimeMacOSX() { Clear(true); } 95 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 TypeSystemClang::GetScratch(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, lldb::eAccessPublic, "__lldb_dispatch_tsd_indexes_s", 423 clang::TTK_Struct, lldb::eLanguageTypeC); 424 425 TypeSystemClang::StartTagDeclarationDefinition(dispatch_tsd_indexes_s); 426 TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, 427 "dti_version", uint16, 428 lldb::eAccessPublic, 0); 429 TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, 430 "dti_queue_index", uint16, 431 lldb::eAccessPublic, 0); 432 TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, 433 "dti_voucher_index", uint16, 434 lldb::eAccessPublic, 0); 435 TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, 436 "dti_qos_class_index", uint16, 437 lldb::eAccessPublic, 0); 438 TypeSystemClang::CompleteTagDeclarationDefinition(dispatch_tsd_indexes_s); 439 440 ProcessStructReader struct_reader(m_process, m_dispatch_tsd_indexes_addr, 441 dispatch_tsd_indexes_s); 442 443 m_libdispatch_tsd_indexes.dti_version = 444 struct_reader.GetField<uint16_t>(ConstString("dti_version")); 445 m_libdispatch_tsd_indexes.dti_queue_index = 446 struct_reader.GetField<uint16_t>(ConstString("dti_queue_index")); 447 m_libdispatch_tsd_indexes.dti_voucher_index = 448 struct_reader.GetField<uint16_t>(ConstString("dti_voucher_index")); 449 m_libdispatch_tsd_indexes.dti_qos_class_index = 450 struct_reader.GetField<uint16_t>(ConstString("dti_qos_class_index")); 451 } 452 } 453 } 454 455 ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceThread(ThreadSP real_thread, 456 ConstString type) { 457 ThreadSP originating_thread_sp; 458 if (BacktraceRecordingHeadersInitialized() && type == "libdispatch") { 459 Status error; 460 461 // real_thread is either an actual, live thread (in which case we need to 462 // call into libBacktraceRecording to find its originator) or it is an 463 // extended backtrace itself, in which case we get the token from it and 464 // call into libBacktraceRecording to find the originator of that token. 465 466 if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS) { 467 originating_thread_sp = GetExtendedBacktraceFromItemRef( 468 real_thread->GetExtendedBacktraceToken()); 469 } else { 470 ThreadSP cur_thread_sp( 471 m_process->GetThreadList().GetExpressionExecutionThread()); 472 AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = 473 m_get_thread_item_info_handler.GetThreadItemInfo( 474 *cur_thread_sp.get(), real_thread->GetID(), m_page_to_free, 475 m_page_to_free_size, error); 476 m_page_to_free = LLDB_INVALID_ADDRESS; 477 m_page_to_free_size = 0; 478 if (ret.item_buffer_ptr != 0 && 479 ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && 480 ret.item_buffer_size > 0) { 481 DataBufferHeap data(ret.item_buffer_size, 0); 482 if (m_process->ReadMemory(ret.item_buffer_ptr, data.GetBytes(), 483 ret.item_buffer_size, error) && 484 error.Success()) { 485 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 486 m_process->GetByteOrder(), 487 m_process->GetAddressByteSize()); 488 ItemInfo item = ExtractItemInfoFromBuffer(extractor); 489 originating_thread_sp = std::make_shared<HistoryThread>( 490 *m_process, item.enqueuing_thread_id, item.enqueuing_callstack); 491 originating_thread_sp->SetExtendedBacktraceToken( 492 item.item_that_enqueued_this); 493 originating_thread_sp->SetQueueName( 494 item.enqueuing_queue_label.c_str()); 495 originating_thread_sp->SetQueueID(item.enqueuing_queue_serialnum); 496 // originating_thread_sp->SetThreadName 497 // (item.enqueuing_thread_label.c_str()); 498 } 499 m_page_to_free = ret.item_buffer_ptr; 500 m_page_to_free_size = ret.item_buffer_size; 501 } 502 } 503 } 504 return originating_thread_sp; 505 } 506 507 ThreadSP 508 SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef(lldb::addr_t item_ref) { 509 ThreadSP return_thread_sp; 510 511 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 512 ThreadSP cur_thread_sp( 513 m_process->GetThreadList().GetExpressionExecutionThread()); 514 Status error; 515 ret = m_get_item_info_handler.GetItemInfo(*cur_thread_sp.get(), item_ref, 516 m_page_to_free, m_page_to_free_size, 517 error); 518 m_page_to_free = LLDB_INVALID_ADDRESS; 519 m_page_to_free_size = 0; 520 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && 521 ret.item_buffer_size > 0) { 522 DataBufferHeap data(ret.item_buffer_size, 0); 523 if (m_process->ReadMemory(ret.item_buffer_ptr, data.GetBytes(), 524 ret.item_buffer_size, error) && 525 error.Success()) { 526 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 527 m_process->GetByteOrder(), 528 m_process->GetAddressByteSize()); 529 ItemInfo item = ExtractItemInfoFromBuffer(extractor); 530 return_thread_sp = std::make_shared<HistoryThread>( 531 *m_process, item.enqueuing_thread_id, item.enqueuing_callstack); 532 return_thread_sp->SetExtendedBacktraceToken(item.item_that_enqueued_this); 533 return_thread_sp->SetQueueName(item.enqueuing_queue_label.c_str()); 534 return_thread_sp->SetQueueID(item.enqueuing_queue_serialnum); 535 // return_thread_sp->SetThreadName 536 // (item.enqueuing_thread_label.c_str()); 537 538 m_page_to_free = ret.item_buffer_ptr; 539 m_page_to_free_size = ret.item_buffer_size; 540 } 541 } 542 return return_thread_sp; 543 } 544 545 ThreadSP 546 SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem(QueueItemSP queue_item_sp, 547 ConstString type) { 548 ThreadSP extended_thread_sp; 549 if (type != "libdispatch") 550 return extended_thread_sp; 551 552 extended_thread_sp = std::make_shared<HistoryThread>( 553 *m_process, queue_item_sp->GetEnqueueingThreadID(), 554 queue_item_sp->GetEnqueueingBacktrace()); 555 extended_thread_sp->SetExtendedBacktraceToken( 556 queue_item_sp->GetItemThatEnqueuedThis()); 557 extended_thread_sp->SetQueueName(queue_item_sp->GetQueueLabel().c_str()); 558 extended_thread_sp->SetQueueID(queue_item_sp->GetEnqueueingQueueID()); 559 // extended_thread_sp->SetThreadName 560 // (queue_item_sp->GetThreadLabel().c_str()); 561 562 return extended_thread_sp; 563 } 564 565 /* Returns true if we were able to get the version / offset information 566 * out of libBacktraceRecording. false means we were unable to retrieve 567 * this; the queue_info_version field will be 0. 568 */ 569 570 bool SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized() { 571 if (m_lib_backtrace_recording_info.queue_info_version != 0) 572 return true; 573 574 addr_t queue_info_version_address = LLDB_INVALID_ADDRESS; 575 addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS; 576 addr_t item_info_version_address = LLDB_INVALID_ADDRESS; 577 addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS; 578 Target &target = m_process->GetTarget(); 579 580 static ConstString introspection_dispatch_queue_info_version( 581 "__introspection_dispatch_queue_info_version"); 582 SymbolContextList sc_list; 583 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 584 introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list); 585 if (!sc_list.IsEmpty()) { 586 SymbolContext sc; 587 sc_list.GetContextAtIndex(0, sc); 588 AddressRange addr_range; 589 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 590 queue_info_version_address = 591 addr_range.GetBaseAddress().GetLoadAddress(&target); 592 } 593 sc_list.Clear(); 594 595 static ConstString introspection_dispatch_queue_info_data_offset( 596 "__introspection_dispatch_queue_info_data_offset"); 597 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 598 introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list); 599 if (!sc_list.IsEmpty()) { 600 SymbolContext sc; 601 sc_list.GetContextAtIndex(0, sc); 602 AddressRange addr_range; 603 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 604 queue_info_data_offset_address = 605 addr_range.GetBaseAddress().GetLoadAddress(&target); 606 } 607 sc_list.Clear(); 608 609 static ConstString introspection_dispatch_item_info_version( 610 "__introspection_dispatch_item_info_version"); 611 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 612 introspection_dispatch_item_info_version, eSymbolTypeData, sc_list); 613 if (!sc_list.IsEmpty()) { 614 SymbolContext sc; 615 sc_list.GetContextAtIndex(0, sc); 616 AddressRange addr_range; 617 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 618 item_info_version_address = 619 addr_range.GetBaseAddress().GetLoadAddress(&target); 620 } 621 sc_list.Clear(); 622 623 static ConstString introspection_dispatch_item_info_data_offset( 624 "__introspection_dispatch_item_info_data_offset"); 625 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 626 introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list); 627 if (!sc_list.IsEmpty()) { 628 SymbolContext sc; 629 sc_list.GetContextAtIndex(0, sc); 630 AddressRange addr_range; 631 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 632 item_info_data_offset_address = 633 addr_range.GetBaseAddress().GetLoadAddress(&target); 634 } 635 636 if (queue_info_version_address != LLDB_INVALID_ADDRESS && 637 queue_info_data_offset_address != LLDB_INVALID_ADDRESS && 638 item_info_version_address != LLDB_INVALID_ADDRESS && 639 item_info_data_offset_address != LLDB_INVALID_ADDRESS) { 640 Status error; 641 m_lib_backtrace_recording_info.queue_info_version = 642 m_process->ReadUnsignedIntegerFromMemory(queue_info_version_address, 2, 643 0, error); 644 if (error.Success()) { 645 m_lib_backtrace_recording_info.queue_info_data_offset = 646 m_process->ReadUnsignedIntegerFromMemory( 647 queue_info_data_offset_address, 2, 0, error); 648 if (error.Success()) { 649 m_lib_backtrace_recording_info.item_info_version = 650 m_process->ReadUnsignedIntegerFromMemory(item_info_version_address, 651 2, 0, error); 652 if (error.Success()) { 653 m_lib_backtrace_recording_info.item_info_data_offset = 654 m_process->ReadUnsignedIntegerFromMemory( 655 item_info_data_offset_address, 2, 0, error); 656 if (!error.Success()) { 657 m_lib_backtrace_recording_info.queue_info_version = 0; 658 } 659 } else { 660 m_lib_backtrace_recording_info.queue_info_version = 0; 661 } 662 } else { 663 m_lib_backtrace_recording_info.queue_info_version = 0; 664 } 665 } 666 } 667 668 return m_lib_backtrace_recording_info.queue_info_version != 0; 669 } 670 671 const std::vector<ConstString> & 672 SystemRuntimeMacOSX::GetExtendedBacktraceTypes() { 673 if (m_types.size() == 0) { 674 m_types.push_back(ConstString("libdispatch")); 675 // We could have pthread as another type in the future if we have a way of 676 // gathering that information & it's useful to distinguish between them. 677 } 678 return m_types; 679 } 680 681 void SystemRuntimeMacOSX::PopulateQueueList( 682 lldb_private::QueueList &queue_list) { 683 if (BacktraceRecordingHeadersInitialized()) { 684 AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer; 685 ThreadSP cur_thread_sp( 686 m_process->GetThreadList().GetExpressionExecutionThread()); 687 if (cur_thread_sp) { 688 Status error; 689 queue_info_pointer = m_get_queues_handler.GetCurrentQueues( 690 *cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error); 691 m_page_to_free = LLDB_INVALID_ADDRESS; 692 m_page_to_free_size = 0; 693 if (error.Success()) { 694 695 if (queue_info_pointer.count > 0 && 696 queue_info_pointer.queues_buffer_size > 0 && 697 queue_info_pointer.queues_buffer_ptr != 0 && 698 queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS) { 699 PopulateQueuesUsingLibBTR(queue_info_pointer.queues_buffer_ptr, 700 queue_info_pointer.queues_buffer_size, 701 queue_info_pointer.count, queue_list); 702 } 703 } 704 } 705 } 706 707 // We either didn't have libBacktraceRecording (and need to create the queues 708 // list based on threads) or we did get the queues list from 709 // libBacktraceRecording but some special queues may not be included in its 710 // information. This is needed because libBacktraceRecording will only list 711 // queues with pending or running items by default - but the magic com.apple 712 // .main-thread queue on thread 1 is always around. 713 714 for (ThreadSP thread_sp : m_process->Threads()) { 715 if (thread_sp->GetAssociatedWithLibdispatchQueue() != eLazyBoolNo) { 716 if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) { 717 if (queue_list.FindQueueByID(thread_sp->GetQueueID()).get() == 718 nullptr) { 719 QueueSP queue_sp(new Queue(m_process->shared_from_this(), 720 thread_sp->GetQueueID(), 721 thread_sp->GetQueueName())); 722 if (thread_sp->ThreadHasQueueInformation()) { 723 queue_sp->SetKind(thread_sp->GetQueueKind()); 724 queue_sp->SetLibdispatchQueueAddress( 725 thread_sp->GetQueueLibdispatchQueueAddress()); 726 queue_list.AddQueue(queue_sp); 727 } else { 728 queue_sp->SetKind( 729 GetQueueKind(thread_sp->GetQueueLibdispatchQueueAddress())); 730 queue_sp->SetLibdispatchQueueAddress( 731 thread_sp->GetQueueLibdispatchQueueAddress()); 732 queue_list.AddQueue(queue_sp); 733 } 734 } 735 } 736 } 737 } 738 } 739 740 // Returns either an array of introspection_dispatch_item_info_ref's for the 741 // pending items on a queue or an array introspection_dispatch_item_info_ref's 742 // and code addresses for the pending items on a queue. The information about 743 // each of these pending items then needs to be fetched individually by passing 744 // the ref to libBacktraceRecording. 745 746 SystemRuntimeMacOSX::PendingItemsForQueue 747 SystemRuntimeMacOSX::GetPendingItemRefsForQueue(lldb::addr_t queue) { 748 PendingItemsForQueue pending_item_refs; 749 AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer; 750 ThreadSP cur_thread_sp( 751 m_process->GetThreadList().GetExpressionExecutionThread()); 752 if (cur_thread_sp) { 753 Status error; 754 pending_items_pointer = m_get_pending_items_handler.GetPendingItems( 755 *cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, 756 error); 757 m_page_to_free = LLDB_INVALID_ADDRESS; 758 m_page_to_free_size = 0; 759 if (error.Success()) { 760 if (pending_items_pointer.count > 0 && 761 pending_items_pointer.items_buffer_size > 0 && 762 pending_items_pointer.items_buffer_ptr != 0 && 763 pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS) { 764 DataBufferHeap data(pending_items_pointer.items_buffer_size, 0); 765 if (m_process->ReadMemory( 766 pending_items_pointer.items_buffer_ptr, data.GetBytes(), 767 pending_items_pointer.items_buffer_size, error)) { 768 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 769 m_process->GetByteOrder(), 770 m_process->GetAddressByteSize()); 771 772 // We either have an array of 773 // void* item_ref 774 // (old style) or we have a structure returned which looks like 775 // 776 // struct introspection_dispatch_pending_item_info_s { 777 // void *item_ref; 778 // void *function_or_block; 779 // }; 780 // 781 // struct introspection_dispatch_pending_items_array_s { 782 // uint32_t version; 783 // uint32_t size_of_item_info; 784 // introspection_dispatch_pending_item_info_s items[]; 785 // } 786 787 offset_t offset = 0; 788 int i = 0; 789 uint32_t version = extractor.GetU32(&offset); 790 if (version == 1) { 791 pending_item_refs.new_style = true; 792 uint32_t item_size = extractor.GetU32(&offset); 793 uint32_t start_of_array_offset = offset; 794 while (offset < pending_items_pointer.items_buffer_size && 795 static_cast<size_t>(i) < pending_items_pointer.count) { 796 offset = start_of_array_offset + (i * item_size); 797 ItemRefAndCodeAddress item; 798 item.item_ref = extractor.GetPointer(&offset); 799 item.code_address = extractor.GetPointer(&offset); 800 pending_item_refs.item_refs_and_code_addresses.push_back(item); 801 i++; 802 } 803 } else { 804 offset = 0; 805 pending_item_refs.new_style = false; 806 while (offset < pending_items_pointer.items_buffer_size && 807 static_cast<size_t>(i) < pending_items_pointer.count) { 808 ItemRefAndCodeAddress item; 809 item.item_ref = extractor.GetPointer(&offset); 810 item.code_address = LLDB_INVALID_ADDRESS; 811 pending_item_refs.item_refs_and_code_addresses.push_back(item); 812 i++; 813 } 814 } 815 } 816 m_page_to_free = pending_items_pointer.items_buffer_ptr; 817 m_page_to_free_size = pending_items_pointer.items_buffer_size; 818 } 819 } 820 } 821 return pending_item_refs; 822 } 823 824 void SystemRuntimeMacOSX::PopulatePendingItemsForQueue(Queue *queue) { 825 if (BacktraceRecordingHeadersInitialized()) { 826 PendingItemsForQueue pending_item_refs = 827 GetPendingItemRefsForQueue(queue->GetLibdispatchQueueAddress()); 828 for (ItemRefAndCodeAddress pending_item : 829 pending_item_refs.item_refs_and_code_addresses) { 830 Address addr; 831 m_process->GetTarget().ResolveLoadAddress(pending_item.code_address, 832 addr); 833 QueueItemSP queue_item_sp(new QueueItem(queue->shared_from_this(), 834 m_process->shared_from_this(), 835 pending_item.item_ref, addr)); 836 queue->PushPendingQueueItem(queue_item_sp); 837 } 838 } 839 } 840 841 void SystemRuntimeMacOSX::CompleteQueueItem(QueueItem *queue_item, 842 addr_t item_ref) { 843 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 844 845 ThreadSP cur_thread_sp( 846 m_process->GetThreadList().GetExpressionExecutionThread()); 847 Status error; 848 ret = m_get_item_info_handler.GetItemInfo(*cur_thread_sp.get(), item_ref, 849 m_page_to_free, m_page_to_free_size, 850 error); 851 m_page_to_free = LLDB_INVALID_ADDRESS; 852 m_page_to_free_size = 0; 853 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && 854 ret.item_buffer_size > 0) { 855 DataBufferHeap data(ret.item_buffer_size, 0); 856 if (m_process->ReadMemory(ret.item_buffer_ptr, data.GetBytes(), 857 ret.item_buffer_size, error) && 858 error.Success()) { 859 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 860 m_process->GetByteOrder(), 861 m_process->GetAddressByteSize()); 862 ItemInfo item = ExtractItemInfoFromBuffer(extractor); 863 queue_item->SetItemThatEnqueuedThis(item.item_that_enqueued_this); 864 queue_item->SetEnqueueingThreadID(item.enqueuing_thread_id); 865 queue_item->SetEnqueueingQueueID(item.enqueuing_queue_serialnum); 866 queue_item->SetStopID(item.stop_id); 867 queue_item->SetEnqueueingBacktrace(item.enqueuing_callstack); 868 queue_item->SetThreadLabel(item.enqueuing_thread_label); 869 queue_item->SetQueueLabel(item.enqueuing_queue_label); 870 queue_item->SetTargetQueueLabel(item.target_queue_label); 871 } 872 m_page_to_free = ret.item_buffer_ptr; 873 m_page_to_free_size = ret.item_buffer_size; 874 } 875 } 876 877 void SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR( 878 lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, 879 lldb_private::QueueList &queue_list) { 880 Status error; 881 DataBufferHeap data(queues_buffer_size, 0); 882 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME)); 883 if (m_process->ReadMemory(queues_buffer, data.GetBytes(), queues_buffer_size, 884 error) == queues_buffer_size && 885 error.Success()) { 886 // We've read the information out of inferior memory; free it on the next 887 // call we make 888 m_page_to_free = queues_buffer; 889 m_page_to_free_size = queues_buffer_size; 890 891 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 892 m_process->GetByteOrder(), 893 m_process->GetAddressByteSize()); 894 offset_t offset = 0; 895 uint64_t queues_read = 0; 896 897 // The information about the queues is stored in this format (v1): typedef 898 // struct introspection_dispatch_queue_info_s { 899 // uint32_t offset_to_next; 900 // dispatch_queue_t queue; 901 // uint64_t serialnum; // queue's serialnum in the process, as 902 // provided by libdispatch 903 // uint32_t running_work_items_count; 904 // uint32_t pending_work_items_count; 905 // 906 // char data[]; // Starting here, we have variable-length data: 907 // // char queue_label[]; 908 // } introspection_dispatch_queue_info_s; 909 910 while (queues_read < count && offset < queues_buffer_size) { 911 offset_t start_of_this_item = offset; 912 913 uint32_t offset_to_next = extractor.GetU32(&offset); 914 915 offset += 4; // Skip over the 4 bytes of reserved space 916 addr_t queue = extractor.GetPointer(&offset); 917 uint64_t serialnum = extractor.GetU64(&offset); 918 uint32_t running_work_items_count = extractor.GetU32(&offset); 919 uint32_t pending_work_items_count = extractor.GetU32(&offset); 920 921 // Read the first field of the variable length data 922 offset = start_of_this_item + 923 m_lib_backtrace_recording_info.queue_info_data_offset; 924 const char *queue_label = extractor.GetCStr(&offset); 925 if (queue_label == nullptr) 926 queue_label = ""; 927 928 offset_t start_of_next_item = start_of_this_item + offset_to_next; 929 offset = start_of_next_item; 930 931 LLDB_LOGF(log, 932 "SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added " 933 "queue with dispatch_queue_t 0x%" PRIx64 934 ", serial number 0x%" PRIx64 935 ", running items %d, pending items %d, name '%s'", 936 queue, serialnum, running_work_items_count, 937 pending_work_items_count, queue_label); 938 939 QueueSP queue_sp( 940 new Queue(m_process->shared_from_this(), serialnum, queue_label)); 941 queue_sp->SetNumRunningWorkItems(running_work_items_count); 942 queue_sp->SetNumPendingWorkItems(pending_work_items_count); 943 queue_sp->SetLibdispatchQueueAddress(queue); 944 queue_sp->SetKind(GetQueueKind(queue)); 945 queue_list.AddQueue(queue_sp); 946 queues_read++; 947 } 948 } 949 } 950 951 SystemRuntimeMacOSX::ItemInfo SystemRuntimeMacOSX::ExtractItemInfoFromBuffer( 952 lldb_private::DataExtractor &extractor) { 953 ItemInfo item; 954 955 offset_t offset = 0; 956 957 item.item_that_enqueued_this = extractor.GetPointer(&offset); 958 item.function_or_block = extractor.GetPointer(&offset); 959 item.enqueuing_thread_id = extractor.GetU64(&offset); 960 item.enqueuing_queue_serialnum = extractor.GetU64(&offset); 961 item.target_queue_serialnum = extractor.GetU64(&offset); 962 item.enqueuing_callstack_frame_count = extractor.GetU32(&offset); 963 item.stop_id = extractor.GetU32(&offset); 964 965 offset = m_lib_backtrace_recording_info.item_info_data_offset; 966 967 for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++) { 968 item.enqueuing_callstack.push_back(extractor.GetPointer(&offset)); 969 } 970 item.enqueuing_thread_label = extractor.GetCStr(&offset); 971 item.enqueuing_queue_label = extractor.GetCStr(&offset); 972 item.target_queue_label = extractor.GetCStr(&offset); 973 974 return item; 975 } 976 977 void SystemRuntimeMacOSX::Initialize() { 978 PluginManager::RegisterPlugin(GetPluginNameStatic(), 979 GetPluginDescriptionStatic(), CreateInstance); 980 } 981 982 void SystemRuntimeMacOSX::Terminate() { 983 PluginManager::UnregisterPlugin(CreateInstance); 984 } 985 986 lldb_private::ConstString SystemRuntimeMacOSX::GetPluginNameStatic() { 987 static ConstString g_name("systemruntime-macosx"); 988 return g_name; 989 } 990 991 const char *SystemRuntimeMacOSX::GetPluginDescriptionStatic() { 992 return "System runtime plugin for Mac OS X native libraries."; 993 } 994 995 // PluginInterface protocol 996 lldb_private::ConstString SystemRuntimeMacOSX::GetPluginName() { 997 return GetPluginNameStatic(); 998 } 999 1000 uint32_t SystemRuntimeMacOSX::GetPluginVersion() { return 1; } 1001