forked from OSchip/llvm-project
Remote Non-Stop Support
Summary: This patch is the beginnings of support for Non-stop mode in the remote protocol. Letting a user examine stopped threads, while other threads execute freely. Non-stop mode is enabled using the setting target.non-stop-mode, which sends a QNonStop packet when establishing the remote connection. Changes are also made to treat the '?' stop reply packet differently in non-stop mode, according to spec https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Non_002dStop.html#Remote-Non_002dStop. A setting for querying the remote for default thread on setup is also included. Handling of '%' async notification packets will be added next. Reviewers: clayborg Subscribers: lldb-commits, ADodds, ted, deepak2427 Differential Revision: http://reviews.llvm.org/D9656 llvm-svn: 237239
This commit is contained in:
parent
acf20fa233
commit
78baa19781
|
@ -189,6 +189,9 @@ public:
|
|||
|
||||
void
|
||||
SetUserSpecifiedTrapHandlerNames (const Args &args);
|
||||
|
||||
bool
|
||||
GetNonStopModeEnabled () const;
|
||||
|
||||
bool
|
||||
GetDisplayRuntimeSupportValues () const;
|
||||
|
|
|
@ -433,6 +433,12 @@ public:
|
|||
m_step_in_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_step_out_avoid_no_debug = eLazyBoolCalculate;
|
||||
m_run_mode = eOnlyDuringStepping;
|
||||
|
||||
// Check if we are in Non-Stop mode
|
||||
lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
|
||||
if (target_sp.get() != nullptr && target_sp->GetNonStopModeEnabled())
|
||||
m_run_mode = eOnlyThisThread;
|
||||
|
||||
m_avoid_regexp.clear();
|
||||
m_step_in_target.clear();
|
||||
m_class_name.clear();
|
||||
|
|
|
@ -424,6 +424,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
|
|||
content_length = total_length = 1; // The command is one byte long...
|
||||
break;
|
||||
|
||||
case '%': // Async notify packet
|
||||
case '$':
|
||||
// Look for a standard gdb packet?
|
||||
{
|
||||
|
@ -466,6 +467,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
|
|||
case '+':
|
||||
case '-':
|
||||
case '\x03':
|
||||
case '%':
|
||||
case '$':
|
||||
done = true;
|
||||
break;
|
||||
|
@ -586,7 +588,7 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
|
|||
}
|
||||
}
|
||||
|
||||
if (m_bytes[0] == '$')
|
||||
if (m_bytes[0] == '$' || m_bytes[0] == '%')
|
||||
{
|
||||
assert (checksum_idx < m_bytes.size());
|
||||
if (::isxdigit (m_bytes[checksum_idx+0]) ||
|
||||
|
|
|
@ -1620,6 +1620,22 @@ GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid)
|
||||
{
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success)
|
||||
return false;
|
||||
|
||||
if (!response.IsNormalResponse())
|
||||
return false;
|
||||
|
||||
if (response.GetChar() == 'Q' && response.GetChar() == 'C')
|
||||
tid = response.GetHexMaxU32(true, -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetHostInfo (bool force)
|
||||
{
|
||||
|
@ -2759,6 +2775,25 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::SetNonStopMode (const bool enable)
|
||||
{
|
||||
// Form non-stop packet request
|
||||
char packet[32];
|
||||
const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable);
|
||||
assert(packet_len < (int)sizeof(packet));
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
// Send to target
|
||||
if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
|
||||
if (response.IsOKResponse())
|
||||
return true;
|
||||
|
||||
// Failed or not supported
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets)
|
||||
{
|
||||
|
|
|
@ -318,6 +318,9 @@ public:
|
|||
|
||||
bool
|
||||
GetHostInfo (bool force = false);
|
||||
|
||||
bool
|
||||
GetDefaultThreadId (lldb::tid_t &tid);
|
||||
|
||||
bool
|
||||
GetOSVersion (uint32_t &major,
|
||||
|
@ -393,6 +396,9 @@ public:
|
|||
lldb::addr_t addr, // Address of breakpoint or watchpoint
|
||||
uint32_t length); // Byte Size of breakpoint or watchpoint
|
||||
|
||||
bool
|
||||
SetNonStopMode (const bool enable);
|
||||
|
||||
void
|
||||
TestPacketSpeed (const uint32_t num_packets);
|
||||
|
||||
|
|
|
@ -391,7 +391,8 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
|
|||
m_waiting_for_attach (false),
|
||||
m_destroy_tried_resuming (false),
|
||||
m_command_sp (),
|
||||
m_breakpoint_pc_offset (0)
|
||||
m_breakpoint_pc_offset (0),
|
||||
m_initial_tid (LLDB_INVALID_THREAD_ID)
|
||||
{
|
||||
m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
|
||||
m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
|
||||
|
@ -769,8 +770,13 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
|
|||
// We have a valid process
|
||||
SetID (pid);
|
||||
GetThreadList();
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)
|
||||
if (m_gdb_comm.GetStopReply(m_last_stop_packet))
|
||||
{
|
||||
|
||||
// '?' Packets must be handled differently in non-stop mode
|
||||
if (GetTarget().GetNonStopModeEnabled())
|
||||
HandleStopReplySequence();
|
||||
|
||||
if (!m_target.GetArchitecture().IsValid())
|
||||
{
|
||||
if (m_gdb_comm.GetProcessArchitecture().IsValid())
|
||||
|
@ -1052,8 +1058,13 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
|
|||
return error;
|
||||
}
|
||||
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success)
|
||||
if (m_gdb_comm.GetStopReply(m_last_stop_packet))
|
||||
{
|
||||
|
||||
// '?' Packets must be handled differently in non-stop mode
|
||||
if (GetTarget().GetNonStopModeEnabled())
|
||||
HandleStopReplySequence();
|
||||
|
||||
const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
|
||||
|
||||
if (process_arch.IsValid())
|
||||
|
@ -1153,12 +1164,22 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
|
|||
error.SetErrorString("not connected to remote gdb server");
|
||||
return error;
|
||||
}
|
||||
|
||||
// Send $QNonStop:1 packet on startup if required
|
||||
if (GetTarget().GetNonStopModeEnabled())
|
||||
m_gdb_comm.SetNonStopMode(true);
|
||||
|
||||
m_gdb_comm.GetThreadSuffixSupported ();
|
||||
m_gdb_comm.GetListThreadsInStopReplySupported ();
|
||||
m_gdb_comm.GetHostInfo ();
|
||||
m_gdb_comm.GetVContSupported ('c');
|
||||
m_gdb_comm.GetVAttachOrWaitSupported();
|
||||
|
||||
|
||||
// Ask the remote server for the default thread id
|
||||
if (GetTarget().GetNonStopModeEnabled())
|
||||
m_gdb_comm.GetDefaultThreadId(m_initial_tid);
|
||||
|
||||
|
||||
size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
|
||||
for (size_t idx = 0; idx < num_cmds; idx++)
|
||||
{
|
||||
|
@ -1430,11 +1451,12 @@ ProcessGDBRemote::DoResume ()
|
|||
bool continue_packet_error = false;
|
||||
if (m_gdb_comm.HasAnyVContSupport ())
|
||||
{
|
||||
if (m_continue_c_tids.size() == num_threads ||
|
||||
if (!GetTarget().GetNonStopModeEnabled() &&
|
||||
(m_continue_c_tids.size() == num_threads ||
|
||||
(m_continue_c_tids.empty() &&
|
||||
m_continue_C_tids.empty() &&
|
||||
m_continue_s_tids.empty() &&
|
||||
m_continue_S_tids.empty()))
|
||||
m_continue_S_tids.empty())))
|
||||
{
|
||||
// All threads are continuing, just send a "c" packet
|
||||
continue_packet.PutCString ("c");
|
||||
|
@ -1661,6 +1683,27 @@ ProcessGDBRemote::DoResume ()
|
|||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessGDBRemote::HandleStopReplySequence ()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
// Send vStopped
|
||||
StringExtractorGDBRemote response;
|
||||
m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false);
|
||||
|
||||
// OK represents end of signal list
|
||||
if (response.IsOKResponse())
|
||||
break;
|
||||
|
||||
// If not OK or a normal packet we have a problem
|
||||
if (!response.IsNormalResponse())
|
||||
break;
|
||||
|
||||
SetLastStopPacket(response);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProcessGDBRemote::ClearThreadIDList ()
|
||||
{
|
||||
|
@ -2095,6 +2138,13 @@ ProcessGDBRemote::RefreshStateAfterStop ()
|
|||
UpdateThreadIDList();
|
||||
}
|
||||
|
||||
// If we have queried for a default thread id
|
||||
if (m_initial_tid != LLDB_INVALID_THREAD_ID)
|
||||
{
|
||||
m_thread_list.SetSelectedThreadByID(m_initial_tid);
|
||||
m_initial_tid = LLDB_INVALID_THREAD_ID;
|
||||
}
|
||||
|
||||
// Let all threads recover from stopping and do any clean up based
|
||||
// on the previous thread state (if any).
|
||||
m_thread_list_real.RefreshStateAfterStop();
|
||||
|
|
|
@ -358,6 +358,7 @@ protected:
|
|||
bool m_destroy_tried_resuming;
|
||||
lldb::CommandObjectSP m_command_sp;
|
||||
int64_t m_breakpoint_pc_offset;
|
||||
lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach
|
||||
|
||||
bool
|
||||
StartAsyncThread ();
|
||||
|
@ -378,6 +379,9 @@ protected:
|
|||
lldb::StateType
|
||||
SetThreadStopInfo (StringExtractor& stop_packet);
|
||||
|
||||
void
|
||||
HandleStopReplySequence ();
|
||||
|
||||
void
|
||||
ClearThreadIDList ();
|
||||
|
||||
|
|
|
@ -2978,6 +2978,7 @@ g_properties[] =
|
|||
{ "display-expression-in-crashlogs" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true." },
|
||||
{ "trap-handler-names" , OptionValue::eTypeArray , true, OptionValue::eTypeString, NULL, NULL, "A list of trap handler function names, e.g. a common Unix user process one is _sigtramp." },
|
||||
{ "display-runtime-support-values" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "If true, LLDB will show variables that are meant to support the operation of a language's runtime support." },
|
||||
{ "non-stop-mode" , OptionValue::eTypeBoolean , false, 0, NULL, NULL, "Disable lock-step debugging, instead control threads independently." },
|
||||
{ NULL , OptionValue::eTypeInvalid , false, 0 , NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -3016,7 +3017,8 @@ enum
|
|||
ePropertyMemoryModuleLoadLevel,
|
||||
ePropertyDisplayExpressionsInCrashlogs,
|
||||
ePropertyTrapHandlerNames,
|
||||
ePropertyDisplayRuntimeSupportValues
|
||||
ePropertyDisplayRuntimeSupportValues,
|
||||
ePropertyNonStopModeEnabled
|
||||
};
|
||||
|
||||
|
||||
|
@ -3515,6 +3517,13 @@ TargetProperties::SetDisplayRuntimeSupportValues (bool b)
|
|||
m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
|
||||
}
|
||||
|
||||
bool
|
||||
TargetProperties::GetNonStopModeEnabled () const
|
||||
{
|
||||
const uint32_t idx = ePropertyNonStopModeEnabled;
|
||||
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, false);
|
||||
}
|
||||
|
||||
const ProcessLaunchInfo &
|
||||
TargetProperties::GetProcessLaunchInfo ()
|
||||
{
|
||||
|
|
|
@ -64,6 +64,10 @@ StringExtractorGDBRemote::GetServerPacketType () const
|
|||
const char *packet_cstr = m_packet.c_str();
|
||||
switch (m_packet[0])
|
||||
{
|
||||
|
||||
case '%':
|
||||
return eServerPacketType_notify;
|
||||
|
||||
case '\x03':
|
||||
if (packet_size == 1) return eServerPacketType_interrupt;
|
||||
break;
|
||||
|
|
|
@ -145,6 +145,7 @@ public:
|
|||
|
||||
eServerPacketType__M,
|
||||
eServerPacketType__m,
|
||||
eServerPacketType_notify, // '%' notification
|
||||
};
|
||||
|
||||
ServerPacketType
|
||||
|
|
Loading…
Reference in New Issue