forked from OSchip/llvm-project
Don't stop execution in batch mode when process stops with SIGINT or SIGSTOP
Summary: Usually, SIGINT and SIGSTOP don't imply a crash, e.g. SIGSTOP is sent on process launch and attach on some platforms. Differential Revision: https://reviews.llvm.org/D67776 llvm-svn: 372961
This commit is contained in:
parent
6b794dfd3d
commit
a11668e87b
|
@ -502,6 +502,8 @@ protected:
|
|||
|
||||
void GetProcessOutput();
|
||||
|
||||
bool DidProcessStopAbnormally() const;
|
||||
|
||||
void SetSynchronous(bool value);
|
||||
|
||||
lldb::CommandObjectSP GetCommandSP(llvm::StringRef cmd,
|
||||
|
|
|
@ -144,14 +144,6 @@ public:
|
|||
|
||||
void SetInteractive(bool b);
|
||||
|
||||
bool GetAbnormalStopWasExpected() const {
|
||||
return m_abnormal_stop_was_expected;
|
||||
}
|
||||
|
||||
void SetAbnormalStopWasExpected(bool signal_was_expected) {
|
||||
m_abnormal_stop_was_expected = signal_was_expected;
|
||||
}
|
||||
|
||||
private:
|
||||
enum { eStreamStringIndex = 0, eImmediateStreamIndex = 1 };
|
||||
|
||||
|
@ -162,14 +154,6 @@ private:
|
|||
bool m_did_change_process_state;
|
||||
bool m_interactive; // If true, then the input handle from the debugger will
|
||||
// be hooked up
|
||||
bool m_abnormal_stop_was_expected; // This is to support
|
||||
// eHandleCommandFlagStopOnCrash vrs.
|
||||
// attach.
|
||||
// The attach command often ends up with the process stopped due to a signal.
|
||||
// Normally that would mean stop on crash should halt batch execution, but we
|
||||
// obviously don't want that for attach. Using this flag, the attach command
|
||||
// (and anything else for which this is relevant) can say that the signal is
|
||||
// expected, and batch command execution can continue.
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -78,6 +78,35 @@ class DriverBatchModeTest(PExpectTest):
|
|||
import pexpect
|
||||
child.expect(pexpect.EOF)
|
||||
|
||||
@expectedFlakeyFreeBSD("llvm.org/pr25172 fails rarely on the buildbot")
|
||||
def test_batch_mode_launch_stop_at_entry(self):
|
||||
"""Test that the lldb driver's batch mode works correctly for process launch."""
|
||||
self.build()
|
||||
|
||||
exe = self.getBuildArtifact("a.out")
|
||||
|
||||
# Launch with the option '--stop-at-entry' stops with a signal (usually SIGSTOP)
|
||||
# that should be suppressed since it doesn't imply a crash and
|
||||
# this is not a reason to exit batch mode.
|
||||
extra_args = ['-b',
|
||||
'-o', 'process launch --stop-at-entry',
|
||||
'-o', 'continue',
|
||||
]
|
||||
self.launch(executable=exe, extra_args=extra_args)
|
||||
child = self.child
|
||||
|
||||
# Check that the process has been launched:
|
||||
child.expect("Process ([0-9]+) launched:")
|
||||
# We should have continued:
|
||||
child.expect_exact("continue")
|
||||
# The App should have not have crashed:
|
||||
child.expect_exact("Got there on time and it did not crash.")
|
||||
|
||||
# Then lldb should exit.
|
||||
child.expect_exact("exited")
|
||||
import pexpect
|
||||
child.expect(pexpect.EOF)
|
||||
|
||||
def closeVictim(self):
|
||||
if self.victim is not None:
|
||||
self.victim.close()
|
||||
|
|
|
@ -429,7 +429,6 @@ protected:
|
|||
result.AppendMessage(stream.GetString());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
result.SetDidChangeProcessState(true);
|
||||
result.SetAbnormalStopWasExpected(true);
|
||||
} else {
|
||||
result.AppendError(
|
||||
"no error returned from Target::Attach, and target has no process");
|
||||
|
|
|
@ -63,8 +63,10 @@
|
|||
#include "lldb/Utility/Args.h"
|
||||
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
#include "lldb/Target/TargetList.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Target/UnixSignals.h"
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
@ -2138,6 +2140,45 @@ PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
|
|||
return platform_sp;
|
||||
}
|
||||
|
||||
bool CommandInterpreter::DidProcessStopAbnormally() const {
|
||||
TargetSP target_sp = m_debugger.GetTargetList().GetSelectedTarget();
|
||||
if (!target_sp)
|
||||
return false;
|
||||
|
||||
ProcessSP process_sp(target_sp->GetProcessSP());
|
||||
if (!process_sp)
|
||||
return false;
|
||||
|
||||
if (eStateStopped != process_sp->GetState())
|
||||
return false;
|
||||
|
||||
for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
|
||||
StopInfoSP stop_info = thread_sp->GetStopInfo();
|
||||
if (!stop_info)
|
||||
return false;
|
||||
|
||||
const StopReason reason = stop_info->GetStopReason();
|
||||
if (reason == eStopReasonException || reason == eStopReasonInstrumentation)
|
||||
return true;
|
||||
|
||||
if (reason == eStopReasonSignal) {
|
||||
const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
|
||||
UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
|
||||
if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
|
||||
// The signal is unknown, treat it as abnormal.
|
||||
return true;
|
||||
|
||||
const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
|
||||
const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
|
||||
if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
|
||||
// The signal very likely implies a crash.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandInterpreter::HandleCommands(const StringList &commands,
|
||||
ExecutionContext *override_context,
|
||||
CommandInterpreterRunOptions &options,
|
||||
|
@ -2248,38 +2289,22 @@ void CommandInterpreter::HandleCommands(const StringList &commands,
|
|||
}
|
||||
|
||||
// Also check for "stop on crash here:
|
||||
bool should_stop = false;
|
||||
if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash()) {
|
||||
TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
|
||||
if (target_sp) {
|
||||
ProcessSP process_sp(target_sp->GetProcessSP());
|
||||
if (process_sp) {
|
||||
for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
|
||||
StopReason reason = thread_sp->GetStopReason();
|
||||
if (reason == eStopReasonSignal || reason == eStopReasonException ||
|
||||
reason == eStopReasonInstrumentation) {
|
||||
should_stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (should_stop) {
|
||||
if (idx != num_lines - 1)
|
||||
result.AppendErrorWithFormat(
|
||||
"Aborting reading of commands after command #%" PRIu64
|
||||
": '%s' stopped with a signal or exception.\n",
|
||||
(uint64_t)idx + 1, cmd);
|
||||
else
|
||||
result.AppendMessageWithFormat(
|
||||
"Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
|
||||
(uint64_t)idx + 1, cmd);
|
||||
if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
|
||||
DidProcessStopAbnormally()) {
|
||||
if (idx != num_lines - 1)
|
||||
result.AppendErrorWithFormat(
|
||||
"Aborting reading of commands after command #%" PRIu64
|
||||
": '%s' stopped with a signal or exception.\n",
|
||||
(uint64_t)idx + 1, cmd);
|
||||
else
|
||||
result.AppendMessageWithFormat(
|
||||
"Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
|
||||
(uint64_t)idx + 1, cmd);
|
||||
|
||||
result.SetStatus(tmp_result.GetStatus());
|
||||
m_debugger.SetAsyncExecution(old_async_execution);
|
||||
result.SetStatus(tmp_result.GetStatus());
|
||||
m_debugger.SetAsyncExecution(old_async_execution);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2767,27 +2792,10 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
|
|||
|
||||
// Finally, if we're going to stop on crash, check that here:
|
||||
if (!m_quit_requested && result.GetDidChangeProcessState() &&
|
||||
io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash)) {
|
||||
bool should_stop = false;
|
||||
TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
|
||||
if (target_sp) {
|
||||
ProcessSP process_sp(target_sp->GetProcessSP());
|
||||
if (process_sp) {
|
||||
for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
|
||||
StopReason reason = thread_sp->GetStopReason();
|
||||
if ((reason == eStopReasonSignal || reason == eStopReasonException ||
|
||||
reason == eStopReasonInstrumentation) &&
|
||||
!result.GetAbnormalStopWasExpected()) {
|
||||
should_stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (should_stop) {
|
||||
io_handler.SetIsDone(true);
|
||||
m_stopped_for_crash = true;
|
||||
}
|
||||
io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
|
||||
DidProcessStopAbnormally()) {
|
||||
io_handler.SetIsDone(true);
|
||||
m_stopped_for_crash = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,7 @@ static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s,
|
|||
|
||||
CommandReturnObject::CommandReturnObject()
|
||||
: m_out_stream(), m_err_stream(), m_status(eReturnStatusStarted),
|
||||
m_did_change_process_state(false), m_interactive(true),
|
||||
m_abnormal_stop_was_expected(false) {}
|
||||
m_did_change_process_state(false), m_interactive(true) {}
|
||||
|
||||
CommandReturnObject::~CommandReturnObject() {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue