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