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