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 lldb::queue_id_t 218 SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr) 219 { 220 queue_id_t queue_id = LLDB_INVALID_QUEUE_ID; 221 222 if (dispatch_qaddr == LLDB_INVALID_ADDRESS || dispatch_qaddr == 0) 223 return queue_id; 224 225 ReadLibdispatchOffsets (); 226 if (m_libdispatch_offsets.IsValid ()) 227 { 228 // dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread - 229 // deref it to get the address of the dispatch_queue_t structure for this thread's 230 // queue. 231 Error error; 232 uint64_t dispatch_queue_addr = m_process->ReadPointerFromMemory (dispatch_qaddr, error); 233 if (error.Success()) 234 { 235 addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets.dqo_serialnum; 236 queue_id_t serialnum = m_process->ReadUnsignedIntegerFromMemory (serialnum_address, m_libdispatch_offsets.dqo_serialnum_size, LLDB_INVALID_QUEUE_ID, error); 237 if (error.Success()) 238 { 239 queue_id = serialnum; 240 } 241 } 242 } 243 244 return queue_id; 245 } 246 247 248 void 249 SystemRuntimeMacOSX::ReadLibdispatchOffsetsAddress () 250 { 251 if (m_dispatch_queue_offsets_addr != LLDB_INVALID_ADDRESS) 252 return; 253 254 static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets"); 255 const Symbol *dispatch_queue_offsets_symbol = NULL; 256 257 // libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard") 258 ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false)); 259 ModuleSP module_sp(m_process->GetTarget().GetImages().FindFirstModule (libSystem_module_spec)); 260 if (module_sp) 261 dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData); 262 263 // libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later 264 if (dispatch_queue_offsets_symbol == NULL) 265 { 266 ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false)); 267 module_sp = m_process->GetTarget().GetImages().FindFirstModule (libdispatch_module_spec); 268 if (module_sp) 269 dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData); 270 } 271 if (dispatch_queue_offsets_symbol) 272 m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget()); 273 } 274 275 void 276 SystemRuntimeMacOSX::ReadLibdispatchOffsets () 277 { 278 if (m_libdispatch_offsets.IsValid()) 279 return; 280 281 ReadLibdispatchOffsetsAddress (); 282 283 uint8_t memory_buffer[sizeof (struct LibdispatchOffsets)]; 284 DataExtractor data (memory_buffer, 285 sizeof(memory_buffer), 286 m_process->GetByteOrder(), 287 m_process->GetAddressByteSize()); 288 289 Error error; 290 if (m_process->ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer)) 291 { 292 lldb::offset_t data_offset = 0; 293 294 // The struct LibdispatchOffsets is a series of uint16_t's - extract them all 295 // in one big go. 296 data.GetU16 (&data_offset, &m_libdispatch_offsets.dqo_version, sizeof (struct LibdispatchOffsets) / sizeof (uint16_t)); 297 } 298 } 299 300 301 ThreadSP 302 SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type) 303 { 304 ThreadSP originating_thread_sp; 305 if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch")) 306 { 307 Error error; 308 309 // real_thread is either an actual, live thread (in which case we need to call into 310 // libBacktraceRecording to find its originator) or it is an extended backtrace itself, 311 // in which case we get the token from it and call into libBacktraceRecording to find 312 // the originator of that token. 313 314 if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS) 315 { 316 originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken()); 317 } 318 else 319 { 320 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); 321 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); 322 m_page_to_free = LLDB_INVALID_ADDRESS; 323 m_page_to_free_size = 0; 324 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) 325 { 326 DataBufferHeap data (ret.item_buffer_size, 0); 327 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) 328 { 329 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 330 ItemInfo item = ExtractItemInfoFromBuffer (extractor); 331 bool stop_id_is_valid = true; 332 if (item.stop_id == 0) 333 stop_id_is_valid = false; 334 originating_thread_sp.reset (new HistoryThread (*m_process, 335 item.enqueuing_thread_id, 336 item.enqueuing_callstack, 337 item.stop_id, 338 stop_id_is_valid)); 339 originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this); 340 originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str()); 341 originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum); 342 // originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str()); 343 } 344 m_page_to_free = ret.item_buffer_ptr; 345 m_page_to_free_size = ret.item_buffer_size; 346 } 347 } 348 } 349 return originating_thread_sp; 350 } 351 352 ThreadSP 353 SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref) 354 { 355 ThreadSP return_thread_sp; 356 357 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 358 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); 359 Error error; 360 ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error); 361 m_page_to_free = LLDB_INVALID_ADDRESS; 362 m_page_to_free_size = 0; 363 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) 364 { 365 DataBufferHeap data (ret.item_buffer_size, 0); 366 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) 367 { 368 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 369 ItemInfo item = ExtractItemInfoFromBuffer (extractor); 370 bool stop_id_is_valid = true; 371 if (item.stop_id == 0) 372 stop_id_is_valid = false; 373 return_thread_sp.reset (new HistoryThread (*m_process, 374 item.enqueuing_thread_id, 375 item.enqueuing_callstack, 376 item.stop_id, 377 stop_id_is_valid)); 378 return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this); 379 return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str()); 380 return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum); 381 // return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str()); 382 383 m_page_to_free = ret.item_buffer_ptr; 384 m_page_to_free_size = ret.item_buffer_size; 385 } 386 } 387 return return_thread_sp; 388 } 389 390 ThreadSP 391 SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem (QueueItemSP queue_item_sp, ConstString type) 392 { 393 ThreadSP extended_thread_sp; 394 if (type != ConstString("libdispatch")) 395 return extended_thread_sp; 396 397 bool stop_id_is_valid = true; 398 if (queue_item_sp->GetStopID() == 0) 399 stop_id_is_valid = false; 400 401 extended_thread_sp.reset (new HistoryThread (*m_process, 402 queue_item_sp->GetEnqueueingThreadID(), 403 queue_item_sp->GetEnqueueingBacktrace(), 404 queue_item_sp->GetStopID(), 405 stop_id_is_valid)); 406 extended_thread_sp->SetExtendedBacktraceToken (queue_item_sp->GetItemThatEnqueuedThis()); 407 extended_thread_sp->SetQueueName (queue_item_sp->GetQueueLabel().c_str()); 408 extended_thread_sp->SetQueueID (queue_item_sp->GetEnqueueingQueueID()); 409 // extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str()); 410 411 return extended_thread_sp; 412 } 413 414 /* Returns true if we were able to get the version / offset information 415 * out of libBacktraceRecording. false means we were unable to retrieve 416 * this; the queue_info_version field will be 0. 417 */ 418 419 bool 420 SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized () 421 { 422 if (m_lib_backtrace_recording_info.queue_info_version != 0) 423 return true; 424 425 addr_t queue_info_version_address = LLDB_INVALID_ADDRESS; 426 addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS; 427 addr_t item_info_version_address = LLDB_INVALID_ADDRESS; 428 addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS; 429 Target &target = m_process->GetTarget(); 430 431 432 static ConstString introspection_dispatch_queue_info_version ("__introspection_dispatch_queue_info_version"); 433 SymbolContextList sc_list; 434 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list) > 0) 435 { 436 SymbolContext sc; 437 sc_list.GetContextAtIndex (0, sc); 438 AddressRange addr_range; 439 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range); 440 queue_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target); 441 } 442 sc_list.Clear(); 443 444 static ConstString introspection_dispatch_queue_info_data_offset ("__introspection_dispatch_queue_info_data_offset"); 445 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list) > 0) 446 { 447 SymbolContext sc; 448 sc_list.GetContextAtIndex (0, sc); 449 AddressRange addr_range; 450 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range); 451 queue_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target); 452 } 453 sc_list.Clear(); 454 455 static ConstString introspection_dispatch_item_info_version ("__introspection_dispatch_item_info_version"); 456 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_version, eSymbolTypeData, sc_list) > 0) 457 { 458 SymbolContext sc; 459 sc_list.GetContextAtIndex (0, sc); 460 AddressRange addr_range; 461 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range); 462 item_info_version_address = addr_range.GetBaseAddress().GetLoadAddress(&target); 463 } 464 sc_list.Clear(); 465 466 static ConstString introspection_dispatch_item_info_data_offset ("__introspection_dispatch_item_info_data_offset"); 467 if (m_process->GetTarget().GetImages().FindSymbolsWithNameAndType (introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list) > 0) 468 { 469 SymbolContext sc; 470 sc_list.GetContextAtIndex (0, sc); 471 AddressRange addr_range; 472 sc.GetAddressRange (eSymbolContextSymbol, 0, false, addr_range); 473 item_info_data_offset_address = addr_range.GetBaseAddress().GetLoadAddress(&target); 474 } 475 476 if (queue_info_version_address != LLDB_INVALID_ADDRESS 477 && queue_info_data_offset_address != LLDB_INVALID_ADDRESS 478 && item_info_version_address != LLDB_INVALID_ADDRESS 479 && item_info_data_offset_address != LLDB_INVALID_ADDRESS) 480 { 481 Error error; 482 m_lib_backtrace_recording_info.queue_info_version = m_process->ReadUnsignedIntegerFromMemory (queue_info_version_address, 2, 0, error); 483 if (error.Success()) 484 { 485 m_lib_backtrace_recording_info.queue_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (queue_info_data_offset_address, 2, 0, error); 486 if (error.Success()) 487 { 488 m_lib_backtrace_recording_info.item_info_version = m_process->ReadUnsignedIntegerFromMemory (item_info_version_address, 2, 0, error); 489 if (error.Success()) 490 { 491 m_lib_backtrace_recording_info.item_info_data_offset = m_process->ReadUnsignedIntegerFromMemory (item_info_data_offset_address, 2, 0, error); 492 if (!error.Success()) 493 { 494 m_lib_backtrace_recording_info.queue_info_version = 0; 495 } 496 } 497 else 498 { 499 m_lib_backtrace_recording_info.queue_info_version = 0; 500 } 501 } 502 else 503 { 504 m_lib_backtrace_recording_info.queue_info_version = 0; 505 } 506 } 507 } 508 509 return m_lib_backtrace_recording_info.queue_info_version != 0; 510 } 511 512 const std::vector<ConstString> & 513 SystemRuntimeMacOSX::GetExtendedBacktraceTypes () 514 { 515 if (m_types.size () == 0) 516 { 517 m_types.push_back(ConstString("libdispatch")); 518 // We could have pthread as another type in the future if we have a way of 519 // gathering that information & it's useful to distinguish between them. 520 } 521 return m_types; 522 } 523 524 void 525 SystemRuntimeMacOSX::PopulateQueueList (lldb_private::QueueList &queue_list) 526 { 527 if (!BacktraceRecordingHeadersInitialized()) 528 { 529 // We don't have libBacktraceRecording -- build the list of queues by looking at 530 // all extant threads, and the queues that they currently belong to. 531 532 for (ThreadSP thread_sp : m_process->Threads()) 533 { 534 if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) 535 { 536 if (queue_list.FindQueueByID (thread_sp->GetQueueID()).get() == NULL) 537 { 538 QueueSP queue_sp (new Queue(m_process->shared_from_this(), thread_sp->GetQueueID(), thread_sp->GetQueueName())); 539 queue_sp->SetKind (GetQueueKind (thread_sp->GetQueueLibdispatchQueueAddress())); 540 queue_sp->SetLibdispatchQueueAddress (thread_sp->GetQueueLibdispatchQueueAddress()); 541 queue_list.AddQueue (queue_sp); 542 } 543 } 544 } 545 } 546 else 547 { 548 AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer; 549 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); 550 if (cur_thread_sp) 551 { 552 Error error; 553 queue_info_pointer = m_get_queues_handler.GetCurrentQueues (*cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error); 554 m_page_to_free = LLDB_INVALID_ADDRESS; 555 m_page_to_free_size = 0; 556 if (error.Success()) 557 { 558 559 if (queue_info_pointer.count > 0 560 && queue_info_pointer.queues_buffer_size > 0 561 && queue_info_pointer.queues_buffer_ptr != 0 562 && queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS) 563 { 564 PopulateQueuesUsingLibBTR (queue_info_pointer.queues_buffer_ptr, queue_info_pointer.queues_buffer_size, queue_info_pointer.count, queue_list); 565 } 566 } 567 } 568 } 569 } 570 571 // Returns either an array of introspection_dispatch_item_info_ref's for the pending items on 572 // a queue or an array introspection_dispatch_item_info_ref's and code addresses for the 573 // pending items on a queue. The information about each of these pending items then needs to 574 // be fetched individually by passing the ref to libBacktraceRecording. 575 576 SystemRuntimeMacOSX::PendingItemsForQueue 577 SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue) 578 { 579 PendingItemsForQueue pending_item_refs; 580 AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer; 581 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); 582 if (cur_thread_sp) 583 { 584 Error error; 585 pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error); 586 m_page_to_free = LLDB_INVALID_ADDRESS; 587 m_page_to_free_size = 0; 588 if (error.Success()) 589 { 590 if (pending_items_pointer.count > 0 591 && pending_items_pointer.items_buffer_size > 0 592 && pending_items_pointer.items_buffer_ptr != 0 593 && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS) 594 { 595 DataBufferHeap data (pending_items_pointer.items_buffer_size, 0); 596 if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error)) 597 { 598 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 599 600 // We either have an array of 601 // void* item_ref 602 // (old style) or we have a structure returned which looks like 603 // 604 // struct introspection_dispatch_pending_item_info_s { 605 // void *item_ref; 606 // void *function_or_block; 607 // }; 608 // 609 // struct introspection_dispatch_pending_items_array_s { 610 // uint32_t version; 611 // uint32_t size_of_item_info; 612 // introspection_dispatch_pending_item_info_s items[]; 613 // } 614 615 offset_t offset = 0; 616 int i = 0; 617 uint32_t version = extractor.GetU32(&offset); 618 if (version == 1) 619 { 620 pending_item_refs.new_style = true; 621 uint32_t item_size = extractor.GetU32(&offset); 622 uint32_t start_of_array_offset = offset; 623 while (offset < pending_items_pointer.items_buffer_size && i < pending_items_pointer.count) 624 { 625 offset = start_of_array_offset + (i * item_size); 626 ItemRefAndCodeAddress item; 627 item.item_ref = extractor.GetPointer (&offset); 628 item.code_address = extractor.GetPointer (&offset); 629 pending_item_refs.item_refs_and_code_addresses.push_back (item); 630 i++; 631 } 632 } 633 else 634 { 635 offset = 0; 636 pending_item_refs.new_style = false; 637 while (offset < pending_items_pointer.items_buffer_size && i < pending_items_pointer.count) 638 { 639 ItemRefAndCodeAddress item; 640 item.item_ref = extractor.GetPointer (&offset); 641 item.code_address = LLDB_INVALID_ADDRESS; 642 pending_item_refs.item_refs_and_code_addresses.push_back (item); 643 i++; 644 } 645 } 646 } 647 m_page_to_free = pending_items_pointer.items_buffer_ptr; 648 m_page_to_free_size = pending_items_pointer.items_buffer_size; 649 } 650 } 651 } 652 return pending_item_refs; 653 } 654 655 656 657 void 658 SystemRuntimeMacOSX::PopulatePendingItemsForQueue (Queue *queue) 659 { 660 if (BacktraceRecordingHeadersInitialized()) 661 { 662 PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue (queue->GetLibdispatchQueueAddress()); 663 for (ItemRefAndCodeAddress pending_item : pending_item_refs.item_refs_and_code_addresses) 664 { 665 Address addr; 666 m_process->GetTarget().ResolveLoadAddress (pending_item.code_address, addr); 667 QueueItemSP queue_item_sp (new QueueItem (queue->shared_from_this(), m_process->shared_from_this(), pending_item.item_ref, addr)); 668 queue->PushPendingQueueItem (queue_item_sp); 669 } 670 } 671 } 672 673 void 674 SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref) 675 { 676 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 677 678 ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); 679 Error error; 680 ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error); 681 m_page_to_free = LLDB_INVALID_ADDRESS; 682 m_page_to_free_size = 0; 683 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) 684 { 685 DataBufferHeap data (ret.item_buffer_size, 0); 686 if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) 687 { 688 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 689 ItemInfo item = ExtractItemInfoFromBuffer (extractor); 690 queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this); 691 queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id); 692 queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum); 693 queue_item->SetStopID (item.stop_id); 694 queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack); 695 queue_item->SetThreadLabel (item.enqueuing_thread_label); 696 queue_item->SetQueueLabel (item.enqueuing_queue_label); 697 queue_item->SetTargetQueueLabel (item.target_queue_label); 698 } 699 m_page_to_free = ret.item_buffer_ptr; 700 m_page_to_free_size = ret.item_buffer_size; 701 } 702 } 703 704 void 705 SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size, 706 uint64_t count, lldb_private::QueueList &queue_list) 707 { 708 Error error; 709 DataBufferHeap data (queues_buffer_size, 0); 710 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); 711 if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success()) 712 { 713 // We've read the information out of inferior memory; free it on the next call we make 714 m_page_to_free = queues_buffer; 715 m_page_to_free_size = queues_buffer_size; 716 717 DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); 718 offset_t offset = 0; 719 uint64_t queues_read = 0; 720 721 // The information about the queues is stored in this format (v1): 722 // typedef struct introspection_dispatch_queue_info_s { 723 // uint32_t offset_to_next; 724 // dispatch_queue_t queue; 725 // uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch 726 // uint32_t running_work_items_count; 727 // uint32_t pending_work_items_count; 728 // 729 // char data[]; // Starting here, we have variable-length data: 730 // // char queue_label[]; 731 // } introspection_dispatch_queue_info_s; 732 733 while (queues_read < count && offset < queues_buffer_size) 734 { 735 offset_t start_of_this_item = offset; 736 737 uint32_t offset_to_next = extractor.GetU32 (&offset); 738 739 offset += 4; // Skip over the 4 bytes of reserved space 740 addr_t queue = extractor.GetPointer (&offset); 741 uint64_t serialnum = extractor.GetU64 (&offset); 742 uint32_t running_work_items_count = extractor.GetU32 (&offset); 743 uint32_t pending_work_items_count = extractor.GetU32 (&offset); 744 745 // Read the first field of the variable length data 746 offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset; 747 const char *queue_label = extractor.GetCStr (&offset); 748 if (queue_label == NULL) 749 queue_label = ""; 750 751 offset_t start_of_next_item = start_of_this_item + offset_to_next; 752 offset = start_of_next_item; 753 754 if (log) 755 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); 756 757 QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label)); 758 queue_sp->SetNumRunningWorkItems (running_work_items_count); 759 queue_sp->SetNumPendingWorkItems (pending_work_items_count); 760 queue_sp->SetLibdispatchQueueAddress (queue); 761 queue_sp->SetKind (GetQueueKind (queue)); 762 queue_list.AddQueue (queue_sp); 763 queues_read++; 764 } 765 } 766 } 767 768 SystemRuntimeMacOSX::ItemInfo 769 SystemRuntimeMacOSX::ExtractItemInfoFromBuffer (lldb_private::DataExtractor &extractor) 770 { 771 ItemInfo item; 772 773 offset_t offset = 0; 774 775 item.item_that_enqueued_this = extractor.GetPointer (&offset); 776 item.function_or_block = extractor.GetPointer (&offset); 777 item.enqueuing_thread_id = extractor.GetU64 (&offset); 778 item.enqueuing_queue_serialnum = extractor.GetU64 (&offset); 779 item.target_queue_serialnum = extractor.GetU64 (&offset); 780 item.enqueuing_callstack_frame_count = extractor.GetU32 (&offset); 781 item.stop_id = extractor.GetU32 (&offset); 782 783 offset = m_lib_backtrace_recording_info.item_info_data_offset; 784 785 for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++) 786 { 787 item.enqueuing_callstack.push_back (extractor.GetPointer (&offset)); 788 } 789 item.enqueuing_thread_label = extractor.GetCStr (&offset); 790 item.enqueuing_queue_label = extractor.GetCStr (&offset); 791 item.target_queue_label = extractor.GetCStr (&offset); 792 793 return item; 794 } 795 796 void 797 SystemRuntimeMacOSX::Initialize() 798 { 799 PluginManager::RegisterPlugin (GetPluginNameStatic(), 800 GetPluginDescriptionStatic(), 801 CreateInstance); 802 } 803 804 void 805 SystemRuntimeMacOSX::Terminate() 806 { 807 PluginManager::UnregisterPlugin (CreateInstance); 808 } 809 810 811 lldb_private::ConstString 812 SystemRuntimeMacOSX::GetPluginNameStatic() 813 { 814 static ConstString g_name("systemruntime-macosx"); 815 return g_name; 816 } 817 818 const char * 819 SystemRuntimeMacOSX::GetPluginDescriptionStatic() 820 { 821 return "System runtime plugin for Mac OS X native libraries."; 822 } 823 824 825 //------------------------------------------------------------------ 826 // PluginInterface protocol 827 //------------------------------------------------------------------ 828 lldb_private::ConstString 829 SystemRuntimeMacOSX::GetPluginName() 830 { 831 return GetPluginNameStatic(); 832 } 833 834 uint32_t 835 SystemRuntimeMacOSX::GetPluginVersion() 836 { 837 return 1; 838 } 839