jingham updated this revision to Diff 432145.
jingham added a comment.
Address Jonas' review comments
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D126259/new/
https://reviews.llvm.org/D126259
Files:
lldb/include/lldb/Target/Target.h
lldb/include/lldb/Target/UnixSignals.h
lldb/packages/Python/lldbsuite/test/lldbutil.py
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Commands/Options.td
lldb/source/Target/Process.cpp
lldb/source/Target/Target.cpp
lldb/source/Target/UnixSignals.cpp
lldb/test/API/commands/process/handle/Makefile
lldb/test/API/commands/process/handle/TestProcessHandle.py
lldb/test/API/commands/process/handle/main.cpp
lldb/test/API/functionalities/signal/raise/TestRaise.py
lldb/unittests/Signals/UnixSignalsTest.cpp
Index: lldb/unittests/Signals/UnixSignalsTest.cpp
===================================================================
--- lldb/unittests/Signals/UnixSignalsTest.cpp
+++ lldb/unittests/Signals/UnixSignalsTest.cpp
@@ -53,6 +53,29 @@
EXPECT_EQ(LLDB_INVALID_SIGNAL_NUMBER, signals.GetNextSignalNumber(16));
}
+TEST(UnixSignalsTest, Reset) {
+ TestSignals signals;
+ bool stop_val = signals.GetShouldStop(2);
+ bool notify_val = signals.GetShouldNotify(2);
+ bool suppress_val = signals.GetShouldSuppress(2);
+
+ // Change two, then reset one and make sure only that one was reset:
+ EXPECT_EQ(true, signals.SetShouldNotify(2, !notify_val));
+ EXPECT_EQ(true, signals.SetShouldSuppress(2, !suppress_val));
+ EXPECT_EQ(true, signals.ResetSignal(2, false, true, false));
+ EXPECT_EQ(stop_val, signals.GetShouldStop(2));
+ EXPECT_EQ(notify_val, signals.GetShouldStop(2));
+ EXPECT_EQ(!suppress_val, signals.GetShouldNotify(2));
+
+ // Make sure reset with no arguments resets them all:
+ EXPECT_EQ(true, signals.SetShouldSuppress(2, !suppress_val));
+ EXPECT_EQ(true, signals.SetShouldNotify(2, !notify_val));
+ EXPECT_EQ(true, signals.ResetSignal(2));
+ EXPECT_EQ(stop_val, signals.GetShouldStop(2));
+ EXPECT_EQ(notify_val, signals.GetShouldNotify(2));
+ EXPECT_EQ(suppress_val, signals.GetShouldSuppress(2));
+}
+
TEST(UnixSignalsTest, GetInfo) {
TestSignals signals;
Index: lldb/test/API/functionalities/signal/raise/TestRaise.py
===================================================================
--- lldb/test/API/functionalities/signal/raise/TestRaise.py
+++ lldb/test/API/functionalities/signal/raise/TestRaise.py
@@ -36,6 +36,10 @@
def launch(self, target, signal):
# launch the process, do not stop at entry point.
+ # If we have gotten the default for this signal, reset that as well.
+ if len(self.default_pass) != 0:
+ lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
+
process = target.LaunchSimple(
[signal], None, self.get_process_working_directory())
self.assertTrue(process, PROCESS_IS_VALID)
@@ -64,27 +68,19 @@
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
lldbutil.run_break_set_by_symbol(self, "main")
+ self.default_pass = ""
+ self.default_stop = ""
+ self.default_notify = ""
# launch
process = self.launch(target, signal)
signo = process.GetUnixSignals().GetSignalNumberFromName(signal)
# retrieve default signal disposition
- return_obj = lldb.SBCommandReturnObject()
- self.dbg.GetCommandInterpreter().HandleCommand(
- "process handle %s " % signal, return_obj)
- match = re.match(
- 'NAME *PASS *STOP *NOTIFY.*(false|true) *(false|true) *(false|true)',
- return_obj.GetOutput(),
- re.IGNORECASE | re.DOTALL)
- if not match:
- self.fail('Unable to retrieve default signal disposition.')
- default_pass = match.group(1)
- default_stop = match.group(2)
- default_notify = match.group(3)
+ (self.default_pass, self.default_stop, self.default_notify) = lldbutil.get_actions_for_signal(self, signal)
# Make sure we stop at the signal
- self.set_handle(signal, "false", "true", "true")
+ lldbutil.set_actions_for_signal(self, signal, "false", "true", "true")
process.Continue()
self.assertEqual(process.GetState(), lldb.eStateStopped)
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
@@ -102,12 +98,11 @@
self.assertEqual(process.GetState(), lldb.eStateExited)
self.assertEqual(process.GetExitStatus(), 0)
- # launch again
process = self.launch(target, signal)
# Make sure we do not stop at the signal. We should still get the
# notification.
- self.set_handle(signal, "false", "false", "true")
+ lldbutil.set_actions_for_signal(self, signal, "false", "false", "true")
self.expect(
"process continue",
substrs=[
@@ -121,7 +116,7 @@
# Make sure we do not stop at the signal, and we do not get the
# notification.
- self.set_handle(signal, "false", "false", "false")
+ lldbutil.set_actions_for_signal(self, signal, "false", "false", "false")
self.expect(
"process continue",
substrs=["stopped and restarted"],
@@ -131,14 +126,14 @@
if not test_passing:
# reset signal handling to default
- self.set_handle(signal, default_pass, default_stop, default_notify)
+ lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
return
# launch again
process = self.launch(target, signal)
# Make sure we stop at the signal
- self.set_handle(signal, "true", "true", "true")
+ lldbutil.set_actions_for_signal(self, signal, "true", "true", "true")
process.Continue()
self.assertEqual(process.GetState(), lldb.eStateStopped)
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal)
@@ -164,7 +159,7 @@
# Make sure we do not stop at the signal. We should still get the notification. Process
# should receive the signal.
- self.set_handle(signal, "true", "false", "true")
+ lldbutil.set_actions_for_signal(self, signal, "true", "false", "true")
self.expect(
"process continue",
substrs=[
@@ -178,7 +173,7 @@
# Make sure we do not stop at the signal, and we do not get the notification. Process
# should receive the signal.
- self.set_handle(signal, "true", "false", "false")
+ lldbutil.set_actions_for_signal(self, signal, "true", "false", "false")
self.expect(
"process continue",
substrs=["stopped and restarted"],
@@ -187,4 +182,4 @@
self.assertEqual(process.GetExitStatus(), signo)
# reset signal handling to default
- self.set_handle(signal, default_pass, default_stop, default_notify)
+ lldbutil.set_actions_for_signal(self, signal, self.default_pass, self.default_stop, self.default_notify)
Index: lldb/test/API/commands/process/handle/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/commands/process/handle/main.cpp
@@ -0,0 +1,3 @@
+int main() {
+ return 0; // break here
+}
Index: lldb/test/API/commands/process/handle/TestProcessHandle.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/process/handle/TestProcessHandle.py
@@ -0,0 +1,136 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
+
+class TestProcessHandle(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @no_debug_info_test
+ @skipIfWindows
+ def test_process_handle(self):
+ """Test that calling process handle before we have a target, and before we
+ have a process will affect the process. Also that the signal settings
+ are preserved on rerun."""
+ self.build()
+
+ # Make sure we don't accept signal values by signo with no process - we don't know what the
+ # mapping will be so we can't do the right thing with bare numbers:
+ lldbutil.set_actions_for_signal(self, "9", "true", None, None, expect_success=False)
+
+ # First, I need a reference value so I can see whether changes actually took:
+ (target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', lldb.SBFileSpec("main.cpp"))
+ (default_pass, default_stop, default_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV")
+
+ # Let's change the value here, then exit and make sure the changed value sticks:
+ new_value = "false"
+ if default_pass == "true":
+ new_value = "false"
+
+ # First make sure we get an error for bogus values when running:
+ lldbutil.set_actions_for_signal(self, "NOTSIGSEGV", new_value, None, None, expect_success=False)
+
+ # Then set the one we intend to change.
+ lldbutil.set_actions_for_signal(self, "SIGSEGV", new_value, None, None)
+
+ process.Continue()
+
+ self.assertEqual(process.GetState(), lldb.eStateExited)
+ self.assertEqual(process.GetExitStatus(), 0)
+
+ # Check that we preserved the setting:
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV",from_target=True)
+ self.assertEqual(curr_pass, new_value, "Pass was set correctly")
+ self.assertEqual(curr_stop, "not set", "Stop was not set by us")
+ self.assertEqual(curr_notify, "not set", "Notify was not set by us")
+
+ # Run again and make sure that we prime the new process with these settings:
+ process = lldbutil.run_to_breakpoint_do_run(self, target, bkpt)
+
+ # We check the process settings now, to see what got copied into the process:
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV")
+ self.assertEqual(curr_pass, new_value, "Pass was set correctly")
+ self.assertEqual(curr_stop, default_stop, "Stop was its default value")
+ self.assertEqual(curr_notify, default_notify, "Notify was its default value")
+
+ # Now kill this target, set the handling and make sure the values get copied from the dummy into the new target.
+ success = self.dbg.DeleteTarget(target)
+ self.assertTrue(success, "Deleted the target")
+ self.assertEqual(self.dbg.GetNumTargets(), 0, "We did delete all the targets.")
+
+ # The signal settings should be back at their default - we were only setting this on the target:
+ lldbutil.get_actions_for_signal(self, "SIGSEGV", from_target=True, expected_absent=True)
+ # Set a valid one:
+ lldbutil.set_actions_for_signal(self, "SIGSEGV", new_value, None, None)
+ # Set a bogus one - we don't have a way to check pre-run so this is allowed
+ # but we should get an error message when launching:
+ lldbutil.set_actions_for_signal(self, "SIGNOTSIG", new_value, None, None)
+
+ out_filename = self.getBuildArtifact('output')
+ success = True
+ try:
+ f = open(out_filename, 'w')
+ except:
+ success = False
+
+ if not success:
+ self.fail("Couldn't open error output file for writing.")
+
+ self.dbg.SetErrorFileHandle(f, False)
+ # Now make a new process and make sure the right values got copied into the new target
+ (target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', lldb.SBFileSpec("main.cpp"))
+ f.write("TESTPATTERN\n")
+ f.flush()
+ f.close()
+
+ try:
+ f = open(out_filename, 'r')
+ except:
+ success = False
+
+ if not success:
+ self.fail("Couldn't open error output file for reading")
+ errors = f.read()
+ f.close()
+
+ self.assertIn("SIGNOTSIG", errors, "We warned about the unset signal")
+ # Also make sure we didn't accidentally add this bogus setting to the process.
+ lldbutil.set_actions_for_signal(self, "SIGNOTSIG", "true", "true", "true", expect_success=False)
+
+ # Check that they went into the target:
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV",from_target=True)
+ self.assertEqual(curr_pass, new_value, "Pass was set correctly")
+ self.assertEqual(curr_stop, "not set", "Stop was not set by us")
+ self.assertEqual(curr_notify, "not set", "Notify was not set by us")
+
+ # And the process:
+ # Check that they went into the target:
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV")
+ self.assertEqual(curr_pass, new_value, "Pass was set correctly")
+ self.assertEqual(curr_stop, default_stop, "Stop was its default value")
+ self.assertEqual(curr_notify, default_notify, "Notify was its default value")
+
+ # Now clear the handling, and make sure that we get the right signal values again:
+ self.runCmd("process handle -c SIGSEGV")
+ # Check that there is no longer configuration for SIGSEGV in the target:
+ lldbutil.get_actions_for_signal(self, "SIGSEGV",from_target=True, expected_absent=True)
+ # Make a new process, to make sure we did indeed reset the values:
+ (target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', lldb.SBFileSpec("main.cpp"))
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV")
+ self.assertEqual(curr_pass, new_value, "Pass was set correctly")
+ self.assertEqual(curr_stop, default_stop, "Stop was its default value")
+ self.assertEqual(curr_notify, default_notify, "Notify was its default value")
+
+ # Finally remove this from the dummy target as well, and make sure it was cleared from there:
+ self.runCmd("process handle -c -d SIGSEGV")
+ error = process.Kill()
+ self.assertSuccess(error, "Killed the process")
+ success = self.dbg.DeleteTarget(target)
+ self.assertTrue(success, "Destroyed the target.")
+
+ (target, process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', lldb.SBFileSpec("main.cpp"))
+ (curr_pass, curr_stop, curr_notify) = lldbutil.get_actions_for_signal(self, "SIGSEGV")
+ self.assertEqual(curr_pass, default_pass, "Pass was set correctly")
+ self.assertEqual(curr_stop, default_stop, "Stop was its default value")
+ self.assertEqual(curr_notify, default_notify, "Notify was its default value")
Index: lldb/test/API/commands/process/handle/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/commands/process/handle/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Target/UnixSignals.cpp
===================================================================
--- lldb/source/Target/UnixSignals.cpp
+++ lldb/source/Target/UnixSignals.cpp
@@ -22,7 +22,9 @@
const char *description, const char *alias)
: m_name(name), m_alias(alias), m_description(),
m_suppress(default_suppress), m_stop(default_stop),
- m_notify(default_notify) {
+ m_notify(default_notify),
+ m_default_suppress(default_suppress), m_default_stop(default_stop),
+ m_default_notify(default_notify) {
if (description)
m_description.assign(description);
}
@@ -330,3 +332,23 @@
}
return std::move(json_signals);
}
+
+void UnixSignals::Signal::Reset(bool reset_stop, bool reset_notify,
+ bool reset_suppress) {
+ if (reset_stop)
+ m_stop = m_default_stop;
+ if (reset_notify)
+ m_notify = m_default_notify;
+ if (reset_suppress)
+ m_suppress = m_default_suppress;
+}
+
+bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop,
+ bool reset_notify, bool reset_suppress) {
+ auto elem = m_signals.find(signo);
+ if (elem == m_signals.end())
+ return false;
+ (*elem).second.Reset(reset_stop, reset_notify, reset_suppress);
+ return true;
+}
+
Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -51,6 +51,7 @@
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
@@ -106,7 +107,7 @@
SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded");
SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed");
SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded");
-
+
CheckInWithManager();
LLDB_LOG(GetLog(LLDBLog::Object), "{0} Target::Target()",
@@ -147,6 +148,8 @@
m_frame_recognizer_manager_up = std::make_unique<StackFrameRecognizerManager>(
*target.m_frame_recognizer_manager_up);
+
+ m_dummy_signals = target.m_dummy_signals;
}
void Target::Dump(Stream *s, lldb::DescriptionLevel description_level) {
@@ -287,6 +290,8 @@
m_stop_hooks.clear();
m_stop_hook_next_id = 0;
m_suppress_stop_hooks = false;
+ Args signal_args;
+ ClearDummySignals(signal_args);
}
llvm::StringRef Target::GetABIName() const {
@@ -3349,6 +3354,129 @@
}
}
+void Target::AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool notify,
+ LazyBool stop) {
+ if (name.empty())
+ return;
+ // Don't add a signal if all the actions are trivial:
+ if (pass == eLazyBoolCalculate && notify == eLazyBoolCalculate
+ && stop == eLazyBoolCalculate)
+ return;
+
+ auto& elem = m_dummy_signals[name];
+ elem.pass = pass;
+ elem.notify = notify;
+ elem.stop = stop;
+}
+
+bool Target::UpdateSignalFromDummy(UnixSignalsSP signals_sp,
+ const DummySignalElement &elem) {
+ if (!signals_sp)
+ return false;
+
+ int32_t signo
+ = signals_sp->GetSignalNumberFromName(elem.first().str().c_str());
+ if (signo == LLDB_INVALID_SIGNAL_NUMBER)
+ return false;
+
+ if (elem.second.pass == eLazyBoolYes)
+ signals_sp->SetShouldSuppress(signo, false);
+ else if (elem.second.pass == eLazyBoolNo)
+ signals_sp->SetShouldSuppress(signo, true);
+
+ if (elem.second.notify == eLazyBoolYes)
+ signals_sp->SetShouldNotify(signo, true);
+ else if (elem.second.notify == eLazyBoolNo)
+ signals_sp->SetShouldNotify(signo, false);
+
+ if (elem.second.stop == eLazyBoolYes)
+ signals_sp->SetShouldStop(signo, true);
+ else if (elem.second.stop == eLazyBoolNo)
+ signals_sp->SetShouldStop(signo, false);
+ return true;
+}
+
+bool Target::ResetSignalFromDummy(UnixSignalsSP signals_sp,
+ const DummySignalElement &elem) {
+ if (!signals_sp)
+ return false;
+ int32_t signo
+ = signals_sp->GetSignalNumberFromName(elem.first().str().c_str());
+ if (signo == LLDB_INVALID_SIGNAL_NUMBER)
+ return false;
+ bool do_pass = elem.second.pass != eLazyBoolCalculate;
+ bool do_stop = elem.second.stop != eLazyBoolCalculate;
+ bool do_notify = elem.second.notify != eLazyBoolCalculate;
+ signals_sp->ResetSignal(signo, do_stop, do_notify, do_pass);
+ return true;
+}
+
+void Target::UpdateSignalsFromDummy(UnixSignalsSP signals_sp,
+ StreamSP warning_stream_sp) {
+ if (!signals_sp)
+ return;
+
+ for (const auto &elem : m_dummy_signals) {
+ if (!UpdateSignalFromDummy(signals_sp, elem))
+ warning_stream_sp->Printf("Target signal '%s' not found in process\n",
+ elem.first().str().c_str());
+ }
+}
+
+void Target::ClearDummySignals(Args &signal_names) {
+ ProcessSP process_sp = GetProcessSP();
+ // The simplest case, delete them all with no process to update.
+ if (signal_names.GetArgumentCount() == 0 && !process_sp) {
+ m_dummy_signals.clear();
+ return;
+ }
+ UnixSignalsSP signals_sp;
+ if (process_sp)
+ signals_sp = process_sp->GetUnixSignals();
+
+ for (const Args::ArgEntry &entry : signal_names) {
+ const char *signal_name = entry.c_str();
+ auto elem = m_dummy_signals.find(signal_name);
+ // If we didn't find it go on.
+ // FIXME: Should I pipe error handling through here?
+ if (elem == m_dummy_signals.end()) {
+ continue;
+ }
+ if (signals_sp)
+ ResetSignalFromDummy(signals_sp, *elem);
+ m_dummy_signals.erase(elem);
+ }
+}
+
+void Target::PrintDummySignals(Stream &strm, Args &signal_args) {
+ strm.Printf("NAME PASS STOP NOTIFY\n");
+ strm.Printf("=========== ======= ======= =======\n");
+
+ auto str_for_lazy = [] (LazyBool lazy) -> const char * {
+ switch (lazy) {
+ case eLazyBoolCalculate: return "not set";
+ case eLazyBoolYes: return "true ";
+ case eLazyBoolNo: return "false ";
+ }
+ };
+ size_t num_args = signal_args.GetArgumentCount();
+ for (const auto &elem : m_dummy_signals) {
+ bool print_it = false;
+ for (size_t idx = 0; idx < num_args; idx++) {
+ if (elem.first() == signal_args.GetArgumentAtIndex(idx)) {
+ print_it = true;
+ break;
+ }
+ }
+ if (print_it) {
+ strm.Printf("%-11s ", elem.first().str().c_str());
+ strm.Printf("%s %s %s\n", str_for_lazy(elem.second.pass),
+ str_for_lazy(elem.second.stop),
+ str_for_lazy(elem.second.notify));
+ }
+ }
+}
+
// Target::StopHook
Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid)
: UserID(uid), m_target_sp(target_sp), m_specifier_sp(),
Index: lldb/source/Target/Process.cpp
===================================================================
--- lldb/source/Target/Process.cpp
+++ lldb/source/Target/Process.cpp
@@ -2557,6 +2557,13 @@
if (state == eStateStopped || state == eStateCrashed) {
DidLaunch();
+
+ // Now that we know the process type, update its signal responses from the
+ // ones stored in the Target:
+ if (m_unix_signals_sp) {
+ StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
+ GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm);
+ }
DynamicLoader *dyld = GetDynamicLoader();
if (dyld)
@@ -2919,6 +2926,12 @@
}
}
}
+ // Now that we know the process type, update its signal responses from the
+ // ones stored in the Target:
+ if (m_unix_signals_sp) {
+ StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
+ GetTarget().UpdateSignalsFromDummy(m_unix_signals_sp, warning_strm);
+ }
// We have completed the attach, now it is time to find the dynamic loader
// plug-in
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -738,6 +738,8 @@
}
let Command = "process handle" in {
+ def process_handle_clear : Option<"clear", "c">, Group<2>,
+ Desc<"Removes the signals listed from the Target signal handlers">;
def process_handle_stop : Option<"stop", "s">, Group<1>, Arg<"Boolean">,
Desc<"Whether or not the process should be stopped if the signal is "
"received.">;
@@ -746,6 +748,10 @@
"received.">;
def process_handle_pass : Option<"pass", "p">, Group<1>, Arg<"Boolean">,
Desc<"Whether or not the signal should be passed to the process.">;
+ def process_handle_only_target : Option<"target", "t">, Group<1>,
+ Desc<"Show only the signals with behaviors modified in this target">;
+ def process_handle_dummy : Option<"dummy", "d">, Group<2>,
+ Desc<"Also clear the values in the dummy target so they won't be inherited by new targets.">;
}
let Command = "process status" in {
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -1432,6 +1432,12 @@
const int short_option = m_getopt_table[option_idx].val;
switch (short_option) {
+ case 'c':
+ do_clear = true;
+ break;
+ case 'd':
+ dummy = true;
+ break;
case 's':
stop = std::string(option_arg);
break;
@@ -1441,6 +1447,9 @@
case 'p':
pass = std::string(option_arg);
break;
+ case 't':
+ only_target_values = true;
+ break;
default:
llvm_unreachable("Unimplemented option");
}
@@ -1451,6 +1460,9 @@
stop.clear();
notify.clear();
pass.clear();
+ only_target_values = false;
+ do_clear = false;
+ dummy = false;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -1462,6 +1474,9 @@
std::string stop;
std::string notify;
std::string pass;
+ bool only_target_values = false;
+ bool do_clear = false;
+ bool dummy = false;
};
CommandObjectProcessHandle(CommandInterpreter &interpreter)
@@ -1469,9 +1484,19 @@
"Manage LLDB handling of OS signals for the "
"current target process. Defaults to showing "
"current policy.",
- nullptr, eCommandRequiresTarget) {
- SetHelpLong("\nIf no signals are specified, update them all. If no update "
- "option is specified, list the current values.");
+ nullptr) {
+ SetHelpLong("\nIf no signals are specified but one or more actions are, "
+ "and there is a live process, update them all. If no action "
+ "is specified, list the current values.\n"
+ "If you specify actions with no target (e.g. in an init file) "
+ "or in a target with no process "
+ "the values will get copied into subsequent targets, but "
+ "lldb won't be able to spell-check the options since it can't "
+ "know which signal set will later be in force."
+ "\nYou can see the signal modifications held by the target"
+ "by passing the -t option."
+ "\nYou can also clear the target modification for a signal"
+ "by passing the -c option");
CommandArgumentEntry arg;
CommandArgumentData signal_arg;
@@ -1554,15 +1579,13 @@
protected:
bool DoExecute(Args &signal_args, CommandReturnObject &result) override {
- Target *target_sp = &GetSelectedTarget();
+ Target &target = GetSelectedOrDummyTarget();
- ProcessSP process_sp = target_sp->GetProcessSP();
-
- if (!process_sp) {
- result.AppendError("No current process; cannot handle signals until you "
- "have a valid process.\n");
- return false;
- }
+ // Any signals that are being set should be added to the Target's
+ // DummySignals so they will get applied on rerun, etc.
+ // If we have a process, however, we can do a more accurate job of vetting
+ // the user's options.
+ ProcessSP process_sp = target.GetProcessSP();
int stop_action = -1; // -1 means leave the current setting alone
int pass_action = -1; // -1 means leave the current setting alone
@@ -1588,35 +1611,99 @@
"true or false.\n");
return false;
}
+
+ bool no_actions = (stop_action == -1 && pass_action == -1
+ && notify_action == -1);
+ if (m_options.only_target_values && !no_actions) {
+ result.AppendError("-t is for reporting, not setting, target values.");
+ return false;
+ }
size_t num_args = signal_args.GetArgumentCount();
- UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
+ UnixSignalsSP signals_sp;
+ if (process_sp)
+ signals_sp = process_sp->GetUnixSignals();
+
int num_signals_set = 0;
+ // If we were just asked to print the target values, do that here and
+ // return:
+ if (m_options.only_target_values) {
+ target.PrintDummySignals(result.GetOutputStream(), signal_args);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ // This handles clearing values:
+ if (m_options.do_clear) {
+ target.ClearDummySignals(signal_args);
+ if (m_options.dummy)
+ GetDummyTarget().ClearDummySignals(signal_args);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ // This rest handles setting values:
if (num_args > 0) {
for (const auto &arg : signal_args) {
- int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str());
- if (signo != LLDB_INVALID_SIGNAL_NUMBER) {
- // Casting the actions as bools here should be okay, because
- // VerifyCommandOptionValue guarantees the value is either 0 or 1.
- if (stop_action != -1)
- signals_sp->SetShouldStop(signo, stop_action);
- if (pass_action != -1) {
- bool suppress = !pass_action;
- signals_sp->SetShouldSuppress(signo, suppress);
+ // Do the process first. If we have a process we can catch
+ // invalid signal names, which we do here.
+ if (signals_sp) {
+ int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str());
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER) {
+ // Casting the actions as bools here should be okay, because
+ // VerifyCommandOptionValue guarantees the value is either 0 or 1.
+ if (stop_action != -1)
+ signals_sp->SetShouldStop(signo, stop_action);
+ if (pass_action != -1) {
+ bool suppress = !pass_action;
+ signals_sp->SetShouldSuppress(signo, suppress);
+ }
+ if (notify_action != -1)
+ signals_sp->SetShouldNotify(signo, notify_action);
+ ++num_signals_set;
+ } else {
+ result.AppendErrorWithFormat("Invalid signal name '%s'\n",
+ arg.c_str());
+ continue;
}
- if (notify_action != -1)
- signals_sp->SetShouldNotify(signo, notify_action);
- ++num_signals_set;
} else {
- result.AppendErrorWithFormat("Invalid signal name '%s'\n",
- arg.c_str());
+ // If there's no process we can't check, so we just set them all.
+ // But since the map signal name -> signal number across all platforms
+ // is not 1-1, we can't sensibly set signal actions by number before
+ // we have a process. Check that here:
+ int32_t signo;
+ if (llvm::to_integer(arg.c_str(), signo)) {
+ result.AppendErrorWithFormat("Can't set signal handling by signal "
+ "number with no process");
+ return false;
+ }
+ num_signals_set = num_args;
}
+ auto set_lazy_bool = [] (int action) -> LazyBool {
+ LazyBool lazy;
+ if (action == -1)
+ lazy = eLazyBoolCalculate;
+ else if (action)
+ lazy = eLazyBoolYes;
+ else
+ lazy = eLazyBoolNo;
+ return lazy;
+ };
+
+ // If there were no actions, we're just listing, don't add the dummy:
+ if (!no_actions)
+ target.AddDummySignal(arg.ref(),
+ set_lazy_bool(pass_action),
+ set_lazy_bool(notify_action),
+ set_lazy_bool(stop_action));
}
} else {
// No signal specified, if any command options were specified, update ALL
- // signals.
- if ((notify_action != -1) || (stop_action != -1) || (pass_action != -1)) {
+ // signals. But we can't do this without a process since we don't know
+ // all the possible signals that might be valid for this target.
+ if (((notify_action != -1) || (stop_action != -1) || (pass_action != -1))
+ && process_sp) {
if (m_interpreter.Confirm(
"Do you really want to update all the signals?", false)) {
int32_t signo = signals_sp->GetFirstSignalNumber();
@@ -1635,11 +1722,15 @@
}
}
- PrintSignalInformation(result.GetOutputStream(), signal_args,
- num_signals_set, signals_sp);
+ if (signals_sp)
+ PrintSignalInformation(result.GetOutputStream(), signal_args,
+ num_signals_set, signals_sp);
+ else
+ target.PrintDummySignals(result.GetOutputStream(),
+ signal_args);
if (num_signals_set > 0)
- result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
else
result.SetStatus(eReturnStatusFailed);
Index: lldb/packages/Python/lldbsuite/test/lldbutil.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/lldbutil.py
+++ lldb/packages/Python/lldbsuite/test/lldbutil.py
@@ -1527,6 +1527,42 @@
# No remote platform; fall back to using local python signals.
return getattr(signal, signal_name)
+def get_actions_for_signal(testcase, signal_name, from_target=False, expected_absent=False):
+ """Returns a triple of (pass, stop, notify)"""
+ return_obj = lldb.SBCommandReturnObject()
+ command = "process handle {0}".format(signal_name)
+ if from_target:
+ command += " -t"
+ testcase.dbg.GetCommandInterpreter().HandleCommand(
+ command, return_obj)
+ match = re.match(
+ 'NAME *PASS *STOP *NOTIFY.*(false|true|not set) *(false|true|not set) *(false|true|not set)',
+ return_obj.GetOutput(),
+ re.IGNORECASE | re.DOTALL)
+ if match and expected_absent:
+ testcase.fail('Signal "{0}" was supposed to be absent'.format(signal_name))
+ if not match:
+ if expected_absent:
+ return (None, None, None)
+ testcase.fail('Unable to retrieve default signal disposition.')
+ return (match.group(1), match.group(2), match.group(3))
+
+
+
+def set_actions_for_signal(testcase, signal_name, pass_action, stop_action, notify_action, expect_success=True):
+ return_obj = lldb.SBCommandReturnObject()
+ command = "process handle {0}".format(signal_name)
+ if pass_action != None:
+ command += " -p {0}".format(pass_action)
+ if stop_action != None:
+ command += " -s {0}".format(stop_action)
+ if notify_action != None:
+ command +=" -n {0}".format(notify_action)
+
+ testcase.dbg.GetCommandInterpreter().HandleCommand(command, return_obj)
+ testcase.assertEqual(expect_success,
+ return_obj.Succeeded(),
+ "Setting signal handling for {0} worked as expected".format(signal_name))
class PrintableRegex(object):
Index: lldb/include/lldb/Target/UnixSignals.h
===================================================================
--- lldb/include/lldb/Target/UnixSignals.h
+++ lldb/include/lldb/Target/UnixSignals.h
@@ -55,6 +55,9 @@
bool SetShouldNotify(int32_t signo, bool value);
bool SetShouldNotify(const char *signal_name, bool value);
+
+ bool ResetSignal(int32_t signo, bool reset_stop = true,
+ bool reset_notify = true, bool reset_suppress = true);
// These provide an iterator through the signals available on this system.
// Call GetFirstSignalNumber to get the first entry, then iterate on
@@ -114,11 +117,13 @@
std::string m_description;
uint32_t m_hit_count = 0;
bool m_suppress : 1, m_stop : 1, m_notify : 1;
+ bool m_default_suppress : 1, m_default_stop : 1, m_default_notify : 1;
Signal(const char *name, bool default_suppress, bool default_stop,
bool default_notify, const char *description, const char *alias);
~Signal() = default;
+ void Reset(bool reset_stop, bool reset_notify, bool reset_suppress);
};
virtual void Reset();
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -1414,6 +1414,42 @@
return *m_frame_recognizer_manager_up;
}
+ /// Add a signal for the target. This will get copied over to the process
+ /// if the signal exists on that target. Only the values with Yes and No are
+ /// set, Calculate values will be ignored.
+protected:
+ struct DummySignalValues {
+ LazyBool pass = eLazyBoolCalculate;
+ LazyBool notify = eLazyBoolCalculate;
+ LazyBool stop = eLazyBoolCalculate;
+ DummySignalValues(LazyBool pass, LazyBool notify, LazyBool stop) :
+ pass(pass), notify(notify), stop(stop) {}
+ DummySignalValues() = default;
+ };
+ using DummySignalElement = llvm::StringMapEntry<DummySignalValues>;
+ static bool UpdateSignalFromDummy(lldb::UnixSignalsSP signals_sp,
+ const DummySignalElement &element);
+ static bool ResetSignalFromDummy(lldb::UnixSignalsSP signals_sp,
+ const DummySignalElement &element);
+
+public:
+ /// Add a signal to the Target's list of stored signals/actions. These
+ /// values will get copied into any processes launched from
+ /// this target.
+ void AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool print,
+ LazyBool stop);
+ /// Updates the signals in signals_sp using the stored dummy signals.
+ /// If warning_stream_sp is not null, if any stored signals are not found in
+ /// the current process, a warning will be emitted here.
+ void UpdateSignalsFromDummy(lldb::UnixSignalsSP signals_sp,
+ lldb::StreamSP warning_stream_sp);
+ /// Clear the dummy signals in signal_names from the target, or all signals
+ /// if signal_names is empty. Also remove the behaviors they set from the
+ /// process's signals if it exists.
+ void ClearDummySignals(Args &signal_names);
+ /// Print all the signals set in this target.
+ void PrintDummySignals(Stream &strm, Args &signals);
+
protected:
/// Implementing of ModuleList::Notifier.
@@ -1443,6 +1479,7 @@
ArchSpec m_spec;
std::unique_ptr<Architecture> m_plugin_up;
};
+
// Member variables.
Debugger &m_debugger;
lldb::PlatformSP m_platform_sp; ///< The platform for this target.
@@ -1493,6 +1530,10 @@
lldb::TraceSP m_trace_sp;
/// Stores the frame recognizers of this target.
lldb::StackFrameRecognizerManagerUP m_frame_recognizer_manager_up;
+ /// These are used to set the signal state when you don't have a process and
+ /// more usefully in the Dummy target where you can't know exactly what
+ /// signals you will have.
+ llvm::StringMap<DummySignalValues> m_dummy_signals;
static void ImageSearchPathsChanged(const PathMappingList &path_list,
void *baton);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits