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 TypeSystemClangSP scratch_ts_sp = 418 ScratchTypeSystemClang::GetForTarget(m_process->GetTarget()); 419 if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) { 420 CompilerType uint16 = 421 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16); 422 CompilerType dispatch_tsd_indexes_s = scratch_ts_sp->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 } else if (type == "Application Specific Backtrace") { 506 StructuredData::ObjectSP thread_extended_sp = 507 real_thread->GetExtendedInfo(); 508 509 if (!thread_extended_sp) 510 return {}; 511 512 StructuredData::Array *thread_extended_info = 513 thread_extended_sp->GetAsArray(); 514 515 if (!thread_extended_info || !thread_extended_info->GetSize()) 516 return {}; 517 518 std::vector<addr_t> app_specific_backtrace_pcs; 519 520 auto extract_frame_pc = 521 [&app_specific_backtrace_pcs](StructuredData::Object *obj) -> bool { 522 if (!obj) 523 return false; 524 525 StructuredData::Dictionary *dict = obj->GetAsDictionary(); 526 if (!dict) 527 return false; 528 529 lldb::addr_t pc = LLDB_INVALID_ADDRESS; 530 if (!dict->GetValueForKeyAsInteger("pc", pc)) 531 return false; 532 533 app_specific_backtrace_pcs.push_back(pc); 534 535 return pc != LLDB_INVALID_ADDRESS; 536 }; 537 538 if (!thread_extended_info->ForEach(extract_frame_pc)) 539 return {}; 540 541 originating_thread_sp = 542 std::make_shared<HistoryThread>(*m_process, real_thread->GetIndexID(), 543 app_specific_backtrace_pcs, true); 544 originating_thread_sp->SetQueueName(type.AsCString()); 545 } 546 return originating_thread_sp; 547 } 548 549 ThreadSP 550 SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef(lldb::addr_t item_ref) { 551 ThreadSP return_thread_sp; 552 553 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 554 ThreadSP cur_thread_sp( 555 m_process->GetThreadList().GetExpressionExecutionThread()); 556 Status error; 557 ret = m_get_item_info_handler.GetItemInfo(*cur_thread_sp.get(), item_ref, 558 m_page_to_free, m_page_to_free_size, 559 error); 560 m_page_to_free = LLDB_INVALID_ADDRESS; 561 m_page_to_free_size = 0; 562 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && 563 ret.item_buffer_size > 0) { 564 DataBufferHeap data(ret.item_buffer_size, 0); 565 if (m_process->ReadMemory(ret.item_buffer_ptr, data.GetBytes(), 566 ret.item_buffer_size, error) && 567 error.Success()) { 568 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 569 m_process->GetByteOrder(), 570 m_process->GetAddressByteSize()); 571 ItemInfo item = ExtractItemInfoFromBuffer(extractor); 572 return_thread_sp = std::make_shared<HistoryThread>( 573 *m_process, item.enqueuing_thread_id, item.enqueuing_callstack); 574 return_thread_sp->SetExtendedBacktraceToken(item.item_that_enqueued_this); 575 return_thread_sp->SetQueueName(item.enqueuing_queue_label.c_str()); 576 return_thread_sp->SetQueueID(item.enqueuing_queue_serialnum); 577 // return_thread_sp->SetThreadName 578 // (item.enqueuing_thread_label.c_str()); 579 580 m_page_to_free = ret.item_buffer_ptr; 581 m_page_to_free_size = ret.item_buffer_size; 582 } 583 } 584 return return_thread_sp; 585 } 586 587 ThreadSP 588 SystemRuntimeMacOSX::GetExtendedBacktraceForQueueItem(QueueItemSP queue_item_sp, 589 ConstString type) { 590 ThreadSP extended_thread_sp; 591 if (type != "libdispatch") 592 return extended_thread_sp; 593 594 extended_thread_sp = std::make_shared<HistoryThread>( 595 *m_process, queue_item_sp->GetEnqueueingThreadID(), 596 queue_item_sp->GetEnqueueingBacktrace()); 597 extended_thread_sp->SetExtendedBacktraceToken( 598 queue_item_sp->GetItemThatEnqueuedThis()); 599 extended_thread_sp->SetQueueName(queue_item_sp->GetQueueLabel().c_str()); 600 extended_thread_sp->SetQueueID(queue_item_sp->GetEnqueueingQueueID()); 601 // extended_thread_sp->SetThreadName 602 // (queue_item_sp->GetThreadLabel().c_str()); 603 604 return extended_thread_sp; 605 } 606 607 /* Returns true if we were able to get the version / offset information 608 * out of libBacktraceRecording. false means we were unable to retrieve 609 * this; the queue_info_version field will be 0. 610 */ 611 612 bool SystemRuntimeMacOSX::BacktraceRecordingHeadersInitialized() { 613 if (m_lib_backtrace_recording_info.queue_info_version != 0) 614 return true; 615 616 addr_t queue_info_version_address = LLDB_INVALID_ADDRESS; 617 addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS; 618 addr_t item_info_version_address = LLDB_INVALID_ADDRESS; 619 addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS; 620 Target &target = m_process->GetTarget(); 621 622 static ConstString introspection_dispatch_queue_info_version( 623 "__introspection_dispatch_queue_info_version"); 624 SymbolContextList sc_list; 625 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 626 introspection_dispatch_queue_info_version, eSymbolTypeData, sc_list); 627 if (!sc_list.IsEmpty()) { 628 SymbolContext sc; 629 sc_list.GetContextAtIndex(0, sc); 630 AddressRange addr_range; 631 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 632 queue_info_version_address = 633 addr_range.GetBaseAddress().GetLoadAddress(&target); 634 } 635 sc_list.Clear(); 636 637 static ConstString introspection_dispatch_queue_info_data_offset( 638 "__introspection_dispatch_queue_info_data_offset"); 639 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 640 introspection_dispatch_queue_info_data_offset, eSymbolTypeData, sc_list); 641 if (!sc_list.IsEmpty()) { 642 SymbolContext sc; 643 sc_list.GetContextAtIndex(0, sc); 644 AddressRange addr_range; 645 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 646 queue_info_data_offset_address = 647 addr_range.GetBaseAddress().GetLoadAddress(&target); 648 } 649 sc_list.Clear(); 650 651 static ConstString introspection_dispatch_item_info_version( 652 "__introspection_dispatch_item_info_version"); 653 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 654 introspection_dispatch_item_info_version, eSymbolTypeData, sc_list); 655 if (!sc_list.IsEmpty()) { 656 SymbolContext sc; 657 sc_list.GetContextAtIndex(0, sc); 658 AddressRange addr_range; 659 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 660 item_info_version_address = 661 addr_range.GetBaseAddress().GetLoadAddress(&target); 662 } 663 sc_list.Clear(); 664 665 static ConstString introspection_dispatch_item_info_data_offset( 666 "__introspection_dispatch_item_info_data_offset"); 667 m_process->GetTarget().GetImages().FindSymbolsWithNameAndType( 668 introspection_dispatch_item_info_data_offset, eSymbolTypeData, sc_list); 669 if (!sc_list.IsEmpty()) { 670 SymbolContext sc; 671 sc_list.GetContextAtIndex(0, sc); 672 AddressRange addr_range; 673 sc.GetAddressRange(eSymbolContextSymbol, 0, false, addr_range); 674 item_info_data_offset_address = 675 addr_range.GetBaseAddress().GetLoadAddress(&target); 676 } 677 678 if (queue_info_version_address != LLDB_INVALID_ADDRESS && 679 queue_info_data_offset_address != LLDB_INVALID_ADDRESS && 680 item_info_version_address != LLDB_INVALID_ADDRESS && 681 item_info_data_offset_address != LLDB_INVALID_ADDRESS) { 682 Status error; 683 m_lib_backtrace_recording_info.queue_info_version = 684 m_process->ReadUnsignedIntegerFromMemory(queue_info_version_address, 2, 685 0, error); 686 if (error.Success()) { 687 m_lib_backtrace_recording_info.queue_info_data_offset = 688 m_process->ReadUnsignedIntegerFromMemory( 689 queue_info_data_offset_address, 2, 0, error); 690 if (error.Success()) { 691 m_lib_backtrace_recording_info.item_info_version = 692 m_process->ReadUnsignedIntegerFromMemory(item_info_version_address, 693 2, 0, error); 694 if (error.Success()) { 695 m_lib_backtrace_recording_info.item_info_data_offset = 696 m_process->ReadUnsignedIntegerFromMemory( 697 item_info_data_offset_address, 2, 0, error); 698 if (!error.Success()) { 699 m_lib_backtrace_recording_info.queue_info_version = 0; 700 } 701 } else { 702 m_lib_backtrace_recording_info.queue_info_version = 0; 703 } 704 } else { 705 m_lib_backtrace_recording_info.queue_info_version = 0; 706 } 707 } 708 } 709 710 return m_lib_backtrace_recording_info.queue_info_version != 0; 711 } 712 713 const std::vector<ConstString> & 714 SystemRuntimeMacOSX::GetExtendedBacktraceTypes() { 715 if (m_types.size() == 0) { 716 m_types.push_back(ConstString("libdispatch")); 717 m_types.push_back(ConstString("Application Specific Backtrace")); 718 // We could have pthread as another type in the future if we have a way of 719 // gathering that information & it's useful to distinguish between them. 720 } 721 return m_types; 722 } 723 724 void SystemRuntimeMacOSX::PopulateQueueList( 725 lldb_private::QueueList &queue_list) { 726 if (BacktraceRecordingHeadersInitialized()) { 727 AppleGetQueuesHandler::GetQueuesReturnInfo queue_info_pointer; 728 ThreadSP cur_thread_sp( 729 m_process->GetThreadList().GetExpressionExecutionThread()); 730 if (cur_thread_sp) { 731 Status error; 732 queue_info_pointer = m_get_queues_handler.GetCurrentQueues( 733 *cur_thread_sp.get(), m_page_to_free, m_page_to_free_size, error); 734 m_page_to_free = LLDB_INVALID_ADDRESS; 735 m_page_to_free_size = 0; 736 if (error.Success()) { 737 738 if (queue_info_pointer.count > 0 && 739 queue_info_pointer.queues_buffer_size > 0 && 740 queue_info_pointer.queues_buffer_ptr != 0 && 741 queue_info_pointer.queues_buffer_ptr != LLDB_INVALID_ADDRESS) { 742 PopulateQueuesUsingLibBTR(queue_info_pointer.queues_buffer_ptr, 743 queue_info_pointer.queues_buffer_size, 744 queue_info_pointer.count, queue_list); 745 } 746 } 747 } 748 } 749 750 // We either didn't have libBacktraceRecording (and need to create the queues 751 // list based on threads) or we did get the queues list from 752 // libBacktraceRecording but some special queues may not be included in its 753 // information. This is needed because libBacktraceRecording will only list 754 // queues with pending or running items by default - but the magic com.apple 755 // .main-thread queue on thread 1 is always around. 756 757 for (ThreadSP thread_sp : m_process->Threads()) { 758 if (thread_sp->GetAssociatedWithLibdispatchQueue() != eLazyBoolNo) { 759 if (thread_sp->GetQueueID() != LLDB_INVALID_QUEUE_ID) { 760 if (queue_list.FindQueueByID(thread_sp->GetQueueID()).get() == 761 nullptr) { 762 QueueSP queue_sp(new Queue(m_process->shared_from_this(), 763 thread_sp->GetQueueID(), 764 thread_sp->GetQueueName())); 765 if (thread_sp->ThreadHasQueueInformation()) { 766 queue_sp->SetKind(thread_sp->GetQueueKind()); 767 queue_sp->SetLibdispatchQueueAddress( 768 thread_sp->GetQueueLibdispatchQueueAddress()); 769 queue_list.AddQueue(queue_sp); 770 } else { 771 queue_sp->SetKind( 772 GetQueueKind(thread_sp->GetQueueLibdispatchQueueAddress())); 773 queue_sp->SetLibdispatchQueueAddress( 774 thread_sp->GetQueueLibdispatchQueueAddress()); 775 queue_list.AddQueue(queue_sp); 776 } 777 } 778 } 779 } 780 } 781 } 782 783 // Returns either an array of introspection_dispatch_item_info_ref's for the 784 // pending items on a queue or an array introspection_dispatch_item_info_ref's 785 // and code addresses for the pending items on a queue. The information about 786 // each of these pending items then needs to be fetched individually by passing 787 // the ref to libBacktraceRecording. 788 789 SystemRuntimeMacOSX::PendingItemsForQueue 790 SystemRuntimeMacOSX::GetPendingItemRefsForQueue(lldb::addr_t queue) { 791 PendingItemsForQueue pending_item_refs = {}; 792 AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer; 793 ThreadSP cur_thread_sp( 794 m_process->GetThreadList().GetExpressionExecutionThread()); 795 if (cur_thread_sp) { 796 Status error; 797 pending_items_pointer = m_get_pending_items_handler.GetPendingItems( 798 *cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, 799 error); 800 m_page_to_free = LLDB_INVALID_ADDRESS; 801 m_page_to_free_size = 0; 802 if (error.Success()) { 803 if (pending_items_pointer.count > 0 && 804 pending_items_pointer.items_buffer_size > 0 && 805 pending_items_pointer.items_buffer_ptr != 0 && 806 pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS) { 807 DataBufferHeap data(pending_items_pointer.items_buffer_size, 0); 808 if (m_process->ReadMemory( 809 pending_items_pointer.items_buffer_ptr, data.GetBytes(), 810 pending_items_pointer.items_buffer_size, error)) { 811 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 812 m_process->GetByteOrder(), 813 m_process->GetAddressByteSize()); 814 815 // We either have an array of 816 // void* item_ref 817 // (old style) or we have a structure returned which looks like 818 // 819 // struct introspection_dispatch_pending_item_info_s { 820 // void *item_ref; 821 // void *function_or_block; 822 // }; 823 // 824 // struct introspection_dispatch_pending_items_array_s { 825 // uint32_t version; 826 // uint32_t size_of_item_info; 827 // introspection_dispatch_pending_item_info_s items[]; 828 // } 829 830 offset_t offset = 0; 831 uint64_t i = 0; 832 uint32_t version = extractor.GetU32(&offset); 833 if (version == 1) { 834 pending_item_refs.new_style = true; 835 uint32_t item_size = extractor.GetU32(&offset); 836 uint32_t start_of_array_offset = offset; 837 while (offset < pending_items_pointer.items_buffer_size && 838 i < pending_items_pointer.count) { 839 offset = start_of_array_offset + (i * item_size); 840 ItemRefAndCodeAddress item; 841 item.item_ref = extractor.GetAddress(&offset); 842 item.code_address = extractor.GetAddress(&offset); 843 pending_item_refs.item_refs_and_code_addresses.push_back(item); 844 i++; 845 } 846 } else { 847 offset = 0; 848 pending_item_refs.new_style = false; 849 while (offset < pending_items_pointer.items_buffer_size && 850 i < pending_items_pointer.count) { 851 ItemRefAndCodeAddress item; 852 item.item_ref = extractor.GetAddress(&offset); 853 item.code_address = LLDB_INVALID_ADDRESS; 854 pending_item_refs.item_refs_and_code_addresses.push_back(item); 855 i++; 856 } 857 } 858 } 859 m_page_to_free = pending_items_pointer.items_buffer_ptr; 860 m_page_to_free_size = pending_items_pointer.items_buffer_size; 861 } 862 } 863 } 864 return pending_item_refs; 865 } 866 867 void SystemRuntimeMacOSX::PopulatePendingItemsForQueue(Queue *queue) { 868 if (BacktraceRecordingHeadersInitialized()) { 869 PendingItemsForQueue pending_item_refs = 870 GetPendingItemRefsForQueue(queue->GetLibdispatchQueueAddress()); 871 for (ItemRefAndCodeAddress pending_item : 872 pending_item_refs.item_refs_and_code_addresses) { 873 Address addr; 874 m_process->GetTarget().ResolveLoadAddress(pending_item.code_address, 875 addr); 876 QueueItemSP queue_item_sp(new QueueItem(queue->shared_from_this(), 877 m_process->shared_from_this(), 878 pending_item.item_ref, addr)); 879 queue->PushPendingQueueItem(queue_item_sp); 880 } 881 } 882 } 883 884 void SystemRuntimeMacOSX::CompleteQueueItem(QueueItem *queue_item, 885 addr_t item_ref) { 886 AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; 887 888 ThreadSP cur_thread_sp( 889 m_process->GetThreadList().GetExpressionExecutionThread()); 890 Status error; 891 ret = m_get_item_info_handler.GetItemInfo(*cur_thread_sp.get(), item_ref, 892 m_page_to_free, m_page_to_free_size, 893 error); 894 m_page_to_free = LLDB_INVALID_ADDRESS; 895 m_page_to_free_size = 0; 896 if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && 897 ret.item_buffer_size > 0) { 898 DataBufferHeap data(ret.item_buffer_size, 0); 899 if (m_process->ReadMemory(ret.item_buffer_ptr, data.GetBytes(), 900 ret.item_buffer_size, error) && 901 error.Success()) { 902 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 903 m_process->GetByteOrder(), 904 m_process->GetAddressByteSize()); 905 ItemInfo item = ExtractItemInfoFromBuffer(extractor); 906 queue_item->SetItemThatEnqueuedThis(item.item_that_enqueued_this); 907 queue_item->SetEnqueueingThreadID(item.enqueuing_thread_id); 908 queue_item->SetEnqueueingQueueID(item.enqueuing_queue_serialnum); 909 queue_item->SetStopID(item.stop_id); 910 queue_item->SetEnqueueingBacktrace(item.enqueuing_callstack); 911 queue_item->SetThreadLabel(item.enqueuing_thread_label); 912 queue_item->SetQueueLabel(item.enqueuing_queue_label); 913 queue_item->SetTargetQueueLabel(item.target_queue_label); 914 } 915 m_page_to_free = ret.item_buffer_ptr; 916 m_page_to_free_size = ret.item_buffer_size; 917 } 918 } 919 920 void SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR( 921 lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, 922 lldb_private::QueueList &queue_list) { 923 Status error; 924 DataBufferHeap data(queues_buffer_size, 0); 925 Log *log = GetLog(LLDBLog::SystemRuntime); 926 if (m_process->ReadMemory(queues_buffer, data.GetBytes(), queues_buffer_size, 927 error) == queues_buffer_size && 928 error.Success()) { 929 // We've read the information out of inferior memory; free it on the next 930 // call we make 931 m_page_to_free = queues_buffer; 932 m_page_to_free_size = queues_buffer_size; 933 934 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 935 m_process->GetByteOrder(), 936 m_process->GetAddressByteSize()); 937 offset_t offset = 0; 938 uint64_t queues_read = 0; 939 940 // The information about the queues is stored in this format (v1): typedef 941 // struct introspection_dispatch_queue_info_s { 942 // uint32_t offset_to_next; 943 // dispatch_queue_t queue; 944 // uint64_t serialnum; // queue's serialnum in the process, as 945 // provided by libdispatch 946 // uint32_t running_work_items_count; 947 // uint32_t pending_work_items_count; 948 // 949 // char data[]; // Starting here, we have variable-length data: 950 // // char queue_label[]; 951 // } introspection_dispatch_queue_info_s; 952 953 while (queues_read < count && offset < queues_buffer_size) { 954 offset_t start_of_this_item = offset; 955 956 uint32_t offset_to_next = extractor.GetU32(&offset); 957 958 offset += 4; // Skip over the 4 bytes of reserved space 959 addr_t queue = extractor.GetAddress(&offset); 960 uint64_t serialnum = extractor.GetU64(&offset); 961 uint32_t running_work_items_count = extractor.GetU32(&offset); 962 uint32_t pending_work_items_count = extractor.GetU32(&offset); 963 964 // Read the first field of the variable length data 965 offset = start_of_this_item + 966 m_lib_backtrace_recording_info.queue_info_data_offset; 967 const char *queue_label = extractor.GetCStr(&offset); 968 if (queue_label == nullptr) 969 queue_label = ""; 970 971 offset_t start_of_next_item = start_of_this_item + offset_to_next; 972 offset = start_of_next_item; 973 974 LLDB_LOGF(log, 975 "SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added " 976 "queue with dispatch_queue_t 0x%" PRIx64 977 ", serial number 0x%" PRIx64 978 ", running items %d, pending items %d, name '%s'", 979 queue, serialnum, running_work_items_count, 980 pending_work_items_count, queue_label); 981 982 QueueSP queue_sp( 983 new Queue(m_process->shared_from_this(), serialnum, queue_label)); 984 queue_sp->SetNumRunningWorkItems(running_work_items_count); 985 queue_sp->SetNumPendingWorkItems(pending_work_items_count); 986 queue_sp->SetLibdispatchQueueAddress(queue); 987 queue_sp->SetKind(GetQueueKind(queue)); 988 queue_list.AddQueue(queue_sp); 989 queues_read++; 990 } 991 } 992 } 993 994 SystemRuntimeMacOSX::ItemInfo SystemRuntimeMacOSX::ExtractItemInfoFromBuffer( 995 lldb_private::DataExtractor &extractor) { 996 ItemInfo item; 997 998 offset_t offset = 0; 999 1000 item.item_that_enqueued_this = extractor.GetAddress(&offset); 1001 item.function_or_block = extractor.GetAddress(&offset); 1002 item.enqueuing_thread_id = extractor.GetU64(&offset); 1003 item.enqueuing_queue_serialnum = extractor.GetU64(&offset); 1004 item.target_queue_serialnum = extractor.GetU64(&offset); 1005 item.enqueuing_callstack_frame_count = extractor.GetU32(&offset); 1006 item.stop_id = extractor.GetU32(&offset); 1007 1008 offset = m_lib_backtrace_recording_info.item_info_data_offset; 1009 1010 for (uint32_t i = 0; i < item.enqueuing_callstack_frame_count; i++) { 1011 item.enqueuing_callstack.push_back(extractor.GetAddress(&offset)); 1012 } 1013 item.enqueuing_thread_label = extractor.GetCStr(&offset); 1014 item.enqueuing_queue_label = extractor.GetCStr(&offset); 1015 item.target_queue_label = extractor.GetCStr(&offset); 1016 1017 return item; 1018 } 1019 1020 void SystemRuntimeMacOSX::Initialize() { 1021 PluginManager::RegisterPlugin( 1022 GetPluginNameStatic(), 1023 "System runtime plugin for Mac OS X native libraries.", CreateInstance); 1024 } 1025 1026 void SystemRuntimeMacOSX::Terminate() { 1027 PluginManager::UnregisterPlugin(CreateInstance); 1028 } 1029