diff --git a/lldb/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py b/lldb/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py --- a/lldb/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py +++ b/lldb/packages/Python/lldbsuite/test/commands/watchpoints/watchpoint_commands/TestWatchpointCommands.py @@ -155,6 +155,56 @@ self.expect("process status", substrs=['exited']) + # Read-write watchpoints not supported on SystemZ + @expectedFailureAll(archs=['s390x']) + def test_rw_watchpoint_delete(self): + """Test delete watchpoint and expect not to stop for watchpoint.""" + self.build(dictionary=self.d) + self.setTearDownCleanup(dictionary=self.d) + + exe = self.getBuildArtifact(self.exe_name) + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Add a breakpoint to set a watchpoint when stopped on the breakpoint. + lldbutil.run_break_set_by_file_and_line( + self, None, self.line, num_expected_locations=1) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + # We should be stopped again due to the breakpoint. + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs=['stopped', + 'stop reason = breakpoint']) + + # Now let's set a read_write-type watchpoint for 'global'. + # There should be two watchpoint hits (see main.c). + self.expect( + "watchpoint set variable -w read_write global", + WATCHPOINT_CREATED, + substrs=[ + 'Watchpoint created', + 'size = 4', + 'type = rw', + '%s:%d' % + (self.source, + self.decl)]) + + # Delete the watchpoint immediately using the force option. + self.expect("watchpoint delete --force", + substrs=['All watchpoints removed.']) + + # Use the '-v' option to do verbose listing of the watchpoint. + self.runCmd("watchpoint list -v") + + self.runCmd("process continue") + + # There should be no more watchpoint hit and the process status should + # be 'exited'. + self.expect("process status", + substrs=['exited']) + # Read-write watchpoints not supported on SystemZ @expectedFailureAll(archs=['s390x']) def test_rw_watchpoint_set_ignore_count(self): diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -414,6 +414,10 @@ } }; +// CommandObjectWatchpointDelete +#define LLDB_OPTIONS_watchpoint_delete +#include "CommandOptions.inc" + // CommandObjectWatchpointDelete #pragma mark Delete @@ -423,7 +427,8 @@ : CommandObjectParsed(interpreter, "watchpoint delete", "Delete the specified watchpoint(s). If no " "watchpoints are specified, delete them all.", - nullptr, eCommandRequiresTarget) { + nullptr, eCommandRequiresTarget), + m_options() { CommandArgumentEntry arg; CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); @@ -434,6 +439,42 @@ ~CommandObjectWatchpointDelete() override = default; + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options(), m_force(false) {} + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + m_force = true; + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_force = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_watchpoint_delete_options); + } + + // Instance variables to hold the values for command options. + bool m_force; + }; + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -453,8 +494,9 @@ return false; } - if (command.GetArgumentCount() == 0) { - if (!m_interpreter.Confirm( + if (command.empty()) { + if (!m_options.m_force && + !m_interpreter.Confirm( "About to delete all watchpoints, do you want to do that?", true)) { result.AppendMessage("Operation cancelled..."); @@ -486,6 +528,9 @@ return result.Succeeded(); } + +private: + CommandOptions m_options; }; // CommandObjectWatchpointIgnore diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1126,3 +1126,8 @@ "to run as command for this watchpoint. Be sure to give a module name if " "appropriate.">; } + +let Command = "watchpoint delete" in { + def watchpoint_delete_force : Option<"force", "f">, Group<1>, + Desc<"Delete all watchpoints without querying for confirmation.">; +}