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