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