void SystemRuntimeMacOSX::CompleteQueueItem (QueueItem *queue_item, addr_t item_ref) { AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); Error error; ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error); m_page_to_free = LLDB_INVALID_ADDRESS; m_page_to_free_size = 0; if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) { DataBufferHeap data (ret.item_buffer_size, 0); if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) { DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); ItemInfo item = ExtractItemInfoFromBuffer (extractor); queue_item->SetItemThatEnqueuedThis (item.item_that_enqueued_this); queue_item->SetEnqueueingThreadID (item.enqueuing_thread_id); queue_item->SetEnqueueingQueueID (item.enqueuing_queue_serialnum); queue_item->SetStopID (item.stop_id); queue_item->SetEnqueueingBacktrace (item.enqueuing_callstack); queue_item->SetThreadLabel (item.enqueuing_thread_label); queue_item->SetQueueLabel (item.enqueuing_queue_label); queue_item->SetTargetQueueLabel (item.target_queue_label); } m_page_to_free = ret.item_buffer_ptr; m_page_to_free_size = ret.item_buffer_size; } }
ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type) { ThreadSP originating_thread_sp; if (BacktraceRecordingHeadersInitialized() && type == ConstString ("libdispatch")) { Error error; // real_thread is either an actual, live thread (in which case we need to call into // libBacktraceRecording to find its originator) or it is an extended backtrace itself, // in which case we get the token from it and call into libBacktraceRecording to find // the originator of that token. if (real_thread->GetExtendedBacktraceToken() != LLDB_INVALID_ADDRESS) { originating_thread_sp = GetExtendedBacktraceFromItemRef (real_thread->GetExtendedBacktraceToken()); } else { ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); AppleGetThreadItemInfoHandler::GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler.GetThreadItemInfo (*cur_thread_sp.get(), real_thread->GetID(), m_page_to_free, m_page_to_free_size, error); m_page_to_free = LLDB_INVALID_ADDRESS; m_page_to_free_size = 0; if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) { DataBufferHeap data (ret.item_buffer_size, 0); if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) { DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); ItemInfo item = ExtractItemInfoFromBuffer (extractor); bool stop_id_is_valid = true; if (item.stop_id == 0) stop_id_is_valid = false; originating_thread_sp.reset (new HistoryThread (*m_process, item.enqueuing_thread_id, item.enqueuing_callstack, item.stop_id, stop_id_is_valid)); originating_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this); originating_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str()); originating_thread_sp->SetQueueID (item.enqueuing_queue_serialnum); // originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str()); } m_page_to_free = ret.item_buffer_ptr; m_page_to_free_size = ret.item_buffer_size; } } } return originating_thread_sp; }
ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceFromItemRef (lldb::addr_t item_ref) { ThreadSP return_thread_sp; AppleGetItemInfoHandler::GetItemInfoReturnInfo ret; ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); Error error; ret = m_get_item_info_handler.GetItemInfo (*cur_thread_sp.get(), item_ref, m_page_to_free, m_page_to_free_size, error); m_page_to_free = LLDB_INVALID_ADDRESS; m_page_to_free_size = 0; if (ret.item_buffer_ptr != 0 && ret.item_buffer_ptr != LLDB_INVALID_ADDRESS && ret.item_buffer_size > 0) { DataBufferHeap data (ret.item_buffer_size, 0); if (m_process->ReadMemory (ret.item_buffer_ptr, data.GetBytes(), ret.item_buffer_size, error) && error.Success()) { DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); ItemInfo item = ExtractItemInfoFromBuffer (extractor); bool stop_id_is_valid = true; if (item.stop_id == 0) stop_id_is_valid = false; return_thread_sp.reset (new HistoryThread (*m_process, item.enqueuing_thread_id, item.enqueuing_callstack, item.stop_id, stop_id_is_valid)); return_thread_sp->SetExtendedBacktraceToken (item.item_that_enqueued_this); return_thread_sp->SetQueueName (item.enqueuing_queue_label.c_str()); return_thread_sp->SetQueueID (item.enqueuing_queue_serialnum); // return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str()); m_page_to_free = ret.item_buffer_ptr; m_page_to_free_size = ret.item_buffer_size; } } return return_thread_sp; }
void SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR (lldb::addr_t queues_buffer, uint64_t queues_buffer_size, uint64_t count, lldb_private::QueueList &queue_list) { Error error; DataBufferHeap data (queues_buffer_size, 0); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYSTEM_RUNTIME)); if (m_process->ReadMemory (queues_buffer, data.GetBytes(), queues_buffer_size, error) == queues_buffer_size && error.Success()) { // We've read the information out of inferior memory; free it on the next call we make m_page_to_free = queues_buffer; m_page_to_free_size = queues_buffer_size; DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); offset_t offset = 0; uint64_t queues_read = 0; // The information about the queues is stored in this format (v1): // typedef struct introspection_dispatch_queue_info_s { // uint32_t offset_to_next; // dispatch_queue_t queue; // uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch // uint32_t running_work_items_count; // uint32_t pending_work_items_count; // // char data[]; // Starting here, we have variable-length data: // // char queue_label[]; // } introspection_dispatch_queue_info_s; while (queues_read < count && offset < queues_buffer_size) { offset_t start_of_this_item = offset; uint32_t offset_to_next = extractor.GetU32 (&offset); offset += 4; // Skip over the 4 bytes of reserved space addr_t queue = extractor.GetPointer (&offset); uint64_t serialnum = extractor.GetU64 (&offset); uint32_t running_work_items_count = extractor.GetU32 (&offset); uint32_t pending_work_items_count = extractor.GetU32 (&offset); // Read the first field of the variable length data offset = start_of_this_item + m_lib_backtrace_recording_info.queue_info_data_offset; const char *queue_label = extractor.GetCStr (&offset); if (queue_label == NULL) queue_label = ""; offset_t start_of_next_item = start_of_this_item + offset_to_next; offset = start_of_next_item; if (log) log->Printf ("SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added queue with dispatch_queue_t 0x%" PRIx64 ", serial number 0x%" PRIx64 ", running items %d, pending items %d, name '%s'", queue, serialnum, running_work_items_count, pending_work_items_count, queue_label); QueueSP queue_sp (new Queue (m_process->shared_from_this(), serialnum, queue_label)); queue_sp->SetNumRunningWorkItems (running_work_items_count); queue_sp->SetNumPendingWorkItems (pending_work_items_count); queue_sp->SetLibdispatchQueueAddress (queue); queue_sp->SetKind (GetQueueKind (queue)); queue_list.AddQueue (queue_sp); queues_read++; } } }
SystemRuntimeMacOSX::PendingItemsForQueue SystemRuntimeMacOSX::GetPendingItemRefsForQueue (lldb::addr_t queue) { PendingItemsForQueue pending_item_refs; AppleGetPendingItemsHandler::GetPendingItemsReturnInfo pending_items_pointer; ThreadSP cur_thread_sp (m_process->GetThreadList().GetSelectedThread()); if (cur_thread_sp) { Error error; pending_items_pointer = m_get_pending_items_handler.GetPendingItems (*cur_thread_sp.get(), queue, m_page_to_free, m_page_to_free_size, error); m_page_to_free = LLDB_INVALID_ADDRESS; m_page_to_free_size = 0; if (error.Success()) { if (pending_items_pointer.count > 0 && pending_items_pointer.items_buffer_size > 0 && pending_items_pointer.items_buffer_ptr != 0 && pending_items_pointer.items_buffer_ptr != LLDB_INVALID_ADDRESS) { DataBufferHeap data (pending_items_pointer.items_buffer_size, 0); if (m_process->ReadMemory (pending_items_pointer.items_buffer_ptr, data.GetBytes(), pending_items_pointer.items_buffer_size, error)) { DataExtractor extractor (data.GetBytes(), data.GetByteSize(), m_process->GetByteOrder(), m_process->GetAddressByteSize()); // We either have an array of // void* item_ref // (old style) or we have a structure returned which looks like // // struct introspection_dispatch_pending_item_info_s { // void *item_ref; // void *function_or_block; // }; // // struct introspection_dispatch_pending_items_array_s { // uint32_t version; // uint32_t size_of_item_info; // introspection_dispatch_pending_item_info_s items[]; // } offset_t offset = 0; int i = 0; uint32_t version = extractor.GetU32(&offset); if (version == 1) { pending_item_refs.new_style = true; uint32_t item_size = extractor.GetU32(&offset); uint32_t start_of_array_offset = offset; while (offset < pending_items_pointer.items_buffer_size && static_cast<size_t>(i) < pending_items_pointer.count) { offset = start_of_array_offset + (i * item_size); ItemRefAndCodeAddress item; item.item_ref = extractor.GetPointer (&offset); item.code_address = extractor.GetPointer (&offset); pending_item_refs.item_refs_and_code_addresses.push_back (item); i++; } } else { offset = 0; pending_item_refs.new_style = false; while (offset < pending_items_pointer.items_buffer_size && static_cast<size_t>(i) < pending_items_pointer.count) { ItemRefAndCodeAddress item; item.item_ref = extractor.GetPointer (&offset); item.code_address = LLDB_INVALID_ADDRESS; pending_item_refs.item_refs_and_code_addresses.push_back (item); i++; } } } m_page_to_free = pending_items_pointer.items_buffer_ptr; m_page_to_free_size = pending_items_pointer.items_buffer_size; } } } return pending_item_refs; }