204 changes: 71 additions & 133 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,10 +603,6 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
if (m_gdb_comm.GetStopReply(response)) {
SetLastStopPacket(response);

// '?' Packets must be handled differently in non-stop mode
if (GetTarget().GetNonStopModeEnabled())
HandleStopReplySequence();

Target &target = GetTarget();
if (!target.GetArchitecture().IsValid()) {
if (m_gdb_comm.GetProcessArchitecture().IsValid()) {
Expand Down Expand Up @@ -846,9 +842,6 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
StringExtractorGDBRemote response;
if (m_gdb_comm.GetStopReply(response)) {
SetLastStopPacket(response);
// '?' Packets must be handled differently in non-stop mode
if (GetTarget().GetNonStopModeEnabled())
HandleStopReplySequence();

const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();

Expand Down Expand Up @@ -919,11 +912,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
return error;
}

// Start the communications read thread so all incoming data can be parsed
// into packets and queued as they arrive.
if (GetTarget().GetNonStopModeEnabled())
m_gdb_comm.StartReadThread();

// We always seem to be able to open a connection to a local port so we need
// to make sure we can then send data to it. If we can't then we aren't
// actually connected to anything, so try and do the handshake with the
Expand All @@ -935,10 +923,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
return error;
}

// Send $QNonStop:1 packet on startup if required
if (GetTarget().GetNonStopModeEnabled())
GetTarget().SetNonStopModeEnabled(m_gdb_comm.SetNonStopMode(true));

m_gdb_comm.GetEchoSupported();
m_gdb_comm.GetThreadSuffixSupported();
m_gdb_comm.GetListThreadsInStopReplySupported();
Expand All @@ -947,10 +931,6 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) {
m_gdb_comm.GetVAttachOrWaitSupported();
m_gdb_comm.EnableErrorStringInPacket();

// 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++) {
StringExtractorGDBRemote response;
Expand Down Expand Up @@ -1210,10 +1190,9 @@ Status ProcessGDBRemote::DoResume() {
StreamString continue_packet;
bool continue_packet_error = false;
if (m_gdb_comm.HasAnyVContSupport()) {
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()))) {
if (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())) {
// All threads are continuing, just send a "c" packet
continue_packet.PutCString("c");
} else {
Expand Down Expand Up @@ -1331,14 +1310,7 @@ Status ProcessGDBRemote::DoResume() {
// All threads are resuming...
m_gdb_comm.SetCurrentThreadForRun(-1);
// If in Non-Stop-Mode use vCont when stepping
if (GetTarget().GetNonStopModeEnabled()) {
if (m_gdb_comm.GetVContSupported('s'))
continue_packet.PutCString("vCont;s");
else
continue_packet.PutChar('s');
} else
continue_packet.PutChar('s');
continue_packet.PutChar('s');
continue_packet_error = false;
} else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 &&
Expand Down Expand Up @@ -1495,12 +1467,9 @@ bool ProcessGDBRemote::UpdateThreadIDList() {
std::unique_lock<std::recursive_mutex> stop_stack_lock(
m_last_stop_packet_mutex, std::defer_lock);
if (stop_stack_lock.try_lock()) {
// Get the number of stop packets on the stack
int nItems = m_stop_packet_stack.size();
// Iterate over them
for (int i = 0; i < nItems; i++) {
if (m_last_stop_packet) {
// Get the thread stop info
StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i];
StringExtractorGDBRemote &stop_info = *m_last_stop_packet;
const std::string &stop_info_str =
std::string(stop_info.GetStringRef());
Expand Down Expand Up @@ -2352,17 +2321,9 @@ void ProcessGDBRemote::RefreshStateAfterStop() {
{
// Lock the thread stack while we access it
std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex);
// Get the number of stop packets on the stack
int nItems = m_stop_packet_stack.size();
// Iterate over them
for (int i = 0; i < nItems; i++) {
// Get the thread stop info
StringExtractorGDBRemote stop_info = m_stop_packet_stack[i];
// Process thread stop info
SetThreadStopInfo(stop_info);
}
// Clear the thread stop stack
m_stop_packet_stack.clear();
if (m_last_stop_packet)
SetThreadStopInfo(*m_last_stop_packet);
m_last_stop_packet.reset();
}

// If we have queried for a default thread id
Expand Down Expand Up @@ -2615,14 +2576,7 @@ void ProcessGDBRemote::SetLastStopPacket(
// Lock the thread stack while we access it
std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex);

// We are are not using non-stop mode, there can only be one last stop
// reply packet, so clear the list.
if (!GetTarget().GetNonStopModeEnabled())
m_stop_packet_stack.clear();

// Add this stop packet to the stop packet stack This stack will get popped
// and examined when we switch to the Stopped state
m_stop_packet_stack.push_back(response);
m_last_stop_packet = response;
}
}

Expand Down Expand Up @@ -3740,88 +3694,72 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
process->SetPrivateState(eStateRunning);
StringExtractorGDBRemote response;

// If in Non-Stop-Mode
if (process->GetTarget().GetNonStopModeEnabled()) {
// send the vCont packet
if (!process->GetGDBRemote().SendvContPacket(
llvm::StringRef(continue_cstr, continue_cstr_len),
process->GetInterruptTimeout(), response)) {
// Something went wrong
done = true;
break;
}
}
// If in All-Stop-Mode
else {
StateType stop_state =
process->GetGDBRemote().SendContinuePacketAndWaitForResponse(
*process, *process->GetUnixSignals(),
llvm::StringRef(continue_cstr, continue_cstr_len),
process->GetInterruptTimeout(),
response);

// We need to immediately clear the thread ID list so we are sure
// to get a valid list of threads. The thread ID list might be
// contained within the "response", or the stop reply packet that
// caused the stop. So clear it now before we give the stop reply
// packet to the process using the
// process->SetLastStopPacket()...
process->ClearThreadIDList();
StateType stop_state =
process->GetGDBRemote().SendContinuePacketAndWaitForResponse(
*process, *process->GetUnixSignals(),
llvm::StringRef(continue_cstr, continue_cstr_len),
process->GetInterruptTimeout(), response);

// We need to immediately clear the thread ID list so we are sure
// to get a valid list of threads. The thread ID list might be
// contained within the "response", or the stop reply packet that
// caused the stop. So clear it now before we give the stop reply
// packet to the process using the
// process->SetLastStopPacket()...
process->ClearThreadIDList();

switch (stop_state) {
case eStateStopped:
case eStateCrashed:
case eStateSuspended:
process->SetLastStopPacket(response);
process->SetPrivateState(stop_state);
break;

switch (stop_state) {
case eStateStopped:
case eStateCrashed:
case eStateSuspended:
process->SetLastStopPacket(response);
process->SetPrivateState(stop_state);
break;

case eStateExited: {
process->SetLastStopPacket(response);
process->ClearThreadIDList();
response.SetFilePos(1);

int exit_status = response.GetHexU8();
std::string desc_string;
if (response.GetBytesLeft() > 0 &&
response.GetChar('-') == ';') {
llvm::StringRef desc_str;
llvm::StringRef desc_token;
while (response.GetNameColonValue(desc_token, desc_str)) {
if (desc_token != "description")
continue;
StringExtractor extractor(desc_str);
extractor.GetHexByteString(desc_string);
}
case eStateExited: {
process->SetLastStopPacket(response);
process->ClearThreadIDList();
response.SetFilePos(1);

int exit_status = response.GetHexU8();
std::string desc_string;
if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') {
llvm::StringRef desc_str;
llvm::StringRef desc_token;
while (response.GetNameColonValue(desc_token, desc_str)) {
if (desc_token != "description")
continue;
StringExtractor extractor(desc_str);
extractor.GetHexByteString(desc_string);
}
process->SetExitStatus(exit_status, desc_string.c_str());
done = true;
break;
}
case eStateInvalid: {
// Check to see if we were trying to attach and if we got back
// the "E87" error code from debugserver -- this indicates that
// the process is not debuggable. Return a slightly more
// helpful error message about why the attach failed.
if (::strstr(continue_cstr, "vAttach") != nullptr &&
response.GetError() == 0x87) {
process->SetExitStatus(-1, "cannot attach to process due to "
"System Integrity Protection");
} else if (::strstr(continue_cstr, "vAttach") != nullptr &&
response.GetStatus().Fail()) {
process->SetExitStatus(-1, response.GetStatus().AsCString());
} else {
process->SetExitStatus(-1, "lost connection");
}
done = true;
break;
process->SetExitStatus(exit_status, desc_string.c_str());
done = true;
break;
}
case eStateInvalid: {
// Check to see if we were trying to attach and if we got back
// the "E87" error code from debugserver -- this indicates that
// the process is not debuggable. Return a slightly more
// helpful error message about why the attach failed.
if (::strstr(continue_cstr, "vAttach") != nullptr &&
response.GetError() == 0x87) {
process->SetExitStatus(-1, "cannot attach to process due to "
"System Integrity Protection");
} else if (::strstr(continue_cstr, "vAttach") != nullptr &&
response.GetStatus().Fail()) {
process->SetExitStatus(-1, response.GetStatus().AsCString());
} else {
process->SetExitStatus(-1, "lost connection");
}
done = true;
break;
}

default:
process->SetPrivateState(stop_state);
break;
} // switch(stop_state)
} // else // if in All-stop-mode
default:
process->SetPrivateState(stop_state);
break;
} // switch(stop_state)
} // if (continue_packet)
} // case eBroadcastBitAsyncContinue
break;
Expand Down
7 changes: 3 additions & 4 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,10 @@ class ProcessGDBRemote : public Process,
GDBRemoteCommunicationClient m_gdb_comm;
GDBRemoteCommunicationReplayServer m_gdb_replay_server;
std::atomic<lldb::pid_t> m_debugserver_pid;
std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet
// stack replaces
// the last stop
// packet variable

llvm::Optional<StringExtractorGDBRemote> m_last_stop_packet;
std::recursive_mutex m_last_stop_packet_mutex;

GDBRemoteDynamicRegisterInfoSP m_register_info_sp;
Broadcaster m_async_broadcaster;
lldb::ListenerSP m_async_listener_sp;
Expand Down
10 changes: 0 additions & 10 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4288,16 +4288,6 @@ void TargetProperties::SetDisplayRecognizedArguments(bool b) {
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}

bool TargetProperties::GetNonStopModeEnabled() const {
const uint32_t idx = ePropertyNonStopModeEnabled;
return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false);
}

void TargetProperties::SetNonStopModeEnabled(bool b) {
const uint32_t idx = ePropertyNonStopModeEnabled;
m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
}

const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() const {
return m_launch_info;
}
Expand Down
3 changes: 0 additions & 3 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ let Definition = "target" in {
def DisplayRecognizedArguments: Property<"display-recognized-arguments", "Boolean">,
DefaultFalse,
Desc<"Show recognized arguments in variable listings by default.">;
def NonStopModeEnabled: Property<"non-stop-mode", "Boolean">,
DefaultFalse,
Desc<"Disable lock-step debugging, instead control threads independently.">;
def RequireHardwareBreakpoints: Property<"require-hardware-breakpoint", "Boolean">,
DefaultFalse,
Desc<"Require all breakpoints to be hardware breakpoints.">;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
class TestCase(TestBase):

mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True

@skipIfRemote
def test_load_after_attach(self):
Expand All @@ -17,18 +18,19 @@ def test_load_after_attach(self):
exe = self.getBuildArtifact("a.out")
lib = self.getBuildArtifact(lib_name)

target = self.dbg.CreateTarget(exe)
environment = self.registerSharedLibrariesWithTarget(target, ["lib_b"])

# Spawn a new process.
# use realpath to workaround llvm.org/pr48376
# Pass path to solib for dlopen to properly locate the library.
popen = self.spawnSubprocess(os.path.realpath(exe), args = [os.path.realpath(lib)])
pid = popen.pid
popen = self.spawnSubprocess(os.path.realpath(exe), extra_env=environment)

# Attach to the spawned process.
self.runCmd("process attach -p " + str(pid))

target = self.dbg.GetSelectedTarget()
process = target.GetProcess()
self.assertTrue(process, PROCESS_IS_VALID)
error = lldb.SBError()
process = target.AttachToProcessWithID(self.dbg.GetListener(),
popen.pid, error)
self.assertSuccess(error)

# Continue until first breakpoint.
breakpoint1 = self.target().BreakpointCreateBySourceRegex(
Expand Down
28 changes: 4 additions & 24 deletions lldb/test/API/functionalities/load_after_attach/main.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,10 @@
#ifdef _WIN32
#include <Windows.h>
#else
#include <dlfcn.h>
#include <unistd.h>
#endif

#include <assert.h>
#include <stdio.h>
#include "dylib.h"
#include <cassert>
#include <cstdio>
#include <thread>
#include <chrono>

// We do not use the dylib.h implementation, because
// we need to pass full path to the dylib.
void* dylib_open(const char* full_path) {
#ifdef _WIN32
return LoadLibraryA(full_path);
#else
return dlopen(full_path, RTLD_LAZY);
#endif
}

int main(int argc, char* argv[]) {
assert(argc == 2 && "argv[1] must be the full path to lib_b library");
const char* dylib_full_path= argv[1];
printf("Using dylib at: %s\n", dylib_full_path);

// Wait until debugger is attached.
int main_thread_continue = 0;
int i = 0;
Expand All @@ -38,7 +18,7 @@ int main(int argc, char* argv[]) {
assert(i != timeout && "timed out waiting for debugger");

// dlopen the 'liblib_b.so' shared library.
void* dylib_handle = dylib_open(dylib_full_path);
void* dylib_handle = dylib_open("lib_b");
assert(dylib_handle && "dlopen failed");

return i; // break after dlopen
Expand Down