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