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