Thread safety changes in debugserver and also in the process GDB remote plugin.
I added support for asking if the GDB remote server supports thread suffixes for packets that should be thread specific (register read/write packets) because the way the GDB remote protocol does it right now is to have a notion of a current thread for register and memory reads/writes (set via the "$Hg%x" packet) and a current thread for running ("$Hc%x"). Now we ask the remote GDB server if it supports adding the thread ID to the register packets and we enable that feature in LLDB if supported. This stops us from having to send a bunch of packets that update the current thread ID to some value which is prone to error, or extra packets. llvm-svn: 123762
This commit is contained in:
parent
4dc73fa075
commit
c4e411ffc0
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/ValueObjectConstResult.h"
|
||||
#include "lldb/Expression/ASTResultSynthesizer.h"
|
||||
|
@ -365,6 +366,12 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
|
|||
error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// jingham: look here
|
||||
StreamFile logfile ("/tmp/exprs.txt", "a");
|
||||
logfile.Printf("0x%16.16llx: thread = 0x%4.4x, expr = '%s'\n", m_jit_addr, exe_ctx.thread ? exe_ctx.thread->GetID() : -1, m_expr_text.c_str());
|
||||
#endif
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Expression/ClangExpressionDeclMap.h"
|
||||
#include "lldb/Expression/ClangExpressionParser.h"
|
||||
#include "lldb/Expression/ClangUtilityFunction.h"
|
||||
|
@ -124,6 +125,15 @@ ClangUtilityFunction::Install (Stream &error_stream,
|
|||
|
||||
Error jit_error = parser.MakeJIT (m_jit_begin, m_jit_end, exe_ctx);
|
||||
|
||||
#if 0
|
||||
// jingham: look here
|
||||
StreamFile logfile ("/tmp/exprs.txt", "a");
|
||||
logfile.Printf ("0x%16.16llx: func = %s, source =\n%s\n",
|
||||
m_jit_begin,
|
||||
m_function_name.c_str(),
|
||||
m_function_text.c_str());
|
||||
#endif
|
||||
|
||||
m_expr_decl_map->DidParse();
|
||||
|
||||
m_expr_decl_map.reset();
|
||||
|
|
|
@ -34,6 +34,7 @@ using namespace lldb_private;
|
|||
GDBRemoteCommunication::GDBRemoteCommunication() :
|
||||
Communication("gdb-remote.packets"),
|
||||
m_send_acks (true),
|
||||
m_thread_suffix_supported (false),
|
||||
m_rx_packet_listener ("gdbremote.rx_packet"),
|
||||
m_sequence_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_is_running (false),
|
||||
|
|
|
@ -99,6 +99,18 @@ public:
|
|||
m_send_acks = enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
GetThreadSuffixSupported () const
|
||||
{
|
||||
return m_thread_suffix_supported;
|
||||
}
|
||||
|
||||
void
|
||||
SetThreadSuffixSupported (bool enabled)
|
||||
{
|
||||
m_thread_suffix_supported = enabled;
|
||||
}
|
||||
|
||||
bool
|
||||
SendAsyncSignal (int signo);
|
||||
|
||||
|
@ -244,7 +256,8 @@ protected:
|
|||
//------------------------------------------------------------------
|
||||
// Classes that inherit from GDBRemoteCommunication can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
bool m_send_acks;
|
||||
bool m_send_acks:1,
|
||||
m_thread_suffix_supported:1;
|
||||
lldb_private::Listener m_rx_packet_listener;
|
||||
lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
|
||||
lldb_private::Predicate<bool> m_is_running;
|
||||
|
|
|
@ -217,15 +217,19 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
|
|||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker))
|
||||
{
|
||||
if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
|
||||
if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
{
|
||||
char packet[32];
|
||||
char packet[64];
|
||||
StringExtractorGDBRemote response;
|
||||
int packet_len;
|
||||
int packet_len = 0;
|
||||
if (m_read_all_at_once)
|
||||
{
|
||||
// Get all registers in one packet
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "g");
|
||||
if (thread_suffix_supported)
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x;", m_thread.GetID());
|
||||
else
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "g");
|
||||
assert (packet_len < (sizeof(packet) - 1));
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
|
||||
{
|
||||
|
@ -237,7 +241,10 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
|
|||
else
|
||||
{
|
||||
// Get each register individually
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
|
||||
if (thread_suffix_supported)
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4x;", reg, m_thread.GetID());
|
||||
else
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
|
||||
assert (packet_len < (sizeof(packet) - 1));
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
|
||||
PrivateSetRegisterValue (reg, response);
|
||||
|
@ -319,7 +326,8 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker))
|
||||
{
|
||||
if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
|
||||
if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
{
|
||||
uint32_t offset, end_offset;
|
||||
StreamString packet;
|
||||
|
@ -336,6 +344,9 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
eByteOrderHost,
|
||||
eByteOrderHost);
|
||||
|
||||
if (thread_suffix_supported)
|
||||
packet.Printf (";thread:%4.4x;", m_thread.GetID());
|
||||
|
||||
// Invalidate all register values
|
||||
InvalidateIfNeeded (true);
|
||||
|
||||
|
@ -361,6 +372,9 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
eByteOrderHost,
|
||||
eByteOrderHost);
|
||||
|
||||
if (thread_suffix_supported)
|
||||
packet.Printf (";thread:%4.4x;", m_thread.GetID());
|
||||
|
||||
// Invalidate just this register
|
||||
m_reg_valid[reg] = false;
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
|
||||
|
@ -391,16 +405,31 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
|
|||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker))
|
||||
{
|
||||
if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
char packet[32];
|
||||
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
|
||||
if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
{
|
||||
if (gdb_comm.SendPacketAndWaitForResponse("g", response, 1, false))
|
||||
int packet_len = 0;
|
||||
if (thread_suffix_supported)
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x", m_thread.GetID());
|
||||
else
|
||||
packet_len = ::snprintf (packet, sizeof(packet), "g");
|
||||
assert (packet_len < (sizeof(packet) - 1));
|
||||
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 1, false))
|
||||
{
|
||||
if (response.IsErrorPacket())
|
||||
return false;
|
||||
|
||||
|
||||
response.GetStringRef().insert(0, 1, 'G');
|
||||
data_sp.reset (new DataBufferHeap(response.GetStringRef().c_str(),
|
||||
response.GetStringRef().size()));
|
||||
if (thread_suffix_supported)
|
||||
{
|
||||
char thread_id_cstr[64];
|
||||
::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4x;", m_thread.GetID());
|
||||
response.GetStringRef().append (thread_id_cstr);
|
||||
}
|
||||
data_sp.reset (new DataBufferHeap (response.GetStringRef().c_str(),
|
||||
response.GetStringRef().size()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -419,7 +448,8 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
|
|||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker))
|
||||
{
|
||||
if (GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
|
||||
if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
|
||||
{
|
||||
if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(),
|
||||
data_sp->GetByteSize(),
|
||||
|
|
|
@ -554,6 +554,13 @@ ProcessGDBRemote::ConnectToDebugserver (const char *host_port)
|
|||
if (response.IsOKPacket())
|
||||
m_gdb_comm.SetAckMode (false);
|
||||
}
|
||||
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse("QThreadSuffixSupported", response, 1, false))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
m_gdb_comm.SetThreadSuffixSupported (true);
|
||||
}
|
||||
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -2021,7 +2028,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid)
|
|||
return true;
|
||||
|
||||
char packet[32];
|
||||
const int packet_len = ::snprintf (packet, sizeof(packet), "Hg%x", tid);
|
||||
const int packet_len = ::snprintf (packet, sizeof(packet), "Hc%x", tid);
|
||||
assert (packet_len + 1 < sizeof(packet));
|
||||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 2, false))
|
||||
|
|
|
@ -340,6 +340,7 @@ ThreadList::ShouldReportRun (Event *event_ptr)
|
|||
void
|
||||
ThreadList::Clear()
|
||||
{
|
||||
Mutex::Locker locker(m_threads_mutex);
|
||||
m_stop_id = 0;
|
||||
m_threads.clear();
|
||||
m_selected_tid = LLDB_INVALID_THREAD_ID;
|
||||
|
@ -504,6 +505,7 @@ ThreadList::WillResume ()
|
|||
void
|
||||
ThreadList::DidResume ()
|
||||
{
|
||||
Mutex::Locker locker(m_threads_mutex);
|
||||
collection::iterator pos, end = m_threads.end();
|
||||
for (pos = m_threads.begin(); pos != end; ++pos)
|
||||
{
|
||||
|
|
|
@ -113,6 +113,14 @@ public:
|
|||
size_t
|
||||
GetHexByteString (std::string &str);
|
||||
|
||||
const char *
|
||||
Peek ()
|
||||
{
|
||||
if (m_index < m_packet.size())
|
||||
return m_packet.c_str() + m_index;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
// For StringExtractor only
|
||||
|
|
|
@ -85,6 +85,13 @@ public:
|
|||
{
|
||||
return m_actions.size();
|
||||
}
|
||||
|
||||
void
|
||||
Clear()
|
||||
{
|
||||
m_actions.clear();
|
||||
m_signal_handled.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<DNBThreadResumeAction> m_actions;
|
||||
|
|
|
@ -101,6 +101,7 @@ MachProcess::MachProcess() :
|
|||
m_stdio_thread (0),
|
||||
m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE),
|
||||
m_stdout_data (),
|
||||
m_thread_actions (),
|
||||
m_thread_list (),
|
||||
m_exception_messages (),
|
||||
m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
|
||||
|
@ -314,7 +315,8 @@ MachProcess::Resume (const DNBThreadResumeActions& thread_actions)
|
|||
|
||||
if (CanResume(state))
|
||||
{
|
||||
PrivateResume(thread_actions);
|
||||
m_thread_actions = thread_actions;
|
||||
PrivateResume();
|
||||
return true;
|
||||
}
|
||||
else if (state == eStateRunning)
|
||||
|
@ -337,7 +339,8 @@ MachProcess::Kill (const struct timespec *timeout_abstime)
|
|||
DNBError err;
|
||||
err.SetErrorToErrno();
|
||||
DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", err.Error(), err.AsString());
|
||||
PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
|
||||
m_thread_actions = DNBThreadResumeActions (eStateRunning, 0);
|
||||
PrivateResume ();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -392,7 +395,8 @@ MachProcess::DoSIGSTOP (bool clear_bps_and_wps, uint32_t *thread_idx_ptr)
|
|||
// No threads were stopped with a SIGSTOP, we need to run and halt the
|
||||
// process with a signal
|
||||
DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state));
|
||||
PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
|
||||
m_thread_actions = DNBThreadResumeActions (eStateRunning, 0);
|
||||
PrivateResume ();
|
||||
|
||||
// Reset the event that says we were indeed running
|
||||
m_events.ResetEvents(eEventProcessRunningStateChanged);
|
||||
|
@ -428,20 +432,19 @@ MachProcess::Detach()
|
|||
DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state));
|
||||
|
||||
{
|
||||
DNBThreadResumeActions thread_actions;
|
||||
m_thread_actions.Clear();
|
||||
DNBThreadResumeAction thread_action;
|
||||
thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx);
|
||||
thread_action.state = eStateRunning;
|
||||
thread_action.signal = -1;
|
||||
thread_action.addr = INVALID_NUB_ADDRESS;
|
||||
|
||||
thread_actions.Append (thread_action);
|
||||
|
||||
thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
|
||||
m_thread_actions.Append (thread_action);
|
||||
m_thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0);
|
||||
|
||||
PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
|
||||
|
||||
ReplyToAllExceptions (thread_actions);
|
||||
ReplyToAllExceptions ();
|
||||
|
||||
}
|
||||
|
||||
|
@ -597,7 +600,7 @@ MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf)
|
|||
|
||||
|
||||
void
|
||||
MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions)
|
||||
MachProcess::ReplyToAllExceptions ()
|
||||
{
|
||||
PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
|
||||
if (m_exception_messages.empty() == false)
|
||||
|
@ -610,13 +613,13 @@ MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions)
|
|||
DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %d...", std::distance(begin, pos));
|
||||
int thread_reply_signal = 0;
|
||||
|
||||
const DNBThreadResumeAction *action = thread_actions.GetActionForThread (pos->state.thread_port, false);
|
||||
const DNBThreadResumeAction *action = m_thread_actions.GetActionForThread (pos->state.thread_port, false);
|
||||
|
||||
if (action)
|
||||
{
|
||||
thread_reply_signal = action->signal;
|
||||
if (thread_reply_signal)
|
||||
thread_actions.SetSignalHandledForThread (pos->state.thread_port);
|
||||
m_thread_actions.SetSignalHandledForThread (pos->state.thread_port);
|
||||
}
|
||||
|
||||
DNBError err (pos->Reply(this, thread_reply_signal));
|
||||
|
@ -630,20 +633,20 @@ MachProcess::ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions)
|
|||
}
|
||||
}
|
||||
void
|
||||
MachProcess::PrivateResume (const DNBThreadResumeActions& thread_actions)
|
||||
MachProcess::PrivateResume ()
|
||||
{
|
||||
PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex);
|
||||
|
||||
ReplyToAllExceptions (thread_actions);
|
||||
ReplyToAllExceptions ();
|
||||
// bool stepOverBreakInstruction = step;
|
||||
|
||||
// Let the thread prepare to resume and see if any threads want us to
|
||||
// step over a breakpoint instruction (ProcessWillResume will modify
|
||||
// the value of stepOverBreakInstruction).
|
||||
m_thread_list.ProcessWillResume (this, thread_actions);
|
||||
m_thread_list.ProcessWillResume (this, m_thread_actions);
|
||||
|
||||
// Set our state accordingly
|
||||
if (thread_actions.NumActionsWithState(eStateStepping))
|
||||
if (m_thread_actions.NumActionsWithState(eStateStepping))
|
||||
SetState (eStateStepping);
|
||||
else
|
||||
SetState (eStateRunning);
|
||||
|
@ -1100,7 +1103,7 @@ MachProcess::ExceptionMessageBundleComplete()
|
|||
else
|
||||
{
|
||||
// Resume without checking our current state.
|
||||
PrivateResume (DNBThreadResumeActions (eStateRunning, 0));
|
||||
PrivateResume ();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "DNBDefs.h"
|
||||
#include "DNBBreakpoint.h"
|
||||
#include "DNBError.h"
|
||||
#include "DNBThreadResumeActions.h"
|
||||
//#include "MachDYLD.h"
|
||||
#include "MachException.h"
|
||||
#include "MachVMMemory.h"
|
||||
|
@ -219,8 +220,8 @@ private:
|
|||
eMachProcessFlagsUsingSBS = (1 << 1)
|
||||
};
|
||||
void Clear ();
|
||||
void ReplyToAllExceptions (const DNBThreadResumeActions& thread_actions);
|
||||
void PrivateResume (const DNBThreadResumeActions& thread_actions);
|
||||
void ReplyToAllExceptions ();
|
||||
void PrivateResume ();
|
||||
nub_size_t RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, uint8_t *buf) const;
|
||||
|
||||
uint32_t Flags () const { return m_flags; }
|
||||
|
@ -239,6 +240,7 @@ private:
|
|||
pthread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
|
||||
PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio
|
||||
std::string m_stdout_data;
|
||||
DNBThreadResumeActions m_thread_actions; // The thread actions for the current MachProcess::Resume() call
|
||||
MachException::Message::collection
|
||||
m_exception_messages; // A collection of exception messages caught when listening to the exception port
|
||||
PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
|
||||
|
|
|
@ -339,6 +339,12 @@ MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action)
|
|||
m_stop_exception.Clear();
|
||||
}
|
||||
|
||||
nub_break_t
|
||||
MachThread::CurrentBreakpoint()
|
||||
{
|
||||
return m_process->Breakpoints().FindIDByAddress(GetPC());
|
||||
}
|
||||
|
||||
bool
|
||||
MachThread::ShouldStop(bool &step_more)
|
||||
{
|
||||
|
@ -394,14 +400,18 @@ MachThread::ShouldStop(bool &step_more)
|
|||
bool
|
||||
MachThread::IsStepping()
|
||||
{
|
||||
#if ENABLE_AUTO_STEPPING_OVER_BP
|
||||
// Return true if this thread is currently being stepped.
|
||||
// MachThread::ThreadWillResume currently determines this by looking if we
|
||||
// have been asked to single step, or if we are at a breakpoint instruction
|
||||
// and have been asked to resume. In the latter case we need to disable the
|
||||
// breakpoint we are at, single step, re-enable and continue.
|
||||
nub_state_t state = GetState();
|
||||
return (state == eStateStepping) ||
|
||||
(state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint()));
|
||||
return ((state == eStateStepping) ||
|
||||
(state == eStateRunning && NUB_BREAK_ID_IS_VALID(CurrentBreakpoint())));
|
||||
#else
|
||||
return GetState() == eStateStepping;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -430,6 +440,7 @@ MachThread::ThreadDidStop()
|
|||
// Update the basic information for a thread
|
||||
MachThread::GetBasicInfo(m_tid, &m_basicInfo);
|
||||
|
||||
#if ENABLE_AUTO_STEPPING_OVER_BP
|
||||
// See if we were at a breakpoint when we last resumed that we disabled,
|
||||
// re-enable it.
|
||||
nub_break_t breakID = CurrentBreakpoint();
|
||||
|
@ -469,10 +480,12 @@ MachThread::ThreadDidStop()
|
|||
SetState(eStateStopped);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SetCurrentBreakpoint(INVALID_NUB_BREAK_ID);
|
||||
|
||||
#else
|
||||
if (m_basicInfo.suspend_count > 0)
|
||||
SetState(eStateSuspended);
|
||||
else
|
||||
SetState(eStateStopped);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -496,30 +509,27 @@ MachThread::NotifyException(MachException::Data& exc)
|
|||
if (!handled)
|
||||
{
|
||||
handled = true;
|
||||
nub_addr_t pc = GetPC();
|
||||
nub_break_t breakID = m_process->Breakpoints().FindIDByAddress(pc);
|
||||
SetCurrentBreakpoint(breakID);
|
||||
switch (exc.exc_type)
|
||||
{
|
||||
case EXC_BAD_ACCESS:
|
||||
break;
|
||||
case EXC_BAD_INSTRUCTION:
|
||||
break;
|
||||
case EXC_ARITHMETIC:
|
||||
break;
|
||||
case EXC_EMULATION:
|
||||
break;
|
||||
case EXC_SOFTWARE:
|
||||
break;
|
||||
case EXC_BREAKPOINT:
|
||||
break;
|
||||
case EXC_SYSCALL:
|
||||
break;
|
||||
case EXC_MACH_SYSCALL:
|
||||
break;
|
||||
case EXC_RPC_ALERT:
|
||||
break;
|
||||
}
|
||||
// switch (exc.exc_type)
|
||||
// {
|
||||
// case EXC_BAD_ACCESS:
|
||||
// break;
|
||||
// case EXC_BAD_INSTRUCTION:
|
||||
// break;
|
||||
// case EXC_ARITHMETIC:
|
||||
// break;
|
||||
// case EXC_EMULATION:
|
||||
// break;
|
||||
// case EXC_SOFTWARE:
|
||||
// break;
|
||||
// case EXC_BREAKPOINT:
|
||||
// break;
|
||||
// case EXC_SYSCALL:
|
||||
// break;
|
||||
// case EXC_MACH_SYSCALL:
|
||||
// break;
|
||||
// case EXC_RPC_ALERT:
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
@ -658,27 +668,6 @@ MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MachThread::NotifyBreakpointChanged (const DNBBreakpoint *bp)
|
||||
{
|
||||
nub_break_t breakID = bp->GetID();
|
||||
if (bp->IsEnabled())
|
||||
{
|
||||
if (bp->Address() == GetPC())
|
||||
{
|
||||
SetCurrentBreakpoint(breakID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CurrentBreakpoint() == breakID)
|
||||
{
|
||||
SetCurrentBreakpoint(INVALID_NUB_BREAK_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MachThread::GetIdentifierInfo ()
|
||||
{
|
||||
|
|
|
@ -60,8 +60,7 @@ public:
|
|||
bool SetPC(uint64_t value); // Set program counter
|
||||
uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer
|
||||
|
||||
nub_break_t CurrentBreakpoint() const { return m_breakID; }
|
||||
void SetCurrentBreakpoint(nub_break_t breakID) { m_breakID = breakID; }
|
||||
nub_break_t CurrentBreakpoint();
|
||||
uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *breakpoint);
|
||||
uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *watchpoint);
|
||||
bool DisableHardwareBreakpoint (const DNBBreakpoint *breakpoint);
|
||||
|
@ -88,7 +87,9 @@ public:
|
|||
bool SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value );
|
||||
nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len);
|
||||
nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len);
|
||||
void NotifyBreakpointChanged (const DNBBreakpoint *bp);
|
||||
void NotifyBreakpointChanged (const DNBBreakpoint *bp)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsUserReady();
|
||||
struct thread_basic_info *
|
||||
|
|
|
@ -428,8 +428,6 @@ DNBArchImplI386::NotifyException(MachException::Data& exc)
|
|||
// Write the new PC back out
|
||||
SetGPRState ();
|
||||
}
|
||||
|
||||
m_thread->SetCurrentBreakpoint(breakID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -355,8 +355,6 @@ DNBArchImplX86_64::NotifyException(MachException::Data& exc)
|
|||
// Write the new PC back out
|
||||
SetGPRState ();
|
||||
}
|
||||
|
||||
m_thread->SetCurrentBreakpoint(breakID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ RNBRemote::RNBRemote (bool use_native_regs, const char *arch) :
|
|||
m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4),
|
||||
m_extended_mode(false),
|
||||
m_noack_mode(false),
|
||||
m_thread_suffix_supported (false),
|
||||
m_use_native_regs (use_native_regs)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__);
|
||||
|
@ -170,12 +171,13 @@ RNBRemote::CreatePacketTable ()
|
|||
t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported."));
|
||||
t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
|
||||
// t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups"));
|
||||
t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_Q , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
|
||||
t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_Q , NULL, "QSetLogging:", "Request that the " DEBUGSERVER_PROGRAM_NAME " set its logging mode bits"));
|
||||
t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle"));
|
||||
t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_Q , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle"));
|
||||
t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_Q , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment"));
|
||||
t.push_back (Packet (set_disable_aslr, &RNBRemote::HandlePacket_Q , NULL, "QSetDisableASLR:", "Set wether to disable ASLR when launching the process with the set argv ('A') packet"));
|
||||
t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
|
||||
t.push_back (Packet (prefix_reg_packets_with_tid, &RNBRemote::HandlePacket_QThreadSuffixSupported , NULL, "QThreadSuffixSupported", "Check if thread specifc packets (register packets 'g', 'G', 'p', and 'P') support having the thread ID appended to the end of the command"));
|
||||
t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_QSetLogging , NULL, "QSetLogging:", "Check if register packets ('g', 'G', 'p', and 'P' support having the thread ID prefix"));
|
||||
t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle"));
|
||||
t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_QSetMaxPayloadSize , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle"));
|
||||
t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_QEnvironment , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment"));
|
||||
t.push_back (Packet (set_disable_aslr, &RNBRemote::HandlePacket_QSetDisableASLR , NULL, "QSetDisableASLR:", "Set wether to disable ASLR when launching the process with the set argv ('A') packet"));
|
||||
// t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior"));
|
||||
t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process."));
|
||||
t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process."));
|
||||
|
@ -1702,104 +1704,105 @@ set_logging (const char *p)
|
|||
return rnb_success;
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QThreadSuffixSupported (const char *p)
|
||||
{
|
||||
m_thread_suffix_supported = true;
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QStartNoAckMode (const char *p)
|
||||
{
|
||||
// Send the OK packet first so the correct checksum is appended...
|
||||
rnb_err_t result = SendPacket ("OK");
|
||||
m_noack_mode = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_Q (const char *p)
|
||||
RNBRemote::HandlePacket_QSetLogging (const char *p)
|
||||
{
|
||||
if (p == NULL || strlen (p) <= 1)
|
||||
{
|
||||
return HandlePacket_ILLFORMED ("No subtype specified in Q packet");
|
||||
}
|
||||
|
||||
/* Switch to no-ack protocol mode after the "OK" packet is sent
|
||||
and the ack for that comes back from gdb. */
|
||||
|
||||
if (strcmp (p, "QStartNoAckMode") == 0)
|
||||
{
|
||||
rnb_err_t result = SendPacket ("OK");
|
||||
m_noack_mode = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (strncmp (p, "QSetLogging:", sizeof ("QSetLogging:") - 1) == 0)
|
||||
{
|
||||
p += sizeof ("QSetLogging:") - 1;
|
||||
rnb_err_t result = set_logging (p);
|
||||
if (result == rnb_success)
|
||||
return SendPacket ("OK");
|
||||
else
|
||||
return SendPacket ("E35");
|
||||
}
|
||||
|
||||
if (strncmp (p, "QSetDisableASLR:", sizeof ("QSetDisableASLR:") - 1) == 0)
|
||||
{
|
||||
extern int g_disable_aslr;
|
||||
p += sizeof ("QSetDisableASLR:") - 1;
|
||||
switch (*p)
|
||||
{
|
||||
case '0': g_disable_aslr = 0; break;
|
||||
case '1': g_disable_aslr = 1; break;
|
||||
default:
|
||||
return SendPacket ("E56");
|
||||
}
|
||||
p += sizeof ("QSetLogging:") - 1;
|
||||
rnb_err_t result = set_logging (p);
|
||||
if (result == rnb_success)
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
else
|
||||
return SendPacket ("E35");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QSetDisableASLR (const char *p)
|
||||
{
|
||||
extern int g_disable_aslr;
|
||||
p += sizeof ("QSetDisableASLR:") - 1;
|
||||
switch (*p)
|
||||
{
|
||||
case '0': g_disable_aslr = 0; break;
|
||||
case '1': g_disable_aslr = 1; break;
|
||||
default:
|
||||
return SendPacket ("E56");
|
||||
}
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QSetMaxPayloadSize (const char *p)
|
||||
{
|
||||
/* The number of characters in a packet payload that gdb is
|
||||
prepared to accept. The packet-start char, packet-end char,
|
||||
2 checksum chars and terminating null character are not included
|
||||
in this size. */
|
||||
if (strncmp (p, "QSetMaxPayloadSize:", sizeof ("QSetMaxPayloadSize:") - 1) == 0)
|
||||
p += sizeof ("QSetMaxPayloadSize:") - 1;
|
||||
errno = 0;
|
||||
uint32_t size = strtoul (p, NULL, 16);
|
||||
if (errno != 0 && size == 0)
|
||||
{
|
||||
p += sizeof ("QSetMaxPayloadSize:") - 1;
|
||||
errno = 0;
|
||||
uint32_t size = strtoul (p, NULL, 16);
|
||||
if (errno != 0 && size == 0)
|
||||
{
|
||||
return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPayloadSize packet");
|
||||
}
|
||||
m_max_payload_size = size;
|
||||
return SendPacket ("OK");
|
||||
return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPayloadSize packet");
|
||||
}
|
||||
m_max_payload_size = size;
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QSetMaxPacketSize (const char *p)
|
||||
{
|
||||
/* This tells us the largest packet that gdb can handle.
|
||||
i.e. the size of gdb's packet-reading buffer.
|
||||
QSetMaxPayloadSize is preferred because it is less ambiguous. */
|
||||
|
||||
if (strncmp (p, "QSetMaxPacketSize:", sizeof ("QSetMaxPacketSize:") - 1) == 0)
|
||||
p += sizeof ("QSetMaxPacketSize:") - 1;
|
||||
errno = 0;
|
||||
uint32_t size = strtoul (p, NULL, 16);
|
||||
if (errno != 0 && size == 0)
|
||||
{
|
||||
p += sizeof ("QSetMaxPacketSize:") - 1;
|
||||
errno = 0;
|
||||
uint32_t size = strtoul (p, NULL, 16);
|
||||
if (errno != 0 && size == 0)
|
||||
{
|
||||
return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPacketSize packet");
|
||||
}
|
||||
m_max_payload_size = size - 5;
|
||||
return SendPacket ("OK");
|
||||
return HandlePacket_ILLFORMED ("Invalid length in QSetMaxPacketSize packet");
|
||||
}
|
||||
m_max_payload_size = size - 5;
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
rnb_err_t
|
||||
RNBRemote::HandlePacket_QEnvironment (const char *p)
|
||||
{
|
||||
/* This sets the environment for the target program. The packet is of the form:
|
||||
|
||||
QEnvironment:VARIABLE=VALUE
|
||||
|
||||
*/
|
||||
|
||||
if (strncmp (p, "QEnvironment:", sizeof ("QEnvironment:") - 1) == 0)
|
||||
{
|
||||
DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"",
|
||||
(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p);
|
||||
DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"",
|
||||
(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p);
|
||||
|
||||
p += sizeof ("QEnvironment:") - 1;
|
||||
RNBContext& ctx = Context();
|
||||
p += sizeof ("QEnvironment:") - 1;
|
||||
RNBContext& ctx = Context();
|
||||
|
||||
ctx.PushEnvironment (p);
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
// Unrecognized Q packet
|
||||
return SendPacket ("");
|
||||
ctx.PushEnvironment (p);
|
||||
return SendPacket ("OK");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2245,7 +2248,9 @@ RNBRemote::HandlePacket_g (const char *p)
|
|||
InitializeRegisters ();
|
||||
|
||||
nub_process_t pid = m_ctx.ProcessID ();
|
||||
nub_thread_t tid = GetCurrentThread();
|
||||
nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p + 1);
|
||||
if (tid == INVALID_NUB_THREAD)
|
||||
return HandlePacket_ILLFORMED ("No thread specified in p packet");
|
||||
|
||||
if (m_use_native_regs)
|
||||
{
|
||||
|
@ -2291,7 +2296,9 @@ RNBRemote::HandlePacket_G (const char *p)
|
|||
packet.SetFilePos(1); // Skip the 'G'
|
||||
|
||||
nub_process_t pid = m_ctx.ProcessID();
|
||||
nub_thread_t tid = GetCurrentThread();
|
||||
nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p);
|
||||
if (tid == INVALID_NUB_THREAD)
|
||||
return HandlePacket_ILLFORMED ("No thread specified in p packet");
|
||||
|
||||
if (m_use_native_regs)
|
||||
{
|
||||
|
@ -2870,6 +2877,30 @@ RNBRemote::HandlePacket_z (const char *p)
|
|||
return HandlePacket_UNIMPLEMENTED(p);
|
||||
}
|
||||
|
||||
// Extract the thread number from the thread suffix that might be appended to
|
||||
// thread specific packets. This will only be enabled if m_thread_suffix_supported
|
||||
// is true.
|
||||
nub_thread_t
|
||||
RNBRemote::ExtractThreadIDFromThreadSuffix (const char *p)
|
||||
{
|
||||
if (m_thread_suffix_supported)
|
||||
{
|
||||
nub_thread_t tid = INVALID_NUB_THREAD;
|
||||
if (p)
|
||||
{
|
||||
const char *tid_cstr = strstr (p, "thread:");
|
||||
if (tid_cstr)
|
||||
{
|
||||
tid_cstr += strlen ("thread:");
|
||||
tid = strtoul(tid_cstr, NULL, 16);
|
||||
}
|
||||
DNBLogThreadedIf (LOG_RNB_PACKETS, "RNBRemote::ExtractThreadIDFromThreadSuffix(%s) got thread 0x%4.4x", p, tid);
|
||||
}
|
||||
}
|
||||
return GetCurrentThread();
|
||||
|
||||
}
|
||||
|
||||
/* `p XX'
|
||||
print the contents of register X */
|
||||
|
||||
|
@ -2889,12 +2920,17 @@ RNBRemote::HandlePacket_p (const char *p)
|
|||
}
|
||||
nub_process_t pid = m_ctx.ProcessID();
|
||||
errno = 0;
|
||||
uint32_t reg = strtoul (p + 1, NULL, 16);
|
||||
char *tid_cstr = NULL;
|
||||
uint32_t reg = strtoul (p + 1, &tid_cstr, 16);
|
||||
if (errno != 0 && reg == 0)
|
||||
{
|
||||
return HandlePacket_ILLFORMED ("Could not parse thread number in p packet");
|
||||
return HandlePacket_ILLFORMED ("Could not parse register number in p packet");
|
||||
}
|
||||
|
||||
nub_thread_t tid = ExtractThreadIDFromThreadSuffix (tid_cstr);
|
||||
if (tid == INVALID_NUB_THREAD)
|
||||
return HandlePacket_ILLFORMED ("No thread specified in p packet");
|
||||
|
||||
const register_map_entry_t *reg_entry;
|
||||
|
||||
if (reg < g_num_reg_entries)
|
||||
|
@ -2925,7 +2961,6 @@ RNBRemote::HandlePacket_p (const char *p)
|
|||
}
|
||||
else
|
||||
{
|
||||
nub_thread_t tid = GetCurrentThread();
|
||||
register_value_in_hex_fixed_width (ostrm, pid, tid, reg_entry);
|
||||
}
|
||||
return SendPacket (ostrm.str());
|
||||
|
@ -2985,8 +3020,9 @@ RNBRemote::HandlePacket_P (const char *p)
|
|||
reg_value.info = reg_entry->nub_info;
|
||||
packet.GetHexBytes (reg_value.value.v_sint8, reg_entry->gdb_size, 0xcc);
|
||||
|
||||
nub_thread_t tid;
|
||||
tid = GetCurrentThread ();
|
||||
nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p);
|
||||
if (tid == INVALID_NUB_THREAD)
|
||||
return HandlePacket_ILLFORMED ("No thread specified in p packet");
|
||||
|
||||
if (!DNBThreadSetRegisterValueByID (pid, tid, reg_entry->nub_info.set, reg_entry->nub_info.reg, ®_value))
|
||||
{
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
query_host_info, // 'qHostInfo'
|
||||
pass_signals_to_inferior, // 'QPassSignals'
|
||||
start_noack_mode, // 'QStartNoAckMode'
|
||||
prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID
|
||||
set_logging_mode, // 'QSetLogging:'
|
||||
set_max_packet_size, // 'QSetMaxPacketSize:'
|
||||
set_max_payload_size, // 'QSetMaxPayloadSize:'
|
||||
|
@ -156,7 +157,14 @@ public:
|
|||
rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
|
||||
rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
|
||||
rnb_err_t HandlePacket_qHostInfo (const char *p);
|
||||
rnb_err_t HandlePacket_Q (const char *p);
|
||||
rnb_err_t HandlePacket_QStartNoAckMode (const char *p);
|
||||
rnb_err_t HandlePacket_QThreadSuffixSupported (const char *p);
|
||||
rnb_err_t HandlePacket_QSetLogging (const char *p);
|
||||
rnb_err_t HandlePacket_QSetDisableASLR (const char *p);
|
||||
rnb_err_t HandlePacket_QSetMaxPayloadSize (const char *p);
|
||||
rnb_err_t HandlePacket_QSetMaxPacketSize (const char *p);
|
||||
rnb_err_t HandlePacket_QEnvironment (const char *p);
|
||||
rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p);
|
||||
rnb_err_t HandlePacket_last_signal (const char *p);
|
||||
rnb_err_t HandlePacket_m (const char *p);
|
||||
rnb_err_t HandlePacket_M (const char *p);
|
||||
|
@ -237,6 +245,9 @@ protected:
|
|||
void CreatePacketTable ();
|
||||
rnb_err_t GetPacketPayload (std::string &);
|
||||
|
||||
nub_thread_t
|
||||
ExtractThreadIDFromThreadSuffix (const char *p);
|
||||
|
||||
// gdb can send multiple Z/z packets for the same address and
|
||||
// these calls must be ref counted.
|
||||
struct Breakpoint
|
||||
|
@ -286,7 +297,13 @@ protected:
|
|||
uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb
|
||||
bool m_extended_mode:1, // are we in extended mode?
|
||||
m_noack_mode:1, // are we in no-ack mode?
|
||||
m_use_native_regs:1; // Use native registers by querying DNB layer for register definitions?
|
||||
m_noack_mode_just_enabled:1, // Did we just enable this and need to compute one more checksum?
|
||||
m_use_native_regs:1, // Use native registers by querying DNB layer for register definitions?
|
||||
m_thread_suffix_supported:1; // Set to true if the 'p', 'P', 'g', and 'G' packets should be prefixed with the thread ID and colon:
|
||||
// "$pRR;thread:TTTT;" instead of "$pRR"
|
||||
// "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV"
|
||||
// "$g;thread:TTTT" instead of "$g"
|
||||
// "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV"
|
||||
};
|
||||
|
||||
/* We translate the /usr/include/mach/exception_types.h exception types
|
||||
|
|
Loading…
Reference in New Issue