summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Clayton <gclayton@apple.com>2011-01-18 19:36:39 +0000
committerGreg Clayton <gclayton@apple.com>2011-01-18 19:36:39 +0000
commitc4e411ffc09a77abe9957f83827fc1745d7e0408 (patch)
tree78a1107cecd93fdb0cda97b735d5ff23751f2c4a
parent4dc73fa075db86bc6a07d755d972e9f8ad7336cc (diff)
downloadbcm5719-llvm-c4e411ffc09a77abe9957f83827fc1745d7e0408.tar.gz
bcm5719-llvm-c4e411ffc09a77abe9957f83827fc1745d7e0408.zip
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
-rw-r--r--lldb/source/Expression/ClangUserExpression.cpp7
-rw-r--r--lldb/source/Expression/ClangUtilityFunction.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp1
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h15
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp54
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp9
-rw-r--r--lldb/source/Target/ThreadList.cpp2
-rw-r--r--lldb/source/Utility/StringExtractor.h8
-rw-r--r--lldb/tools/debugserver/source/DNBThreadResumeActions.h7
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.cpp35
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachProcess.h6
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.cpp91
-rw-r--r--lldb/tools/debugserver/source/MacOSX/MachThread.h7
-rw-r--r--lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp2
-rw-r--r--lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp2
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp196
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h21
17 files changed, 301 insertions, 172 deletions
diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp
index 13d5ab9c96b..c435136e2e6 100644
--- a/lldb/source/Expression/ClangUserExpression.cpp
+++ b/lldb/source/Expression/ClangUserExpression.cpp
@@ -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)
{
diff --git a/lldb/source/Expression/ClangUtilityFunction.cpp b/lldb/source/Expression/ClangUtilityFunction.cpp
index f682e360778..d3ede6b4a34 100644
--- a/lldb/source/Expression/ClangUtilityFunction.cpp
+++ b/lldb/source/Expression/ClangUtilityFunction.cpp
@@ -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();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 5925812f7f3..1a7b27b40f9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -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),
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index 7bc795dcf7a..c0d8685db39 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -100,6 +100,18 @@ public:
}
bool
+ GetThreadSuffixSupported () const
+ {
+ return m_thread_suffix_supported;
+ }
+
+ void
+ SetThreadSuffixSupported (bool enabled)
+ {
+ m_thread_suffix_supported = enabled;
+ }
+
+ bool
SendAsyncSignal (int signo);
bool
@@ -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;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index eaf91eb98b1..2c00b9a8431 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -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(),
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 80580f8dddc..26aa4564281 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -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))
diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp
index a4004ea9ee2..e5056326b1c 100644
--- a/lldb/source/Target/ThreadList.cpp
+++ b/lldb/source/Target/ThreadList.cpp
@@ -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)
{
diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h
index ed67b926c2a..bb65f707f7d 100644
--- a/lldb/source/Utility/StringExtractor.h
+++ b/lldb/source/Utility/StringExtractor.h
@@ -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
diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.h b/lldb/tools/debugserver/source/DNBThreadResumeActions.h
index f3fb8de6a82..81c7c43b722 100644
--- a/lldb/tools/debugserver/source/DNBThreadResumeActions.h
+++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.h
@@ -85,6 +85,13 @@ public:
{
return m_actions.size();
}
+
+ void
+ Clear()
+ {
+ m_actions.clear();
+ m_signal_handled.clear();
+ }
protected:
std::vector<DNBThreadResumeAction> m_actions;
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp
index 10f86f91225..05298168037 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.cpp
@@ -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
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
index 04ad02eb634..8866187b56a 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -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
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
index 7890c069a77..003a58b79d6 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp
@@ -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 ()
{
diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h
index 0b2a8bf1ff9..e7e18fe262c 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachThread.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h
@@ -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 *
diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
index 1222b809904..411e91426e1 100644
--- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
@@ -428,8 +428,6 @@ DNBArchImplI386::NotifyException(MachException::Data& exc)
// Write the new PC back out
SetGPRState ();
}
-
- m_thread->SetCurrentBreakpoint(breakID);
}
return true;
}
diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
index fde3be6ab5d..ce0e9c2c579 100644
--- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
+++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
@@ -355,8 +355,6 @@ DNBArchImplX86_64::NotifyException(MachException::Data& exc)
// Write the new PC back out
SetGPRState ();
}
-
- m_thread->SetCurrentBreakpoint(breakID);
}
return true;
}
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 7fa05073d72..7ce808dbab4 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -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_Q (const char *p)
+RNBRemote::HandlePacket_QStartNoAckMode (const char *p)
{
- if (p == NULL || strlen (p) <= 1)
- {
- return HandlePacket_ILLFORMED ("No subtype specified in Q packet");
- }
+ // Send the OK packet first so the correct checksum is appended...
+ rnb_err_t result = SendPacket ("OK");
+ m_noack_mode = true;
+ return result;
+}
- /* 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;
- }
+rnb_err_t
+RNBRemote::HandlePacket_QSetLogging (const char *p)
+{
+ 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, "QSetLogging:", sizeof ("QSetLogging:") - 1) == 0)
+rnb_err_t
+RNBRemote::HandlePacket_QSetDisableASLR (const char *p)
+{
+ extern int g_disable_aslr;
+ p += sizeof ("QSetDisableASLR:") - 1;
+ switch (*p)
{
- p += sizeof ("QSetLogging:") - 1;
- rnb_err_t result = set_logging (p);
- if (result == rnb_success)
- return SendPacket ("OK");
- else
- return SendPacket ("E35");
+ case '0': g_disable_aslr = 0; break;
+ case '1': g_disable_aslr = 1; break;
+ default:
+ return SendPacket ("E56");
}
+ return SendPacket ("OK");
+}
- 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");
- }
- 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();
-
- ctx.PushEnvironment (p);
- return SendPacket ("OK");
- }
+ p += sizeof ("QEnvironment:") - 1;
+ RNBContext& ctx = Context();
- // 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, &reg_value))
{
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index fab42bc9693..82febf7d226 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -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
OpenPOWER on IntegriCloud