bool ProcessFreeBSD::IsSoftwareStepBreakpoint(lldb::tid_t tid) { ThreadSP thread = GetThreadList().FindThreadByID(tid); if (!thread) return false; assert(thread->GetRegisterContext()); lldb::addr_t stop_pc = thread->GetRegisterContext()->GetPC(); const auto &iter = m_threads_stepping_with_breakpoint.find(tid); if (iter == m_threads_stepping_with_breakpoint.end()) return false; lldb::break_id_t bp_id = iter->second; BreakpointSP bp = GetTarget().GetBreakpointByID(bp_id); if (!bp) return false; BreakpointLocationSP bp_loc = bp->FindLocationByAddress(stop_pc); if (!bp_loc) return false; GetTarget().RemoveBreakpointByID(bp_id); m_threads_stepping_with_breakpoint.erase(tid); return true; }
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; }
bool SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread (ThreadSP thread_sp) { if (thread_sp && thread_sp->GetStackFrameCount() > 0 && thread_sp->GetFrameWithConcreteFrameIndex(0)) { const SymbolContext sym_ctx (thread_sp->GetFrameWithConcreteFrameIndex(0)->GetSymbolContext (eSymbolContextSymbol)); static ConstString g_select_symbol ("__select"); if (sym_ctx.GetFunctionName() == g_select_symbol) { return false; } } return true; }
addr_t SystemRuntimeMacOSX::GetThreadCreatorItem (ThreadSP thread_sp) { addr_t enqueued_item_ptr = thread_sp->GetExtendedBacktraceToken(); if (enqueued_item_ptr == LLDB_INVALID_ADDRESS) { if (thread_sp->GetQueueID() == LLDB_INVALID_QUEUE_ID || thread_sp->GetQueueID() == 0) return LLDB_INVALID_ADDRESS; Error error; uint64_t this_thread_queue_id = thread_sp->GetQueueID(); addr_t queues_head = GetQueuesHead(); if (queues_head == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; // Step through the queues_head linked list looking for a queue matching this thread, if any uint64_t queue_obj_ptr = queues_head; enqueued_item_ptr = LLDB_INVALID_ADDRESS; while (queue_obj_ptr != 0) { uint64_t queue_id = m_process->ReadUnsignedIntegerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.queue_id, 8, LLDB_INVALID_ADDRESS, error); if (error.Success() && queue_id != LLDB_INVALID_ADDRESS) { if (queue_id == this_thread_queue_id) { enqueued_item_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.current_item_ptr, error); break; } } queue_obj_ptr = m_process->ReadPointerFromMemory (queue_obj_ptr + m_ldi_header.queue_offsets.next, error); if (error.Success() == false || queue_obj_ptr == LLDB_INVALID_ADDRESS) { break; } } } return enqueued_item_ptr; }
void SystemRuntimeMacOSX::SetNewThreadExtendedBacktraceToken (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) { addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) { Error error; uint64_t further_extended_backtrace = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.enqueueing_thread_dispatch_block_ptr, error); if (error.Success() && further_extended_backtrace != 0 && further_extended_backtrace != LLDB_INVALID_ADDRESS) { new_extended_thread_sp->SetExtendedBacktraceToken (further_extended_backtrace); } } }
void ThreadCollection::AddThreadSortedByIndexID (const ThreadSP &thread_sp) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); // Make sure we always keep the threads sorted by thread index ID const uint32_t thread_index_id = thread_sp->GetIndexID(); if (m_threads.empty() || m_threads.back()->GetIndexID() < thread_index_id) m_threads.push_back (thread_sp); else { m_threads.insert(std::upper_bound(m_threads.begin(), m_threads.end(), thread_sp, [] (const ThreadSP &lhs, const ThreadSP &rhs) -> bool { return lhs->GetIndexID() < rhs->GetIndexID(); }), thread_sp); } }
void SystemRuntimeMacOSX::SetNewThreadQueueID (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) { queue_id_t queue_id = LLDB_INVALID_QUEUE_ID; addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); if (enqueued_item_ptr != LLDB_INVALID_ADDRESS && m_ldi_header.item_offsets.queue_id_from_thread_info != 0xffff) { Error error; queue_id = m_process->ReadUnsignedIntegerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.queue_id_from_thread_info, 8, LLDB_INVALID_QUEUE_ID, error); if (!error.Success()) queue_id = LLDB_INVALID_QUEUE_ID; } if (queue_id != LLDB_INVALID_QUEUE_ID) { new_extended_thread_sp->SetQueueID (queue_id); } }
void SystemRuntimeMacOSX::SetNewThreadThreadName (ThreadSP original_thread_sp, ThreadSP new_extended_thread_sp) { addr_t enqueued_item_ptr = GetThreadCreatorItem (original_thread_sp); if (enqueued_item_ptr != LLDB_INVALID_ADDRESS) { Error error; addr_t thread_name_ptr = m_process->ReadPointerFromMemory (enqueued_item_ptr + m_ldi_header.item_offsets.thread_name_ptr, error); if (thread_name_ptr != LLDB_INVALID_ADDRESS && error.Success()) { char namebuf[512]; if (m_process->ReadCStringFromMemory (thread_name_ptr, namebuf, sizeof (namebuf), error) > 0 && error.Success()) { new_extended_thread_sp->SetName (namebuf); } } } }
bool OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list, ThreadList &real_thread_list, ThreadList &new_thread_list) { new_thread_list = real_thread_list; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS)); if (!(m_allg_sp || Init(real_thread_list)) || (m_allg_sp && !m_allglen_sp) || !GetGlobalPluginProperties()->GetEnableGoroutines()) { return new_thread_list.GetSize(false) > 0; } if (log) log->Printf("OperatingSystemGo::UpdateThreadList(%d, %d, %d) fetching thread data from Go for pid %" PRIu64, old_thread_list.GetSize(false), real_thread_list.GetSize(false), new_thread_list.GetSize(0), m_process->GetID()); uint64_t allglen = m_allglen_sp->GetValueAsUnsigned(0); if (allglen == 0) { return new_thread_list.GetSize(false) > 0; } std::vector<Goroutine> goroutines; // The threads that are in "new_thread_list" upon entry are the threads from the // lldb_private::Process subclass, no memory threads will be in this list. Error err; for (uint64_t i = 0; i < allglen; ++i) { goroutines.push_back(CreateGoroutineAtIndex(i, err)); if (err.Fail()) { err.PutToLog(log, "OperatingSystemGo::UpdateThreadList"); return new_thread_list.GetSize(false) > 0; } } // Make a map so we can match goroutines with backing threads. std::map<uint64_t, ThreadSP> stack_map; for (uint32_t i = 0; i < real_thread_list.GetSize(false); ++i) { ThreadSP thread = real_thread_list.GetThreadAtIndex(i, false); stack_map[thread->GetRegisterContext()->GetSP()] = thread; } for (const Goroutine &goroutine : goroutines) { if (0 /* Gidle */ == goroutine.m_status || 6 /* Gdead */ == goroutine.m_status) { continue; } ThreadSP memory_thread = old_thread_list.FindThreadByID(goroutine.m_goid, false); if (memory_thread && IsOperatingSystemPluginThread(memory_thread) && memory_thread->IsValid()) { memory_thread->ClearBackingThread(); } else { memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, nullptr, nullptr, goroutine.m_gobuf)); } // Search for the backing thread if the goroutine is running. if (2 == (goroutine.m_status & 0xfff)) { auto backing_it = stack_map.lower_bound(goroutine.m_lostack); if (backing_it != stack_map.end()) { if (goroutine.m_histack >= backing_it->first) { if (log) log->Printf("OperatingSystemGo::UpdateThreadList found backing thread %" PRIx64 " (%" PRIx64 ") for thread %" PRIx64 "", backing_it->second->GetID(), backing_it->second->GetProtocolID(), memory_thread->GetID()); memory_thread->SetBackingThread(backing_it->second); new_thread_list.RemoveThreadByID(backing_it->second->GetID(), false); } } } new_thread_list.AddThread(memory_thread); } return new_thread_list.GetSize(false) > 0; }