From 97d5cf05eb93d7efc4ab3de7948741957d9e5059 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Tue, 25 Sep 2012 02:40:06 +0000 Subject: [PATCH] More KDP debugging process. We can not set breakpoints, hit them, resume, step and detach while running. llvm-svn: 164584 --- lldb/include/lldb/Core/Stream.h | 2 +- lldb/include/lldb/Target/Thread.h | 36 ++- lldb/source/API/SBThread.cpp | 4 +- .../Process/MacOSX-Kernel/CommunicationKDP.cpp | 47 ++-- .../Process/MacOSX-Kernel/CommunicationKDP.h | 8 +- .../Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp | 258 +++++++++------------ .../Plugins/Process/MacOSX-Kernel/ProcessKDP.h | 15 +- .../Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp | 76 +++--- .../Plugins/Process/MacOSX-Kernel/ThreadKDP.h | 4 + .../Process/Utility/StopInfoMachException.cpp | 40 +++- .../Process/Utility/StopInfoMachException.h | 6 +- lldb/source/Target/Thread.cpp | 13 +- 12 files changed, 274 insertions(+), 235 deletions(-) diff --git a/lldb/include/lldb/Core/Stream.h b/lldb/include/lldb/Core/Stream.h index 5496580..8510158 100644 --- a/lldb/include/lldb/Core/Stream.h +++ b/lldb/include/lldb/Core/Stream.h @@ -590,7 +590,7 @@ public: static void UnitTest(Stream *s); -private: +protected: //------------------------------------------------------------------ // Member variables //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 347aafb..a509fb4 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -226,6 +226,9 @@ public: lldb::StopInfoSP GetStopInfo (); + lldb::StopReason + GetStopReason(); + // This sets the stop reason to a "blank" stop reason, so you can call functions on the thread // without having the called function run with whatever stop reason you stopped with. void @@ -721,6 +724,27 @@ public: virtual lldb::StopInfoSP GetPrivateStopReason () = 0; + //---------------------------------------------------------------------- + // Gets the temporary resume state for a thread. + // + // This value gets set in each thread by complex debugger logic in + // Thread::WillResume() and an appropriate thread resume state will get + // set in each thread every time the process is resumed prior to calling + // Process::DoResume(). The lldb_private::Process subclass should adhere + // to the thread resume state request which will be one of: + // + // eStateRunning - thread will resume when process is resumed + // eStateStepping - thread should step 1 instruction and stop when process + // is resumed + // eStateSuspended - thread should not execute any instructions when + // process is resumed + //---------------------------------------------------------------------- + lldb::StateType + GetTemporaryResumeState() const + { + return m_temporary_resume_state; + } + protected: friend class ThreadPlan; @@ -764,18 +788,6 @@ protected: lldb::StackFrameListSP GetStackFrameList (); - lldb::StateType GetTemporaryResumeState() - { - return m_temporary_resume_state; - } - - lldb::StateType SetTemporaryResumeState(lldb::StateType resume_state) - { - lldb::StateType old_temp_resume_state = m_temporary_resume_state; - m_temporary_resume_state = resume_state; - return old_temp_resume_state; - } - struct ThreadState { uint32_t orig_stop_id; diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 345cd7b..5a09dcc 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -104,9 +104,7 @@ SBThread::GetStopReason() Process::StopLocker stop_locker; if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) { - StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo (); - if (stop_info_sp) - reason = stop_info_sp->GetStopReason(); + return exe_ctx.GetThreadPtr()->GetStopReason(); } else { diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 48c65db..c0e6288 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -42,7 +42,7 @@ CommunicationKDP::CommunicationKDP (const char *comm_name) : m_byte_order (eByteOrderLittle), m_packet_timeout (1), m_sequence_mutex (Mutex::eMutexTypeRecursive), - m_private_is_running (false), + m_is_running (false), m_session_key (0u), m_request_sequence_id (0u), m_exception_sequence_id (0u), @@ -99,8 +99,23 @@ CommunicationKDP::SendRequestAndGetReply (const CommandType command, const PacketStreamType &request_packet, DataExtractor &reply_packet) { + if (IsRunning()) + { + LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); + if (log) + { + PacketStreamType log_strm; + DumpPacket (log_strm, request_packet.GetData(), request_packet.GetSize()); + log->Printf("error: kdp running, not sending packet: %.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); + } + return false; + } - Mutex::Locker locker(m_sequence_mutex); + Mutex::Locker locker(m_sequence_mutex); +#ifdef LLDB_CONFIGURATION_DEBUG + // NOTE: this only works for packets that are in native endian byte order + assert (request_packet.GetSize() == *((uint16_t *)(request_packet.GetData() + 2))); +#endif if (SendRequestPacketNoLock(request_packet)) { if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ())) @@ -111,7 +126,11 @@ CommunicationKDP::SendRequestAndGetReply (const CommandType command, if ((reply_command & eCommandTypeMask) == command) { if (request_sequence_id == reply_sequence_id) + { + if (command == KDP_RESUMECPUS) + m_is_running.SetValue(true, eBroadcastAlways); return true; + } } } } @@ -160,7 +179,7 @@ CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker) bool CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) { - return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); + return m_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); } size_t @@ -266,6 +285,7 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtrac request_ack_packet.PutHex8 (packet.GetU8(&offset)); request_ack_packet.PutHex16 (packet.GetU16(&offset)); request_ack_packet.PutHex32 (packet.GetU32(&offset)); + m_is_running.SetValue(false, eBroadcastAlways); // Ack to the exception or termination SendRequestPacketNoLock (request_ack_packet); } @@ -688,12 +708,14 @@ CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet) if (command_name) { const bool is_reply = ExtractIsReply(first_packet_byte); - s.Printf ("%s {%u:%u} <0x%4.4x> %s", - is_reply ? "<--" : "-->", - key, + s.Printf ("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ", + IsRunning(), + is_reply ? "<--" : "-->", + command_name, + first_packet_byte, sequence_id, length, - command_name); + key); if (is_reply) { @@ -944,7 +966,6 @@ CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet) { const uint32_t count = packet.GetU32 (&offset); - s.Printf(" (count = %u:", count); for (uint32_t i=0; i m_public_is_running; - lldb_private::Predicate m_private_is_running; + lldb_private::Predicate m_is_running; uint32_t m_session_key; uint8_t m_request_sequence_id; uint8_t m_exception_sequence_id; diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index dea16f2..c5be914 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -28,7 +28,6 @@ #include "ProcessKDP.h" #include "ProcessKDPLog.h" #include "ThreadKDP.h" -#include "StopInfoMachException.h" using namespace lldb; using namespace lldb_private; @@ -102,7 +101,8 @@ ProcessKDP::ProcessKDP(Target& target, Listener &listener) : Process (target, listener), m_comm("lldb.process.kdp-remote.communication"), m_async_broadcaster (NULL, "lldb.process.kdp-remote.async-broadcaster"), - m_async_thread (LLDB_INVALID_HOST_THREAD) + m_async_thread (LLDB_INVALID_HOST_THREAD), + m_destroy_in_process (false) { m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); @@ -214,6 +214,8 @@ ProcessKDP::DoConnectRemote (const char *remote_url) ArchSpec kernel_arch; kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub); m_target.SetArchitecture(kernel_arch); + // Set the thread ID + UpdateThreadListIfNeeded (); SetID (1); GetThreadList (); SetPrivateState (eStateStopped); @@ -233,10 +235,16 @@ ProcessKDP::DoConnectRemote (const char *remote_url) // } } } + else + { + puts ("KDP_CONNECT failed"); // REMOVE THIS + error.SetErrorString("KDP_REATTACH failed"); + } } else { - error.SetErrorString("KDP reattach failed"); + puts ("KDP_REATTACH failed"); // REMOVE THIS + error.SetErrorString("KDP_REATTACH failed"); } } else @@ -320,42 +328,46 @@ ProcessKDP::DoResume () if (!IS_VALID_LLDB_HOST_THREAD(m_async_thread)) StartAsyncThread (); - const uint32_t num_threads = m_thread_list.GetSize(); - uint32_t resume_cpu_mask = 0; + bool resume = false; - for (uint32_t idx = 0; idx < num_threads; ++idx) + // With KDP there is only one thread we can tell what to do + ThreadSP kernel_thread_sp (GetKernelThread(m_thread_list, m_thread_list)); + if (kernel_thread_sp) { - ThreadSP thread_sp (m_thread_list.GetThreadAtIndex(idx)); - const StateType thread_resume_state = thread_sp->GetState(); + const StateType thread_resume_state = kernel_thread_sp->GetTemporaryResumeState(); switch (thread_resume_state) { - case eStateStopped: case eStateSuspended: // Nothing to do here when a thread will stay suspended // we just leave the CPU mask bit set to zero for the thread + puts("REMOVE THIS: ProcessKDP::DoResume () -- thread suspended"); break; case eStateStepping: - case eStateRunning: - thread_sp->GetRegisterContext()->HardwareSingleStep (thread_resume_state == eStateStepping); - // Thread ID is the bit we need for the CPU mask - resume_cpu_mask |= thread_sp->GetID(); + puts("REMOVE THIS: ProcessKDP::DoResume () -- thread stepping"); + kernel_thread_sp->GetRegisterContext()->HardwareSingleStep (true); + resume = true; break; - + + case eStateRunning: + puts("REMOVE THIS: ProcessKDP::DoResume () -- thread running"); + kernel_thread_sp->GetRegisterContext()->HardwareSingleStep (false); + resume = true; break; - + default: + // The only valid thread resume states are listed above assert (!"invalid thread resume state"); break; } } - if (log) - log->Printf ("ProcessKDP::DoResume () sending resume with cpu_mask = 0x%8.8x", - resume_cpu_mask); - if (resume_cpu_mask) + + if (resume) { + if (log) + log->Printf ("ProcessKDP::DoResume () sending resume"); - if (m_comm.SendRequestResume (resume_cpu_mask)) + if (m_comm.SendRequestResume ()) { m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue); SetPrivateState(eStateRunning); @@ -365,12 +377,30 @@ ProcessKDP::DoResume () } else { - error.SetErrorString ("all threads suspended"); + error.SetErrorString ("kernel thread is suspended"); } return error; } +lldb::ThreadSP +ProcessKDP::GetKernelThread(ThreadList &old_thread_list, ThreadList &new_thread_list) +{ + // KDP only tells us about one thread/core. Any other threads will usually + // be the ones that are read from memory by the OS plug-ins. + const lldb::tid_t kernel_tid = 1; + ThreadSP thread_sp (old_thread_list.FindThreadByID (kernel_tid, false)); + if (!thread_sp) + { + thread_sp.reset(new ThreadKDP (shared_from_this(), kernel_tid)); + new_thread_list.AddThread(thread_sp); + } + return thread_sp; +} + + + + bool ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) { @@ -379,20 +409,10 @@ ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_threa if (log && log->GetMask().Test(KDP_LOG_VERBOSE)) log->Printf ("ProcessKDP::%s (pid = %llu)", __FUNCTION__, GetID()); - // We currently are making only one thread per core and we - // actually don't know about actual threads. Eventually we - // want to get the thread list from memory and note which - // threads are on CPU as those are the only ones that we - // will be able to resume. - const uint32_t cpu_mask = m_comm.GetCPUMask(); - for (uint32_t cpu_mask_bit = 1; cpu_mask_bit & cpu_mask; cpu_mask_bit <<= 1) - { - lldb::tid_t tid = cpu_mask_bit; - ThreadSP thread_sp (old_thread_list.FindThreadByID (tid, false)); - if (!thread_sp) - thread_sp.reset(new ThreadKDP (shared_from_this(), tid)); - new_thread_list.AddThread(thread_sp); - } + // Even though there is a CPU mask, it doesn't mean to can see each CPU + // indivudually, there is really only one. Lets call this thread 1. + GetKernelThread (old_thread_list, new_thread_list); + return new_thread_list.GetSize(false) > 0; } @@ -409,112 +429,24 @@ ProcessKDP::DoHalt (bool &caused_stop) { Error error; -// bool timed_out = false; - Mutex::Locker locker; - - if (m_public_state.GetValue() == eStateAttaching) - { - // We are being asked to halt during an attach. We need to just close - // our file handle and debugserver will go away, and we can be done... - m_comm.Disconnect(); - } - else - { - if (!m_comm.SendRequestSuspend ()) - error.SetErrorString ("KDP halt failed"); - } - return error; -} - -Error -ProcessKDP::InterruptIfRunning (bool discard_thread_plans, - bool catch_stop_event, - EventSP &stop_event_sp) -{ - Error error; - - LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - - bool paused_private_state_thread = false; - const bool is_running = m_comm.IsRunning(); - if (log) - log->Printf ("ProcessKDP::InterruptIfRunning(discard_thread_plans=%i, catch_stop_event=%i) is_running=%i", - discard_thread_plans, - catch_stop_event, - is_running); - - if (discard_thread_plans) - { - if (log) - log->Printf ("ProcessKDP::InterruptIfRunning() discarding all thread plans"); - m_thread_list.DiscardThreadPlans(); - } - if (is_running) + if (m_comm.IsRunning()) { - if (catch_stop_event) + if (m_destroy_in_process) { - if (log) - log->Printf ("ProcessKDP::InterruptIfRunning() pausing private state thread"); - PausePrivateStateThread(); - paused_private_state_thread = true; - } - - bool timed_out = false; -// bool sent_interrupt = false; - Mutex::Locker locker; - - // TODO: implement halt in CommunicationKDP -// if (!m_comm.SendInterrupt (locker, 1, sent_interrupt, timed_out)) -// { -// if (timed_out) -// error.SetErrorString("timed out sending interrupt packet"); -// else -// error.SetErrorString("unknown error sending interrupt packet"); -// if (paused_private_state_thread) -// ResumePrivateStateThread(); -// return error; -// } - - if (catch_stop_event) - { - // LISTEN HERE - TimeValue timeout_time; - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds(5); - StateType state = WaitForStateChangedEventsPrivate (&timeout_time, stop_event_sp); - - timed_out = state == eStateInvalid; - if (log) - log->Printf ("ProcessKDP::InterruptIfRunning() catch stop event: state = %s, timed-out=%i", StateAsCString(state), timed_out); - - if (timed_out) - error.SetErrorString("unable to verify target stopped"); + // If we are attemping to destroy, we need to not return an error to + // Halt or DoDestroy won't get called. + // We are also currently running, so send a process stopped event + SetPrivateState (eStateStopped); } - - if (paused_private_state_thread) + else { - if (log) - log->Printf ("ProcessKDP::InterruptIfRunning() resuming private state thread"); - ResumePrivateStateThread(); + error.SetErrorString ("KDP cannot interrupt a running kernel"); } } return error; } Error -ProcessKDP::WillDetach () -{ - LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (log) - log->Printf ("ProcessKDP::WillDetach()"); - - bool discard_thread_plans = true; - bool catch_stop_event = true; - EventSP event_sp; - return InterruptIfRunning (discard_thread_plans, catch_stop_event, event_sp); -} - -Error ProcessKDP::DoDetach() { Error error; @@ -522,27 +454,33 @@ ProcessKDP::DoDetach() if (log) log->Printf ("ProcessKDP::DoDetach()"); - DisableAllBreakpointSites (); - - m_thread_list.DiscardThreadPlans(); - - if (m_comm.IsConnected()) + if (m_comm.IsRunning()) + { + // We are running and we can't interrupt a running kernel, so we need + // to just close the connection to the kernel and hope for the best + } + else { + DisableAllBreakpointSites (); + + m_thread_list.DiscardThreadPlans(); + + if (m_comm.IsConnected()) + { - m_comm.SendRequestDisconnect(); + m_comm.SendRequestDisconnect(); - size_t response_size = m_comm.Disconnect (); - if (log) - { - if (response_size) - log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); - else - log->PutCString ("ProcessKDP::DoDetach() detach packet send failed"); + size_t response_size = m_comm.Disconnect (); + if (log) + { + if (response_size) + log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); + else + log->PutCString ("ProcessKDP::DoDetach() detach packet send failed"); + } } } - // Sleep for one second to let the process get all detached... - StopAsyncThread (); - + StopAsyncThread (); m_comm.Clear(); SetPrivateState (eStateDetached); @@ -553,6 +491,14 @@ ProcessKDP::DoDetach() } Error +ProcessKDP::WillDestroy () +{ + Error error; + m_destroy_in_process = true; + return error; +} + +Error ProcessKDP::DoDestroy () { // For KDP there really is no difference between destroy and detach @@ -639,10 +585,18 @@ ProcessKDP::DisableBreakpoint (BreakpointSite *bp_site) BreakpointSite::Type bp_type = bp_site->GetType(); if (bp_type == BreakpointSite::eExternal) { - if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) + if (m_destroy_in_process && m_comm.IsRunning()) + { + // We are trying to destroy our connection and we are running bp_site->SetEnabled(false); + } else - error.SetErrorString ("KDP remove breakpoint failed"); + { + if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) + bp_site->SetEnabled(false); + else + error.SetErrorString ("KDP remove breakpoint failed"); + } } else { @@ -787,8 +741,12 @@ ProcessKDP::AsyncThread (void *arg) is_running = true; if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC)) { + ThreadSP thread_sp (process->GetKernelThread(process->GetThreadList(), process->GetThreadList())); + thread_sp->GetRegisterContext()->InvalidateAllRegisters(); + static_cast(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet); + // TODO: parse the stop reply packet - is_running = false; + is_running = false; process->SetPrivateState(eStateStopped); } else diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h index 7ef3cb7..825e6b6 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -129,15 +129,15 @@ public: DoHalt (bool &caused_stop); virtual lldb_private::Error - WillDetach (); - - virtual lldb_private::Error DoDetach (); virtual lldb_private::Error DoSignal (int signal); virtual lldb_private::Error + WillDestroy (); + + virtual lldb_private::Error DoDestroy (); virtual void @@ -241,11 +241,9 @@ protected: eBroadcastBitAsyncThreadShouldExit = (1 << 1) }; - - lldb_private::Error - InterruptIfRunning (bool discard_thread_plans, - bool catch_stop_event, - lldb::EventSP &stop_event_sp); + lldb::ThreadSP + GetKernelThread (lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list); //------------------------------------------------------------------ /// Broadcaster event bits definitions. @@ -253,6 +251,7 @@ protected: CommunicationKDP m_comm; lldb_private::Broadcaster m_async_broadcaster; lldb::thread_t m_async_thread; + bool m_destroy_in_process; bool StartAsyncThread (); diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp index 9f68d10..150c314 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -28,6 +28,7 @@ #include "RegisterContextKDP_arm.h" #include "RegisterContextKDP_i386.h" #include "RegisterContextKDP_x86_64.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" using namespace lldb; using namespace lldb_private; @@ -68,31 +69,17 @@ ThreadKDP::GetQueueName () bool ThreadKDP::WillResume (StateType resume_state) { - ClearStackFrames(); // Call the Thread::WillResume first. If we stop at a signal, the stop info // class for signal will set the resume signal that we need below. The signal // stuff obeys the Process::UnixSignal defaults. Thread::WillResume(resume_state); + ClearStackFrames(); + lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); if (log) log->Printf ("Resuming thread: %4.4llx with state: %s.", GetID(), StateAsCString(resume_state)); -// ProcessKDP &process = GetKDPProcess(); -// switch (resume_state) -// { -// case eStateSuspended: -// case eStateStopped: -// // Don't append anything for threads that should stay stopped. -// break; -// -// case eStateRunning: -// case eStateStepping: -// break; -// -// default: -// break; -// } return true; } @@ -192,25 +179,50 @@ ThreadKDP::GetPrivateStopReason () if (m_thread_stop_reason_stop_id != process_stop_id || (m_actual_stop_info_sp && !m_actual_stop_info_sp->IsValid())) { - // TODO: can we query the initial state of the thread here? - // For now I am just going to pretend that a SIGSTOP happened. - - SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP)); - - // If GetKDPProcess().SetThreadStopInfo() doesn't find a stop reason - // for this thread, then m_actual_stop_info_sp will not ever contain - // a valid stop reason and the "m_actual_stop_info_sp->IsValid() == false" - // check will never be able to tell us if we have the correct stop info - // for this thread and we will continually send qThreadStopInfo packets - // down to the remote KDP server, so we need to keep our own notion - // of the stop ID that m_actual_stop_info_sp is valid for (even if it - // contains nothing). We use m_thread_stop_reason_stop_id for this below. - // m_thread_stop_reason_stop_id = process_stop_id; - // m_actual_stop_info_sp.reset(); - + if (m_cached_stop_info_sp) + SetStopInfo (m_cached_stop_info_sp); + else + SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP)); } } return m_actual_stop_info_sp; } +void +ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION (const DataExtractor &exc_reply_packet) +{ + uint32_t offset = 0; + uint8_t reply_command = exc_reply_packet.GetU8(&offset); + if (reply_command == CommunicationKDP::KDP_EXCEPTION) + { + offset = 8; + const uint32_t count = exc_reply_packet.GetU32 (&offset); + if (count >= 1) + { + //const uint32_t cpu = exc_reply_packet.GetU32 (&offset); + offset += 4; // Skip the useless CPU field + const uint32_t exc_type = exc_reply_packet.GetU32 (&offset); + const uint32_t exc_code = exc_reply_packet.GetU32 (&offset); + const uint32_t exc_subcode = exc_reply_packet.GetU32 (&offset); + // We have to make a copy of the stop info because the thread list + // will iterate through the threads and clear all stop infos.. + + // Let the StopInfoMachException::CreateStopReasonWithMachException() + // function update the PC if needed as we might hit a software breakpoint + // and need to decrement the PC (i386 and x86_64 need this) and KDP + // doesn't do this for us. + const bool pc_already_adjusted = false; + const bool adjust_pc_if_needed = true; + + m_cached_stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException (*this, + exc_type, + 2, + exc_code, + exc_subcode, + 0, + pc_already_adjusted, + adjust_pc_if_needed); + } + } +} diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h index 1bf688d..97f5f8a 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h @@ -79,6 +79,9 @@ public: { m_thread_dispatch_qaddr = thread_dispatch_qaddr; } + + void + SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet); protected: @@ -90,6 +93,7 @@ protected: std::string m_thread_name; std::string m_dispatch_queue_name; lldb::addr_t m_thread_dispatch_qaddr; + lldb::StopInfoSP m_cached_stop_info_sp; //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index bc313f7..87c9962 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -242,6 +242,9 @@ StopInfoMachException::GetDescription () } + + + StopInfoSP StopInfoMachException::CreateStopReasonWithMachException ( @@ -250,11 +253,14 @@ StopInfoMachException::CreateStopReasonWithMachException uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, - uint64_t exc_sub_sub_code + uint64_t exc_sub_sub_code, + bool pc_already_adjusted, + bool adjust_pc_if_needed ) { if (exc_type != 0) { + uint32_t pc_decrement = 0; ExecutionContext exe_ctx (thread.shared_from_this()); Target *target = exe_ctx.GetTargetPtr(); const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch; @@ -300,6 +306,7 @@ StopInfoMachException::CreateStopReasonWithMachException case 6: // EXC_BREAKPOINT { bool is_software_breakpoint = false; + bool is_trace_if_software_breakpoint_missing = false; switch (cpu) { case llvm::Triple::x86: @@ -323,9 +330,16 @@ StopInfoMachException::CreateStopReasonWithMachException return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); } } - else if (exc_code == 2) // EXC_I386_BPT + else if (exc_code == 2 || // EXC_I386_BPT + exc_code == 3) // EXC_I386_BPTFLT { + // KDP returns EXC_I386_BPTFLT for trace breakpoints + if (exc_code == 3) + is_trace_if_software_breakpoint_missing = true; + is_software_breakpoint = true; + if (!pc_already_adjusted) + pc_decrement = 1; } break; @@ -353,8 +367,11 @@ StopInfoMachException::CreateStopReasonWithMachException // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS return StopInfo::CreateStopReasonToTrace(thread); } - else - is_software_breakpoint = exc_code == 1; // EXC_ARM_BREAKPOINT + else if (exc_code == 1) + { + is_software_breakpoint = true; + is_trace_if_software_breakpoint_missing = true; + } break; default: @@ -363,14 +380,22 @@ StopInfoMachException::CreateStopReasonWithMachException if (is_software_breakpoint) { - addr_t pc = thread.GetRegisterContext()->GetPC(); + RegisterContextSP reg_ctx_sp (thread.GetRegisterContext()); + addr_t pc = reg_ctx_sp->GetPC() - pc_decrement; + ProcessSP process_sp (thread.CalculateProcess()); lldb::BreakpointSiteSP bp_site_sp; if (process_sp) bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc); - if (bp_site_sp) + if (bp_site_sp && bp_site_sp->IsEnabled()) { + // Update the PC if we were asked to do so, but only do + // so if we find a breakpoint that we know about cause + // this could be a trap instruction in the code + if (pc_decrement > 0 && adjust_pc_if_needed) + reg_ctx_sp->SetPC (pc); + // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. @@ -379,7 +404,8 @@ StopInfoMachException::CreateStopReasonWithMachException else return StopInfoSP(); } - else if (cpu == llvm::Triple::arm) + + if (is_trace_if_software_breakpoint_missing) { return StopInfo::CreateStopReasonToTrace (thread); } diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h index a40bd71..130ee0b 100644 --- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.h +++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.h @@ -61,8 +61,10 @@ public: uint32_t exc_data_count, uint64_t exc_code, uint64_t exc_sub_code, - uint64_t exc_sub_sub_code); - + uint64_t exc_sub_sub_code, + bool pc_already_adjusted = true, + bool adjust_pc_if_needed = false); + protected: uint32_t m_exc_data_count; uint64_t m_exc_code; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index c75b9c9..5cffe2d 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -204,6 +204,17 @@ Thread::GetStopInfo () } } +lldb::StopReason +Thread::GetStopReason() +{ + lldb::StopInfoSP stop_info_sp (GetStopInfo ()); + if (stop_info_sp) + stop_info_sp->GetStopReason(); + return eStopReasonNone; +} + + + void Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp) { @@ -332,7 +343,7 @@ Thread::WillResume (StateType resume_state) m_completed_plan_stack.clear(); m_discarded_plan_stack.clear(); - SetTemporaryResumeState(resume_state); + m_temporary_resume_state = resume_state; // This is a little dubious, but we are trying to limit how often we actually fetch stop info from // the target, 'cause that slows down single stepping. So assume that if we got to the point where -- 2.7.4