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