forked from OSchip/llvm-project
<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:
parent
42bca056e0
commit
97d5cf05eb
|
@ -590,7 +590,7 @@ public:
|
|||
static void
|
||||
UnitTest(Stream *s);
|
||||
|
||||
private:
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// Member variables
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue