More KDP debugging process. We can not set breakpoints, hit them, resume, step and detach while running.
llvm-svn: 164584
static void
UnitTest(Stream *s);
-private:
+protected:
//------------------------------------------------------------------
// Member variables
//------------------------------------------------------------------
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
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;
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;
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
{
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),
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 ()))
if ((reply_command & eCommandTypeMask) == command)
{
if (request_sequence_id == reply_sequence_id)
+ {
+ if (command == KDP_RESUMECPUS)
+ m_is_running.SetValue(true, eBroadcastAlways);
return true;
+ }
}
}
}
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
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);
}
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)
{
{
const uint32_t count = packet.GetU32 (&offset);
- s.Printf(" (count = %u:", count);
for (uint32_t i=0; i<count; ++i)
{
const uint32_t cpu = packet.GetU32 (&offset);
break;
}
- s.Printf ("\n cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), subcode = %u (0x%8.8x)\n",
+ s.Printf ("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), subcode = %u (0x%8.8x)} ",
cpu, exc_cstr, exc, code, code, subcode, subcode);
}
}
PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
const CommandType command = KDP_WRITEREGS;
// Size is header + 4 byte cpu and 4 byte flavor
- const uint32_t command_length = 8 + 4 + 4;
+ const uint32_t command_length = 8 + 4 + 4 + src_len;
const uint32_t request_sequence_id = m_request_sequence_id;
MakeRequestPacketHeader (command, request_packet, command_length);
request_packet.PutHex32 (cpu);
bool
-CommunicationKDP::SendRequestResume (uint32_t cpu_mask)
+CommunicationKDP::SendRequestResume ()
{
- if (cpu_mask == 0)
- cpu_mask = GetCPUMask();
PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
const CommandType command = KDP_RESUMECPUS;
const uint32_t command_length = 12;
const uint32_t request_sequence_id = m_request_sequence_id;
MakeRequestPacketHeader (command, request_packet, command_length);
- request_packet.PutHex32(cpu_mask);
+ request_packet.PutHex32(GetCPUMask());
DataExtractor reply_packet;
if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
bool
IsRunning() const
{
- return m_public_is_running.GetValue();
+ return m_is_running.GetValue();
}
//------------------------------------------------------------------
uint32_t
GetCPUSubtype ();
- // If cpu_mask is zero, then we will resume all CPUs
bool
- SendRequestResume (uint32_t cpu_mask = 0);
+ SendRequestResume ();
bool
SendRequestSuspend ();
lldb::ByteOrder m_byte_order;
uint32_t m_packet_timeout;
lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
- lldb_private::Predicate<bool> m_public_is_running;
- lldb_private::Predicate<bool> m_private_is_running;
+ lldb_private::Predicate<bool> m_is_running;
uint32_t m_session_key;
uint8_t m_request_sequence_id;
uint8_t m_exception_sequence_id;
#include "ProcessKDP.h"
#include "ProcessKDPLog.h"
#include "ThreadKDP.h"
-#include "StopInfoMachException.h"
using namespace lldb;
using namespace lldb_private;
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");
ArchSpec kernel_arch;
kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
m_target.SetArchitecture(kernel_arch);
+ // Set the thread ID
+ UpdateThreadListIfNeeded ();
SetID (1);
GetThreadList ();
SetPrivateState (eStateStopped);
// }
}
}
+ 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
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);
}
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)
{
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;
}
{
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;
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);
}
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
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
{
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<ThreadKDP *>(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
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
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.
CommunicationKDP m_comm;
lldb_private::Broadcaster m_async_broadcaster;
lldb::thread_t m_async_thread;
+ bool m_destroy_in_process;
bool
StartAsyncThread ();
#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;
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;
}
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);
+ }
+ }
+}
{
m_thread_dispatch_qaddr = thread_dispatch_qaddr;
}
+
+ void
+ SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet);
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.
//------------------------------------------------------------------
}
+
+
+
StopInfoSP
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;
case 6: // EXC_BREAKPOINT
{
bool is_software_breakpoint = false;
+ bool is_trace_if_software_breakpoint_missing = false;
switch (cpu)
{
case llvm::Triple::x86:
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;
// 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:
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.
else
return StopInfoSP();
}
- else if (cpu == llvm::Triple::arm)
+
+ if (is_trace_if_software_breakpoint_missing)
{
return StopInfo::CreateStopReasonToTrace (thread);
}
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;
}
}
+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)
{
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