Error ProcessPOSIX::DoDetach(bool keep_stopped) { Error error; if (keep_stopped) { // FIXME: If you want to implement keep_stopped, // this would be the place to do it. error.SetErrorString("Detaching with keep_stopped true is not currently supported on this platform."); return error; } Mutex::Locker lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); error = m_monitor->Detach(thread->GetID()); } if (error.Success()) SetPrivateState(eStateDetached); return error; }
// ProcessPOSIX override void ProcessLinux::StopAllThreads(lldb::tid_t stop_tid) { // If a breakpoint occurs while we're stopping threads, we'll get back // here, but we don't want to do it again. Only the MonitorChildProcess // thread calls this function, so we don't need to protect this flag. if (m_stopping_threads) return; m_stopping_threads = true; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) log->Printf ("ProcessLinux::%s() stopping all threads", __FUNCTION__); // Walk the thread list and stop the other threads. The thread that caused // the stop should already be marked as stopped before we get here. Mutex::Locker thread_list_lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); assert(thread); lldb::tid_t tid = thread->GetID(); if (!StateIsStoppedState(thread->GetState(), false)) m_monitor->StopThread(tid); } m_stopping_threads = false; if (log) log->Printf ("ProcessLinux::%s() finished", __FUNCTION__); }
void ProcessPOSIX::RefreshStateAfterStop() { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); Mutex::Locker lock(m_message_mutex); // This method used to only handle one message. Changing it to loop allows // it to handle the case where we hit a breakpoint while handling a different // breakpoint. while (!m_message_queue.empty()) { ProcessMessage &message = m_message_queue.front(); // Resolve the thread this message corresponds to and pass it along. lldb::tid_t tid = message.GetTID(); if (log) log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); if (message.GetKind() == ProcessMessage::eNewThreadMessage) { if (log) log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID()); lldb::tid_t child_tid = message.GetChildTID(); ThreadSP thread_sp; thread_sp.reset(CreateNewPOSIXThread(*this, child_tid)); Mutex::Locker lock(m_thread_list.GetMutex()); m_thread_list.AddThread(thread_sp); } m_thread_list.RefreshStateAfterStop(); POSIXThread *thread = static_cast<POSIXThread*>( GetThreadList().FindThreadByID(tid, false).get()); if (thread) thread->Notify(message); if (message.GetKind() == ProcessMessage::eExitMessage) { // FIXME: We should tell the user about this, but the limbo message is probably better for that. if (log) log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); Mutex::Locker lock(m_thread_list.GetMutex()); ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); thread_sp.reset(); m_seen_initial_stop.erase(tid); } m_message_queue.pop(); } }
Error ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num) { Error error; Mutex::Locker lock(m_thread_list.GetMutex()); POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(0, false).get()); if (thread) num = thread->NumSupportedHardwareWatchpoints(); else error.SetErrorString("Process does not exist."); return error; }
Error ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify) { Error error; if (wp) { user_id_t watchID = wp->GetID(); addr_t addr = wp->GetLoadAddress(); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); if (log) log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")", watchID); if (!wp->IsEnabled()) { if (log) log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", watchID, (uint64_t)addr); // This is needed (for now) to keep watchpoints disabled correctly wp->SetEnabled(false, notify); return error; } if (wp->IsHardware()) { bool wp_disabled = true; Mutex::Locker lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); if (thread) wp_disabled &= thread->DisableHardwareWatchpoint(wp); else wp_disabled = false; } if (wp_disabled) { wp->SetHardwareIndex(LLDB_INVALID_INDEX32); wp->SetEnabled(false, notify); return error; } else error.SetErrorString("Disabling hardware watchpoint failed"); } } else error.SetErrorString("Watchpoint argument was NULL."); return error; }
bool ProcessPOSIX::IsAThreadRunning() { bool is_running = false; Mutex::Locker lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); StateType thread_state = thread->GetState(); if (thread_state == eStateRunning || thread_state == eStateStepping) { is_running = true; break; } } return is_running; }
Error ProcessPOSIX::DoResume() { StateType state = GetPrivateState(); assert(state == eStateStopped); SetPrivateState(eStateRunning); bool did_resume = false; Mutex::Locker lock(m_thread_list.GetMutex()); uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); did_resume = thread->Resume() || did_resume; } assert(did_resume && "Process resume failed!"); return Error(); }
Error ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify) { Error error; if (wp) { user_id_t watchID = wp->GetID(); addr_t addr = wp->GetLoadAddress(); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); if (log) log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")", watchID); if (wp->IsEnabled()) { if (log) log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr); return error; } // Try to find a vacant watchpoint slot in the inferiors' main thread uint32_t wp_hw_index = LLDB_INVALID_INDEX32; Mutex::Locker lock(m_thread_list.GetMutex()); POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(0, false).get()); if (thread) wp_hw_index = thread->FindVacantWatchpointIndex(); if (wp_hw_index == LLDB_INVALID_INDEX32) { error.SetErrorString("Setting hardware watchpoint failed."); } else { wp->SetHardwareIndex(wp_hw_index); bool wp_enabled = true; uint32_t thread_count = m_thread_list.GetSize(false); for (uint32_t i = 0; i < thread_count; ++i) { thread = static_cast<POSIXThread*>( m_thread_list.GetThreadAtIndex(i, false).get()); if (thread) wp_enabled &= thread->EnableHardwareWatchpoint(wp); else wp_enabled = false; } if (wp_enabled) { wp->SetEnabled(true, notify); return error; } else { // Watchpoint enabling failed on at least one // of the threads so roll back all of them DisableWatchpoint(wp, false); error.SetErrorString("Setting hardware watchpoint failed"); } } } else error.SetErrorString("Watchpoint argument was NULL."); return error; }
void ProcessPOSIX::SendMessage(const ProcessMessage &message) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); Mutex::Locker lock(m_message_mutex); Mutex::Locker thread_lock(m_thread_list.GetMutex()); POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.FindThreadByID(message.GetTID(), false).get()); switch (message.GetKind()) { case ProcessMessage::eInvalidMessage: return; case ProcessMessage::eAttachMessage: SetPrivateState(eStateStopped); return; case ProcessMessage::eLimboMessage: assert(thread); thread->SetState(eStateStopped); if (message.GetTID() == GetID()) { m_exit_status = message.GetExitStatus(); if (m_exit_now) { SetPrivateState(eStateExited); m_monitor->Detach(GetID()); } else { StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } } else { StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } break; case ProcessMessage::eExitMessage: if (thread != nullptr) thread->SetState(eStateExited); else { if (log) log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ()); } // FIXME: I'm not sure we need to do this. if (message.GetTID() == GetID()) { SetExitStatus(message.GetExitStatus(), NULL); } else if (!IsAThreadRunning()) SetPrivateState(eStateStopped); break; case ProcessMessage::eSignalMessage: case ProcessMessage::eSignalDeliveredMessage: if (message.GetSignal() == SIGSTOP && AddThreadForInitialStopIfNeeded(message.GetTID())) return; // Intentional fall-through case ProcessMessage::eBreakpointMessage: case ProcessMessage::eTraceMessage: case ProcessMessage::eWatchpointMessage: case ProcessMessage::eCrashMessage: assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; case ProcessMessage::eNewThreadMessage: { lldb::tid_t new_tid = message.GetChildTID(); if (WaitingForInitialStop(new_tid)) { m_monitor->WaitForInitialTIDStop(new_tid); } assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; } case ProcessMessage::eExecMessage: { assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; } } m_message_queue.push(message); }
void ProcessPOSIX::SendMessage(const ProcessMessage &message) { Mutex::Locker lock(m_message_mutex); Mutex::Locker thread_lock(m_thread_list.GetMutex()); POSIXThread *thread = static_cast<POSIXThread*>( m_thread_list.FindThreadByID(message.GetTID(), false).get()); switch (message.GetKind()) { case ProcessMessage::eInvalidMessage: return; case ProcessMessage::eLimboMessage: assert(thread); thread->SetState(eStateStopped); if (message.GetTID() == GetID()) { m_exit_status = message.GetExitStatus(); if (m_exit_now) { SetPrivateState(eStateExited); m_monitor->Detach(GetID()); } else { StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } } else { StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); } break; case ProcessMessage::eExitMessage: assert(thread); thread->SetState(eStateExited); // FIXME: I'm not sure we need to do this. if (message.GetTID() == GetID()) { m_exit_status = message.GetExitStatus(); SetExitStatus(m_exit_status, NULL); } else if (!IsAThreadRunning()) SetPrivateState(eStateStopped); break; assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; case ProcessMessage::eSignalMessage: case ProcessMessage::eSignalDeliveredMessage: if (message.GetSignal() == SIGSTOP && AddThreadForInitialStopIfNeeded(message.GetTID())) return; // Intentional fall-through case ProcessMessage::eBreakpointMessage: case ProcessMessage::eTraceMessage: case ProcessMessage::eWatchpointMessage: case ProcessMessage::eNewThreadMessage: case ProcessMessage::eCrashMessage: assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; } m_message_queue.push(message); }
POSIXThread* POSIXThread__New_1(::uStatic* __this, ::uDelegate* callback) { POSIXThread* inst = (POSIXThread*)::uAllocObject(sizeof(POSIXThread), POSIXThread__typeof()); inst->_ObjInit_1(callback); return inst; }