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