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