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