[PowerPC] Collect some CallLowering arguments into a struct. [NFC]
[llvm-project.git] / lldb / source / Commands / CommandObjectWatchpointCommand.cpp
blob1b83e885d27ed06e3edc6f944656f9b92f3b5b1d
1 //===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include <vector>
11 #include "CommandObjectWatchpoint.h"
12 #include "CommandObjectWatchpointCommand.h"
13 #include "lldb/Breakpoint/StoppointCallbackContext.h"
14 #include "lldb/Breakpoint/Watchpoint.h"
15 #include "lldb/Core/IOHandler.h"
16 #include "lldb/Host/OptionParser.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Interpreter/OptionArgParser.h"
20 #include "lldb/Target/Target.h"
22 using namespace lldb;
23 using namespace lldb_private;
25 // FIXME: "script-type" needs to have its contents determined dynamically, so
26 // somebody can add a new scripting language to lldb and have it pickable here
27 // without having to change this enumeration by hand and rebuild lldb proper.
28 static constexpr OptionEnumValueElement g_script_option_enumeration[] = {
30 eScriptLanguageNone,
31 "command",
32 "Commands are in the lldb command interpreter language",
35 eScriptLanguagePython,
36 "python",
37 "Commands are in the Python language.",
40 eScriptLanguageLua,
41 "lua",
42 "Commands are in the Python language.",
45 eSortOrderByName,
46 "default-script",
47 "Commands are in the default scripting language.",
51 static constexpr OptionEnumValues ScriptOptionEnum() {
52 return OptionEnumValues(g_script_option_enumeration);
55 #define LLDB_OPTIONS_watchpoint_command_add
56 #include "CommandOptions.inc"
58 class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
59 public IOHandlerDelegateMultiline {
60 public:
61 CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
62 : CommandObjectParsed(interpreter, "add",
63 "Add a set of LLDB commands to a watchpoint, to be "
64 "executed whenever the watchpoint is hit.",
65 nullptr, eCommandRequiresTarget),
66 IOHandlerDelegateMultiline("DONE",
67 IOHandlerDelegate::Completion::LLDBCommand),
68 m_options() {
69 SetHelpLong(
70 R"(
71 General information about entering watchpoint commands
72 ------------------------------------------------------
75 "This command will prompt for commands to be executed when the specified \
76 watchpoint is hit. Each command is typed on its own line following the '> ' \
77 prompt until 'DONE' is entered."
78 R"(
81 "Syntactic errors may not be detected when initially entered, and many \
82 malformed commands can silently fail when executed. If your watchpoint commands \
83 do not appear to be executing, double-check the command syntax."
84 R"(
87 "Note: You may enter any debugger command exactly as you would at the debugger \
88 prompt. There is no limit to the number of commands supplied, but do NOT enter \
89 more than one command per line."
90 R"(
92 Special information about PYTHON watchpoint commands
93 ----------------------------------------------------
96 "You may enter either one or more lines of Python, including function \
97 definitions or calls to functions that will have been imported by the time \
98 the code executes. Single line watchpoint commands will be interpreted 'as is' \
99 when the watchpoint is hit. Multiple lines of Python will be wrapped in a \
100 generated function, and a call to the function will be attached to the watchpoint."
103 This auto-generated function is passed in three arguments:
105 frame: an lldb.SBFrame object for the frame which hit the watchpoint.
107 wp: the watchpoint that was hit.
110 "When specifying a python function with the --python-function option, you need \
111 to supply the function name prepended by the module name:"
114 --python-function myutils.watchpoint_callback
116 The function itself must have the following prototype:
118 def watchpoint_callback(frame, wp):
119 # Your code goes here
122 "The arguments are the same as the arguments passed to generated functions as \
123 described above. Note that the global variable 'lldb.frame' will NOT be updated when \
124 this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
125 can get you to the thread via frame.GetThread(), the thread can get you to the \
126 process via thread.GetProcess(), and the process can get you back to the target \
127 via process.GetTarget()."
131 "Important Note: As Python code gets collected into functions, access to global \
132 variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
133 Python syntax, including indentation, when entering Python watchpoint commands."
136 Example Python one-line watchpoint command:
138 (lldb) watchpoint command add -s python 1
139 Enter your Python command(s). Type 'DONE' to end.
140 > print "Hit this watchpoint!"
141 > DONE
143 As a convenience, this also works for a short Python one-liner:
145 (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
146 (lldb) run
147 Launching '.../a.out' (x86_64)
148 (lldb) Fri Sep 10 12:17:45 2010
149 Process 21778 Stopped
150 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
152 37 int c(int val)
153 38 {
154 39 -> return val + 3;
155 40 }
157 42 int main (int argc, char const *argv[])
159 Example multiple line Python watchpoint command, using function definition:
161 (lldb) watchpoint command add -s python 1
162 Enter your Python command(s). Type 'DONE' to end.
163 > def watchpoint_output (wp_no):
164 > out_string = "Hit watchpoint number " + repr (wp_no)
165 > print out_string
166 > return True
167 > watchpoint_output (1)
168 > DONE
170 Example multiple line Python watchpoint command, using 'loose' Python:
172 (lldb) watchpoint command add -s p 1
173 Enter your Python command(s). Type 'DONE' to end.
174 > global wp_count
175 > wp_count = wp_count + 1
176 > print "Hit this watchpoint " + repr(wp_count) + " times!"
177 > DONE
180 "In this case, since there is a reference to a global variable, \
181 'wp_count', you will also need to make sure 'wp_count' exists and is \
182 initialized:"
185 (lldb) script
186 >>> wp_count = 0
187 >>> quit()
190 "Final Note: A warning that no watchpoint command was generated when there \
191 are no syntax errors may indicate that a function was declared but never called.");
193 CommandArgumentEntry arg;
194 CommandArgumentData wp_id_arg;
196 // Define the first (and only) variant of this arg.
197 wp_id_arg.arg_type = eArgTypeWatchpointID;
198 wp_id_arg.arg_repetition = eArgRepeatPlain;
200 // There is only one variant this argument could be; put it into the
201 // argument entry.
202 arg.push_back(wp_id_arg);
204 // Push the data for the first argument into the m_arguments vector.
205 m_arguments.push_back(arg);
208 ~CommandObjectWatchpointCommandAdd() override = default;
210 Options *GetOptions() override { return &m_options; }
212 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
213 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
214 if (output_sp && interactive) {
215 output_sp->PutCString(
216 "Enter your debugger command(s). Type 'DONE' to end.\n");
217 output_sp->Flush();
221 void IOHandlerInputComplete(IOHandler &io_handler,
222 std::string &line) override {
223 io_handler.SetIsDone(true);
225 // The WatchpointOptions object is owned by the watchpoint or watchpoint
226 // location
227 WatchpointOptions *wp_options =
228 (WatchpointOptions *)io_handler.GetUserData();
229 if (wp_options) {
230 std::unique_ptr<WatchpointOptions::CommandData> data_up(
231 new WatchpointOptions::CommandData());
232 if (data_up) {
233 data_up->user_source.SplitIntoLines(line);
234 auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>(
235 std::move(data_up));
236 wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
241 void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
242 CommandReturnObject &result) {
243 m_interpreter.GetLLDBCommandsFromIOHandler(
244 "> ", // Prompt
245 *this, // IOHandlerDelegate
246 wp_options); // Baton for the "io_handler" that will be passed back into
247 // our IOHandlerDelegate functions
250 /// Set a one-liner as the callback for the watchpoint.
251 void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
252 const char *oneliner) {
253 std::unique_ptr<WatchpointOptions::CommandData> data_up(
254 new WatchpointOptions::CommandData());
256 // It's necessary to set both user_source and script_source to the
257 // oneliner. The former is used to generate callback description (as in
258 // watchpoint command list) while the latter is used for Python to
259 // interpret during the actual callback.
260 data_up->user_source.AppendString(oneliner);
261 data_up->script_source.assign(oneliner);
262 data_up->stop_on_error = m_options.m_stop_on_error;
264 auto baton_sp =
265 std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up));
266 wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
269 static bool
270 WatchpointOptionsCallbackFunction(void *baton,
271 StoppointCallbackContext *context,
272 lldb::user_id_t watch_id) {
273 bool ret_value = true;
274 if (baton == nullptr)
275 return true;
277 WatchpointOptions::CommandData *data =
278 (WatchpointOptions::CommandData *)baton;
279 StringList &commands = data->user_source;
281 if (commands.GetSize() > 0) {
282 ExecutionContext exe_ctx(context->exe_ctx_ref);
283 Target *target = exe_ctx.GetTargetPtr();
284 if (target) {
285 CommandReturnObject result;
286 Debugger &debugger = target->GetDebugger();
287 // Rig up the results secondary output stream to the debugger's, so the
288 // output will come out synchronously if the debugger is set up that
289 // way.
291 StreamSP output_stream(debugger.GetAsyncOutputStream());
292 StreamSP error_stream(debugger.GetAsyncErrorStream());
293 result.SetImmediateOutputStream(output_stream);
294 result.SetImmediateErrorStream(error_stream);
296 CommandInterpreterRunOptions options;
297 options.SetStopOnContinue(true);
298 options.SetStopOnError(data->stop_on_error);
299 options.SetEchoCommands(false);
300 options.SetPrintResults(true);
301 options.SetPrintErrors(true);
302 options.SetAddToHistory(false);
304 debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
305 options, result);
306 result.GetImmediateOutputStream()->Flush();
307 result.GetImmediateErrorStream()->Flush();
310 return ret_value;
313 class CommandOptions : public Options {
314 public:
315 CommandOptions()
316 : Options(), m_use_commands(false), m_use_script_language(false),
317 m_script_language(eScriptLanguageNone), m_use_one_liner(false),
318 m_one_liner(), m_function_name() {}
320 ~CommandOptions() override = default;
322 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
323 ExecutionContext *execution_context) override {
324 Status error;
325 const int short_option = m_getopt_table[option_idx].val;
327 switch (short_option) {
328 case 'o':
329 m_use_one_liner = true;
330 m_one_liner = option_arg;
331 break;
333 case 's':
334 m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
335 option_arg, GetDefinitions()[option_idx].enum_values,
336 eScriptLanguageNone, error);
338 switch (m_script_language) {
339 case eScriptLanguagePython:
340 case eScriptLanguageLua:
341 m_use_script_language = true;
342 break;
343 case eScriptLanguageNone:
344 case eScriptLanguageUnknown:
345 m_use_script_language = false;
346 break;
348 break;
350 case 'e': {
351 bool success = false;
352 m_stop_on_error =
353 OptionArgParser::ToBoolean(option_arg, false, &success);
354 if (!success)
355 error.SetErrorStringWithFormat(
356 "invalid value for stop-on-error: \"%s\"",
357 option_arg.str().c_str());
358 } break;
360 case 'F':
361 m_use_one_liner = false;
362 m_function_name.assign(option_arg);
363 break;
365 default:
366 llvm_unreachable("Unimplemented option");
368 return error;
371 void OptionParsingStarting(ExecutionContext *execution_context) override {
372 m_use_commands = true;
373 m_use_script_language = false;
374 m_script_language = eScriptLanguageNone;
376 m_use_one_liner = false;
377 m_stop_on_error = true;
378 m_one_liner.clear();
379 m_function_name.clear();
382 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
383 return llvm::makeArrayRef(g_watchpoint_command_add_options);
386 // Instance variables to hold the values for command options.
388 bool m_use_commands;
389 bool m_use_script_language;
390 lldb::ScriptLanguage m_script_language;
392 // Instance variables to hold the values for one_liner options.
393 bool m_use_one_liner;
394 std::string m_one_liner;
395 bool m_stop_on_error;
396 std::string m_function_name;
399 protected:
400 bool DoExecute(Args &command, CommandReturnObject &result) override {
401 Target *target = &GetSelectedTarget();
403 const WatchpointList &watchpoints = target->GetWatchpointList();
404 size_t num_watchpoints = watchpoints.GetSize();
406 if (num_watchpoints == 0) {
407 result.AppendError("No watchpoints exist to have commands added");
408 result.SetStatus(eReturnStatusFailed);
409 return false;
412 if (!m_options.m_function_name.empty()) {
413 if (!m_options.m_use_script_language) {
414 m_options.m_script_language = GetDebugger().GetScriptLanguage();
415 m_options.m_use_script_language = true;
419 std::vector<uint32_t> valid_wp_ids;
420 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
421 valid_wp_ids)) {
422 result.AppendError("Invalid watchpoints specification.");
423 result.SetStatus(eReturnStatusFailed);
424 return false;
427 result.SetStatus(eReturnStatusSuccessFinishNoResult);
428 const size_t count = valid_wp_ids.size();
429 for (size_t i = 0; i < count; ++i) {
430 uint32_t cur_wp_id = valid_wp_ids.at(i);
431 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
432 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
433 // Sanity check wp first.
434 if (wp == nullptr)
435 continue;
437 WatchpointOptions *wp_options = wp->GetOptions();
438 // Skip this watchpoint if wp_options is not good.
439 if (wp_options == nullptr)
440 continue;
442 // If we are using script language, get the script interpreter in order
443 // to set or collect command callback. Otherwise, call the methods
444 // associated with this object.
445 if (m_options.m_use_script_language) {
446 ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter(
447 /*can_create=*/true, m_options.m_script_language);
448 // Special handling for one-liner specified inline.
449 if (m_options.m_use_one_liner) {
450 script_interp->SetWatchpointCommandCallback(
451 wp_options, m_options.m_one_liner.c_str());
453 // Special handling for using a Python function by name instead of
454 // extending the watchpoint callback data structures, we just
455 // automatize what the user would do manually: make their watchpoint
456 // command be a function call
457 else if (!m_options.m_function_name.empty()) {
458 std::string oneliner(m_options.m_function_name);
459 oneliner += "(frame, wp, internal_dict)";
460 script_interp->SetWatchpointCommandCallback(
461 wp_options, oneliner.c_str());
462 } else {
463 script_interp->CollectDataForWatchpointCommandCallback(wp_options,
464 result);
466 } else {
467 // Special handling for one-liner specified inline.
468 if (m_options.m_use_one_liner)
469 SetWatchpointCommandCallback(wp_options,
470 m_options.m_one_liner.c_str());
471 else
472 CollectDataForWatchpointCommandCallback(wp_options, result);
477 return result.Succeeded();
480 private:
481 CommandOptions m_options;
484 // CommandObjectWatchpointCommandDelete
486 class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
487 public:
488 CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
489 : CommandObjectParsed(interpreter, "delete",
490 "Delete the set of commands from a watchpoint.",
491 nullptr, eCommandRequiresTarget) {
492 CommandArgumentEntry arg;
493 CommandArgumentData wp_id_arg;
495 // Define the first (and only) variant of this arg.
496 wp_id_arg.arg_type = eArgTypeWatchpointID;
497 wp_id_arg.arg_repetition = eArgRepeatPlain;
499 // There is only one variant this argument could be; put it into the
500 // argument entry.
501 arg.push_back(wp_id_arg);
503 // Push the data for the first argument into the m_arguments vector.
504 m_arguments.push_back(arg);
507 ~CommandObjectWatchpointCommandDelete() override = default;
509 protected:
510 bool DoExecute(Args &command, CommandReturnObject &result) override {
511 Target *target = &GetSelectedTarget();
513 const WatchpointList &watchpoints = target->GetWatchpointList();
514 size_t num_watchpoints = watchpoints.GetSize();
516 if (num_watchpoints == 0) {
517 result.AppendError("No watchpoints exist to have commands deleted");
518 result.SetStatus(eReturnStatusFailed);
519 return false;
522 if (command.GetArgumentCount() == 0) {
523 result.AppendError(
524 "No watchpoint specified from which to delete the commands");
525 result.SetStatus(eReturnStatusFailed);
526 return false;
529 std::vector<uint32_t> valid_wp_ids;
530 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
531 valid_wp_ids)) {
532 result.AppendError("Invalid watchpoints specification.");
533 result.SetStatus(eReturnStatusFailed);
534 return false;
537 result.SetStatus(eReturnStatusSuccessFinishNoResult);
538 const size_t count = valid_wp_ids.size();
539 for (size_t i = 0; i < count; ++i) {
540 uint32_t cur_wp_id = valid_wp_ids.at(i);
541 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
542 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
543 if (wp)
544 wp->ClearCallback();
545 } else {
546 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
547 result.SetStatus(eReturnStatusFailed);
548 return false;
551 return result.Succeeded();
555 // CommandObjectWatchpointCommandList
557 class CommandObjectWatchpointCommandList : public CommandObjectParsed {
558 public:
559 CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
560 : CommandObjectParsed(interpreter, "list",
561 "List the script or set of commands to be executed "
562 "when the watchpoint is hit.",
563 nullptr, eCommandRequiresTarget) {
564 CommandArgumentEntry arg;
565 CommandArgumentData wp_id_arg;
567 // Define the first (and only) variant of this arg.
568 wp_id_arg.arg_type = eArgTypeWatchpointID;
569 wp_id_arg.arg_repetition = eArgRepeatPlain;
571 // There is only one variant this argument could be; put it into the
572 // argument entry.
573 arg.push_back(wp_id_arg);
575 // Push the data for the first argument into the m_arguments vector.
576 m_arguments.push_back(arg);
579 ~CommandObjectWatchpointCommandList() override = default;
581 protected:
582 bool DoExecute(Args &command, CommandReturnObject &result) override {
583 Target *target = &GetSelectedTarget();
585 const WatchpointList &watchpoints = target->GetWatchpointList();
586 size_t num_watchpoints = watchpoints.GetSize();
588 if (num_watchpoints == 0) {
589 result.AppendError("No watchpoints exist for which to list commands");
590 result.SetStatus(eReturnStatusFailed);
591 return false;
594 if (command.GetArgumentCount() == 0) {
595 result.AppendError(
596 "No watchpoint specified for which to list the commands");
597 result.SetStatus(eReturnStatusFailed);
598 return false;
601 std::vector<uint32_t> valid_wp_ids;
602 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
603 valid_wp_ids)) {
604 result.AppendError("Invalid watchpoints specification.");
605 result.SetStatus(eReturnStatusFailed);
606 return false;
609 result.SetStatus(eReturnStatusSuccessFinishNoResult);
610 const size_t count = valid_wp_ids.size();
611 for (size_t i = 0; i < count; ++i) {
612 uint32_t cur_wp_id = valid_wp_ids.at(i);
613 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
614 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
616 if (wp) {
617 const WatchpointOptions *wp_options = wp->GetOptions();
618 if (wp_options) {
619 // Get the callback baton associated with the current watchpoint.
620 const Baton *baton = wp_options->GetBaton();
621 if (baton) {
622 result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
623 baton->GetDescription(result.GetOutputStream().AsRawOstream(),
624 eDescriptionLevelFull,
625 result.GetOutputStream().GetIndentLevel() +
627 } else {
628 result.AppendMessageWithFormat(
629 "Watchpoint %u does not have an associated command.\n",
630 cur_wp_id);
633 result.SetStatus(eReturnStatusSuccessFinishResult);
634 } else {
635 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
636 cur_wp_id);
637 result.SetStatus(eReturnStatusFailed);
642 return result.Succeeded();
646 // CommandObjectWatchpointCommand
648 CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
649 CommandInterpreter &interpreter)
650 : CommandObjectMultiword(
651 interpreter, "command",
652 "Commands for adding, removing and examining LLDB commands "
653 "executed when the watchpoint is hit (watchpoint 'commands').",
654 "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
655 CommandObjectSP add_command_object(
656 new CommandObjectWatchpointCommandAdd(interpreter));
657 CommandObjectSP delete_command_object(
658 new CommandObjectWatchpointCommandDelete(interpreter));
659 CommandObjectSP list_command_object(
660 new CommandObjectWatchpointCommandList(interpreter));
662 add_command_object->SetCommandName("watchpoint command add");
663 delete_command_object->SetCommandName("watchpoint command delete");
664 list_command_object->SetCommandName("watchpoint command list");
666 LoadSubCommand("add", add_command_object);
667 LoadSubCommand("delete", delete_command_object);
668 LoadSubCommand("list", list_command_object);
671 CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;