<rdar://problem/9959501>

More KDP debugging process. We can not set breakpoints, hit them, resume, step and detach while running.

llvm-svn: 164584
This commit is contained in:
Greg Clayton 2012-09-25 02:40:06 +00:00
parent 42bca056e0
commit 97d5cf05eb
12 changed files with 275 additions and 236 deletions

View File

@ -590,7 +590,7 @@ public:
static void
UnitTest(Stream *s);
private:
protected:
//------------------------------------------------------------------
// Member variables
//------------------------------------------------------------------

View File

@ -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;

View File

@ -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
{

View File

@ -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);
#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,10 +126,14 @@ 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;
}
}
}
}
reply_packet.Clear();
return false;
}
@ -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",
s.Printf ("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ",
IsRunning(),
is_reply ? "<--" : "-->",
key,
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<count; ++i)
{
const uint32_t cpu = packet.GetU32 (&offset);
@ -968,7 +989,7 @@ CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet)
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);
}
}
@ -1065,7 +1086,7 @@ CommunicationKDP::SendRequestWriteRegisters (uint32_t cpu,
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);
@ -1085,16 +1106,14 @@ CommunicationKDP::SendRequestWriteRegisters (uint32_t 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))

View File

@ -111,7 +111,7 @@ public:
bool
IsRunning() const
{
return m_public_is_running.GetValue();
return m_is_running.GetValue();
}
//------------------------------------------------------------------
@ -213,9 +213,8 @@ public:
uint32_t
GetCPUSubtype ();
// If cpu_mask is zero, then we will resume all CPUs
bool
SendRequestResume (uint32_t cpu_mask = 0);
SendRequestResume ();
bool
SendRequestSuspend ();
@ -310,8 +309,7 @@ protected:
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;

View File

@ -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 (m_comm.SendRequestResume (resume_cpu_mask))
if (resume)
{
if (log)
log->Printf ("ProcessKDP::DoResume () sending resume");
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,111 +429,23 @@ ProcessKDP::DoHalt (bool &caused_stop)
{
Error error;
// bool timed_out = false;
Mutex::Locker locker;
if (m_public_state.GetValue() == eStateAttaching)
if (m_comm.IsRunning())
{
// 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();
if (m_destroy_in_process)
{
// 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);
}
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 (catch_stop_event)
{
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 (paused_private_state_thread)
{
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()
{
@ -522,6 +454,13 @@ ProcessKDP::DoDetach()
if (log)
log->Printf ("ProcessKDP::DoDetach()");
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();
@ -540,9 +479,8 @@ ProcessKDP::DoDetach()
log->PutCString ("ProcessKDP::DoDetach() detach packet send failed");
}
}
// Sleep for one second to let the process get all detached...
}
StopAsyncThread ();
m_comm.Clear();
SetPrivateState (eStateDetached);
@ -552,6 +490,14 @@ ProcessKDP::DoDetach()
return error;
}
Error
ProcessKDP::WillDestroy ()
{
Error error;
m_destroy_in_process = true;
return error;
}
Error
ProcessKDP::DoDestroy ()
{
@ -638,12 +584,20 @@ ProcessKDP::DisableBreakpoint (BreakpointSite *bp_site)
{
BreakpointSite::Type bp_type = bp_site->GetType();
if (bp_type == BreakpointSite::eExternal)
{
if (m_destroy_in_process && m_comm.IsRunning())
{
// We are trying to destroy our connection and we are running
bp_site->SetEnabled(false);
}
else
{
if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress()))
bp_site->SetEnabled(false);
else
error.SetErrorString ("KDP remove breakpoint failed");
}
}
else
{
error = DisableSoftwareBreakpoint (bp_site);
@ -787,6 +741,10 @@ 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<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet);
// TODO: parse the stop reply packet
is_running = false;
process->SetPrivateState(eStateStopped);

View File

@ -128,15 +128,15 @@ public:
virtual lldb_private::Error
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 ();
@ -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 ();

View File

@ -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.
if (m_cached_stop_info_sp)
SetStopInfo (m_cached_stop_info_sp);
else
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();
}
}
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);
}
}
}

View File

@ -80,6 +80,9 @@ public:
m_thread_dispatch_qaddr = thread_dispatch_qaddr;
}
void
SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet);
protected:
friend class ProcessKDP;
@ -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.
//------------------------------------------------------------------

View File

@ -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);
}

View File

@ -61,7 +61,9 @@ 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;

View File

@ -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