1*dda28197Spatrick //===-- CommandObjectWatchpointCommand.cpp --------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include <vector> 10061da546Spatrick 11061da546Spatrick #include "CommandObjectWatchpoint.h" 12061da546Spatrick #include "CommandObjectWatchpointCommand.h" 13061da546Spatrick #include "lldb/Breakpoint/StoppointCallbackContext.h" 14061da546Spatrick #include "lldb/Breakpoint/Watchpoint.h" 15061da546Spatrick #include "lldb/Core/IOHandler.h" 16061da546Spatrick #include "lldb/Host/OptionParser.h" 17061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h" 18061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h" 19061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h" 20061da546Spatrick #include "lldb/Target/Target.h" 21061da546Spatrick 22061da546Spatrick using namespace lldb; 23061da546Spatrick using namespace lldb_private; 24061da546Spatrick 25061da546Spatrick // FIXME: "script-type" needs to have its contents determined dynamically, so 26061da546Spatrick // somebody can add a new scripting language to lldb and have it pickable here 27061da546Spatrick // without having to change this enumeration by hand and rebuild lldb proper. 28061da546Spatrick static constexpr OptionEnumValueElement g_script_option_enumeration[] = { 29061da546Spatrick { 30061da546Spatrick eScriptLanguageNone, 31061da546Spatrick "command", 32061da546Spatrick "Commands are in the lldb command interpreter language", 33061da546Spatrick }, 34061da546Spatrick { 35061da546Spatrick eScriptLanguagePython, 36061da546Spatrick "python", 37061da546Spatrick "Commands are in the Python language.", 38061da546Spatrick }, 39061da546Spatrick { 40061da546Spatrick eScriptLanguageLua, 41061da546Spatrick "lua", 42*dda28197Spatrick "Commands are in the Lua language.", 43061da546Spatrick }, 44061da546Spatrick { 45061da546Spatrick eSortOrderByName, 46061da546Spatrick "default-script", 47061da546Spatrick "Commands are in the default scripting language.", 48061da546Spatrick }, 49061da546Spatrick }; 50061da546Spatrick 51061da546Spatrick static constexpr OptionEnumValues ScriptOptionEnum() { 52061da546Spatrick return OptionEnumValues(g_script_option_enumeration); 53061da546Spatrick } 54061da546Spatrick 55061da546Spatrick #define LLDB_OPTIONS_watchpoint_command_add 56061da546Spatrick #include "CommandOptions.inc" 57061da546Spatrick 58061da546Spatrick class CommandObjectWatchpointCommandAdd : public CommandObjectParsed, 59061da546Spatrick public IOHandlerDelegateMultiline { 60061da546Spatrick public: 61061da546Spatrick CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter) 62061da546Spatrick : CommandObjectParsed(interpreter, "add", 63061da546Spatrick "Add a set of LLDB commands to a watchpoint, to be " 64061da546Spatrick "executed whenever the watchpoint is hit.", 65061da546Spatrick nullptr, eCommandRequiresTarget), 66061da546Spatrick IOHandlerDelegateMultiline("DONE", 67061da546Spatrick IOHandlerDelegate::Completion::LLDBCommand), 68061da546Spatrick m_options() { 69061da546Spatrick SetHelpLong( 70061da546Spatrick R"( 71061da546Spatrick General information about entering watchpoint commands 72061da546Spatrick ------------------------------------------------------ 73061da546Spatrick 74061da546Spatrick )" 75061da546Spatrick "This command will prompt for commands to be executed when the specified \ 76061da546Spatrick watchpoint is hit. Each command is typed on its own line following the '> ' \ 77061da546Spatrick prompt until 'DONE' is entered." 78061da546Spatrick R"( 79061da546Spatrick 80061da546Spatrick )" 81061da546Spatrick "Syntactic errors may not be detected when initially entered, and many \ 82061da546Spatrick malformed commands can silently fail when executed. If your watchpoint commands \ 83061da546Spatrick do not appear to be executing, double-check the command syntax." 84061da546Spatrick R"( 85061da546Spatrick 86061da546Spatrick )" 87061da546Spatrick "Note: You may enter any debugger command exactly as you would at the debugger \ 88061da546Spatrick prompt. There is no limit to the number of commands supplied, but do NOT enter \ 89061da546Spatrick more than one command per line." 90061da546Spatrick R"( 91061da546Spatrick 92061da546Spatrick Special information about PYTHON watchpoint commands 93061da546Spatrick ---------------------------------------------------- 94061da546Spatrick 95061da546Spatrick )" 96061da546Spatrick "You may enter either one or more lines of Python, including function \ 97061da546Spatrick definitions or calls to functions that will have been imported by the time \ 98061da546Spatrick the code executes. Single line watchpoint commands will be interpreted 'as is' \ 99061da546Spatrick when the watchpoint is hit. Multiple lines of Python will be wrapped in a \ 100061da546Spatrick generated function, and a call to the function will be attached to the watchpoint." 101061da546Spatrick R"( 102061da546Spatrick 103061da546Spatrick This auto-generated function is passed in three arguments: 104061da546Spatrick 105061da546Spatrick frame: an lldb.SBFrame object for the frame which hit the watchpoint. 106061da546Spatrick 107061da546Spatrick wp: the watchpoint that was hit. 108061da546Spatrick 109061da546Spatrick )" 110061da546Spatrick "When specifying a python function with the --python-function option, you need \ 111061da546Spatrick to supply the function name prepended by the module name:" 112061da546Spatrick R"( 113061da546Spatrick 114061da546Spatrick --python-function myutils.watchpoint_callback 115061da546Spatrick 116061da546Spatrick The function itself must have the following prototype: 117061da546Spatrick 118061da546Spatrick def watchpoint_callback(frame, wp): 119061da546Spatrick # Your code goes here 120061da546Spatrick 121061da546Spatrick )" 122061da546Spatrick "The arguments are the same as the arguments passed to generated functions as \ 123061da546Spatrick described above. Note that the global variable 'lldb.frame' will NOT be updated when \ 124061da546Spatrick this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ 125061da546Spatrick can get you to the thread via frame.GetThread(), the thread can get you to the \ 126061da546Spatrick process via thread.GetProcess(), and the process can get you back to the target \ 127061da546Spatrick via process.GetTarget()." 128061da546Spatrick R"( 129061da546Spatrick 130061da546Spatrick )" 131061da546Spatrick "Important Note: As Python code gets collected into functions, access to global \ 132061da546Spatrick variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ 133061da546Spatrick Python syntax, including indentation, when entering Python watchpoint commands." 134061da546Spatrick R"( 135061da546Spatrick 136061da546Spatrick Example Python one-line watchpoint command: 137061da546Spatrick 138061da546Spatrick (lldb) watchpoint command add -s python 1 139061da546Spatrick Enter your Python command(s). Type 'DONE' to end. 140061da546Spatrick > print "Hit this watchpoint!" 141061da546Spatrick > DONE 142061da546Spatrick 143061da546Spatrick As a convenience, this also works for a short Python one-liner: 144061da546Spatrick 145061da546Spatrick (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()' 146061da546Spatrick (lldb) run 147061da546Spatrick Launching '.../a.out' (x86_64) 148061da546Spatrick (lldb) Fri Sep 10 12:17:45 2010 149061da546Spatrick Process 21778 Stopped 150061da546Spatrick * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread 151061da546Spatrick 36 152061da546Spatrick 37 int c(int val) 153061da546Spatrick 38 { 154061da546Spatrick 39 -> return val + 3; 155061da546Spatrick 40 } 156061da546Spatrick 41 157061da546Spatrick 42 int main (int argc, char const *argv[]) 158061da546Spatrick 159061da546Spatrick Example multiple line Python watchpoint command, using function definition: 160061da546Spatrick 161061da546Spatrick (lldb) watchpoint command add -s python 1 162061da546Spatrick Enter your Python command(s). Type 'DONE' to end. 163061da546Spatrick > def watchpoint_output (wp_no): 164061da546Spatrick > out_string = "Hit watchpoint number " + repr (wp_no) 165061da546Spatrick > print out_string 166061da546Spatrick > return True 167061da546Spatrick > watchpoint_output (1) 168061da546Spatrick > DONE 169061da546Spatrick 170061da546Spatrick Example multiple line Python watchpoint command, using 'loose' Python: 171061da546Spatrick 172061da546Spatrick (lldb) watchpoint command add -s p 1 173061da546Spatrick Enter your Python command(s). Type 'DONE' to end. 174061da546Spatrick > global wp_count 175061da546Spatrick > wp_count = wp_count + 1 176061da546Spatrick > print "Hit this watchpoint " + repr(wp_count) + " times!" 177061da546Spatrick > DONE 178061da546Spatrick 179061da546Spatrick )" 180061da546Spatrick "In this case, since there is a reference to a global variable, \ 181061da546Spatrick 'wp_count', you will also need to make sure 'wp_count' exists and is \ 182061da546Spatrick initialized:" 183061da546Spatrick R"( 184061da546Spatrick 185061da546Spatrick (lldb) script 186061da546Spatrick >>> wp_count = 0 187061da546Spatrick >>> quit() 188061da546Spatrick 189061da546Spatrick )" 190061da546Spatrick "Final Note: A warning that no watchpoint command was generated when there \ 191061da546Spatrick are no syntax errors may indicate that a function was declared but never called."); 192061da546Spatrick 193061da546Spatrick CommandArgumentEntry arg; 194061da546Spatrick CommandArgumentData wp_id_arg; 195061da546Spatrick 196061da546Spatrick // Define the first (and only) variant of this arg. 197061da546Spatrick wp_id_arg.arg_type = eArgTypeWatchpointID; 198061da546Spatrick wp_id_arg.arg_repetition = eArgRepeatPlain; 199061da546Spatrick 200061da546Spatrick // There is only one variant this argument could be; put it into the 201061da546Spatrick // argument entry. 202061da546Spatrick arg.push_back(wp_id_arg); 203061da546Spatrick 204061da546Spatrick // Push the data for the first argument into the m_arguments vector. 205061da546Spatrick m_arguments.push_back(arg); 206061da546Spatrick } 207061da546Spatrick 208061da546Spatrick ~CommandObjectWatchpointCommandAdd() override = default; 209061da546Spatrick 210061da546Spatrick Options *GetOptions() override { return &m_options; } 211061da546Spatrick 212061da546Spatrick void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 213061da546Spatrick StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 214061da546Spatrick if (output_sp && interactive) { 215061da546Spatrick output_sp->PutCString( 216061da546Spatrick "Enter your debugger command(s). Type 'DONE' to end.\n"); 217061da546Spatrick output_sp->Flush(); 218061da546Spatrick } 219061da546Spatrick } 220061da546Spatrick 221061da546Spatrick void IOHandlerInputComplete(IOHandler &io_handler, 222061da546Spatrick std::string &line) override { 223061da546Spatrick io_handler.SetIsDone(true); 224061da546Spatrick 225061da546Spatrick // The WatchpointOptions object is owned by the watchpoint or watchpoint 226061da546Spatrick // location 227061da546Spatrick WatchpointOptions *wp_options = 228061da546Spatrick (WatchpointOptions *)io_handler.GetUserData(); 229061da546Spatrick if (wp_options) { 230061da546Spatrick std::unique_ptr<WatchpointOptions::CommandData> data_up( 231061da546Spatrick new WatchpointOptions::CommandData()); 232061da546Spatrick if (data_up) { 233061da546Spatrick data_up->user_source.SplitIntoLines(line); 234061da546Spatrick auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>( 235061da546Spatrick std::move(data_up)); 236061da546Spatrick wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 237061da546Spatrick } 238061da546Spatrick } 239061da546Spatrick } 240061da546Spatrick 241061da546Spatrick void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, 242061da546Spatrick CommandReturnObject &result) { 243061da546Spatrick m_interpreter.GetLLDBCommandsFromIOHandler( 244061da546Spatrick "> ", // Prompt 245061da546Spatrick *this, // IOHandlerDelegate 246061da546Spatrick wp_options); // Baton for the "io_handler" that will be passed back into 247061da546Spatrick // our IOHandlerDelegate functions 248061da546Spatrick } 249061da546Spatrick 250061da546Spatrick /// Set a one-liner as the callback for the watchpoint. 251061da546Spatrick void SetWatchpointCommandCallback(WatchpointOptions *wp_options, 252061da546Spatrick const char *oneliner) { 253061da546Spatrick std::unique_ptr<WatchpointOptions::CommandData> data_up( 254061da546Spatrick new WatchpointOptions::CommandData()); 255061da546Spatrick 256061da546Spatrick // It's necessary to set both user_source and script_source to the 257061da546Spatrick // oneliner. The former is used to generate callback description (as in 258061da546Spatrick // watchpoint command list) while the latter is used for Python to 259061da546Spatrick // interpret during the actual callback. 260061da546Spatrick data_up->user_source.AppendString(oneliner); 261061da546Spatrick data_up->script_source.assign(oneliner); 262061da546Spatrick data_up->stop_on_error = m_options.m_stop_on_error; 263061da546Spatrick 264061da546Spatrick auto baton_sp = 265061da546Spatrick std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 266061da546Spatrick wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 267061da546Spatrick } 268061da546Spatrick 269061da546Spatrick static bool 270061da546Spatrick WatchpointOptionsCallbackFunction(void *baton, 271061da546Spatrick StoppointCallbackContext *context, 272061da546Spatrick lldb::user_id_t watch_id) { 273061da546Spatrick bool ret_value = true; 274061da546Spatrick if (baton == nullptr) 275061da546Spatrick return true; 276061da546Spatrick 277061da546Spatrick WatchpointOptions::CommandData *data = 278061da546Spatrick (WatchpointOptions::CommandData *)baton; 279061da546Spatrick StringList &commands = data->user_source; 280061da546Spatrick 281061da546Spatrick if (commands.GetSize() > 0) { 282061da546Spatrick ExecutionContext exe_ctx(context->exe_ctx_ref); 283061da546Spatrick Target *target = exe_ctx.GetTargetPtr(); 284061da546Spatrick if (target) { 285061da546Spatrick Debugger &debugger = target->GetDebugger(); 286*dda28197Spatrick CommandReturnObject result(debugger.GetUseColor()); 287*dda28197Spatrick 288061da546Spatrick // Rig up the results secondary output stream to the debugger's, so the 289061da546Spatrick // output will come out synchronously if the debugger is set up that 290061da546Spatrick // way. 291061da546Spatrick StreamSP output_stream(debugger.GetAsyncOutputStream()); 292061da546Spatrick StreamSP error_stream(debugger.GetAsyncErrorStream()); 293061da546Spatrick result.SetImmediateOutputStream(output_stream); 294061da546Spatrick result.SetImmediateErrorStream(error_stream); 295061da546Spatrick 296061da546Spatrick CommandInterpreterRunOptions options; 297061da546Spatrick options.SetStopOnContinue(true); 298061da546Spatrick options.SetStopOnError(data->stop_on_error); 299061da546Spatrick options.SetEchoCommands(false); 300061da546Spatrick options.SetPrintResults(true); 301061da546Spatrick options.SetPrintErrors(true); 302061da546Spatrick options.SetAddToHistory(false); 303061da546Spatrick 304061da546Spatrick debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx, 305061da546Spatrick options, result); 306061da546Spatrick result.GetImmediateOutputStream()->Flush(); 307061da546Spatrick result.GetImmediateErrorStream()->Flush(); 308061da546Spatrick } 309061da546Spatrick } 310061da546Spatrick return ret_value; 311061da546Spatrick } 312061da546Spatrick 313061da546Spatrick class CommandOptions : public Options { 314061da546Spatrick public: 315061da546Spatrick CommandOptions() 316061da546Spatrick : Options(), m_use_commands(false), m_use_script_language(false), 317061da546Spatrick m_script_language(eScriptLanguageNone), m_use_one_liner(false), 318061da546Spatrick m_one_liner(), m_function_name() {} 319061da546Spatrick 320061da546Spatrick ~CommandOptions() override = default; 321061da546Spatrick 322061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 323061da546Spatrick ExecutionContext *execution_context) override { 324061da546Spatrick Status error; 325061da546Spatrick const int short_option = m_getopt_table[option_idx].val; 326061da546Spatrick 327061da546Spatrick switch (short_option) { 328061da546Spatrick case 'o': 329061da546Spatrick m_use_one_liner = true; 330*dda28197Spatrick m_one_liner = std::string(option_arg); 331061da546Spatrick break; 332061da546Spatrick 333061da546Spatrick case 's': 334061da546Spatrick m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( 335061da546Spatrick option_arg, GetDefinitions()[option_idx].enum_values, 336061da546Spatrick eScriptLanguageNone, error); 337061da546Spatrick 338061da546Spatrick switch (m_script_language) { 339061da546Spatrick case eScriptLanguagePython: 340061da546Spatrick case eScriptLanguageLua: 341061da546Spatrick m_use_script_language = true; 342061da546Spatrick break; 343061da546Spatrick case eScriptLanguageNone: 344061da546Spatrick case eScriptLanguageUnknown: 345061da546Spatrick m_use_script_language = false; 346061da546Spatrick break; 347061da546Spatrick } 348061da546Spatrick break; 349061da546Spatrick 350061da546Spatrick case 'e': { 351061da546Spatrick bool success = false; 352061da546Spatrick m_stop_on_error = 353061da546Spatrick OptionArgParser::ToBoolean(option_arg, false, &success); 354061da546Spatrick if (!success) 355061da546Spatrick error.SetErrorStringWithFormat( 356061da546Spatrick "invalid value for stop-on-error: \"%s\"", 357061da546Spatrick option_arg.str().c_str()); 358061da546Spatrick } break; 359061da546Spatrick 360061da546Spatrick case 'F': 361061da546Spatrick m_use_one_liner = false; 362*dda28197Spatrick m_function_name.assign(std::string(option_arg)); 363061da546Spatrick break; 364061da546Spatrick 365061da546Spatrick default: 366061da546Spatrick llvm_unreachable("Unimplemented option"); 367061da546Spatrick } 368061da546Spatrick return error; 369061da546Spatrick } 370061da546Spatrick 371061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override { 372061da546Spatrick m_use_commands = true; 373061da546Spatrick m_use_script_language = false; 374061da546Spatrick m_script_language = eScriptLanguageNone; 375061da546Spatrick 376061da546Spatrick m_use_one_liner = false; 377061da546Spatrick m_stop_on_error = true; 378061da546Spatrick m_one_liner.clear(); 379061da546Spatrick m_function_name.clear(); 380061da546Spatrick } 381061da546Spatrick 382061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 383061da546Spatrick return llvm::makeArrayRef(g_watchpoint_command_add_options); 384061da546Spatrick } 385061da546Spatrick 386061da546Spatrick // Instance variables to hold the values for command options. 387061da546Spatrick 388061da546Spatrick bool m_use_commands; 389061da546Spatrick bool m_use_script_language; 390061da546Spatrick lldb::ScriptLanguage m_script_language; 391061da546Spatrick 392061da546Spatrick // Instance variables to hold the values for one_liner options. 393061da546Spatrick bool m_use_one_liner; 394061da546Spatrick std::string m_one_liner; 395061da546Spatrick bool m_stop_on_error; 396061da546Spatrick std::string m_function_name; 397061da546Spatrick }; 398061da546Spatrick 399061da546Spatrick protected: 400061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 401061da546Spatrick Target *target = &GetSelectedTarget(); 402061da546Spatrick 403061da546Spatrick const WatchpointList &watchpoints = target->GetWatchpointList(); 404061da546Spatrick size_t num_watchpoints = watchpoints.GetSize(); 405061da546Spatrick 406061da546Spatrick if (num_watchpoints == 0) { 407061da546Spatrick result.AppendError("No watchpoints exist to have commands added"); 408061da546Spatrick result.SetStatus(eReturnStatusFailed); 409061da546Spatrick return false; 410061da546Spatrick } 411061da546Spatrick 412061da546Spatrick if (!m_options.m_function_name.empty()) { 413061da546Spatrick if (!m_options.m_use_script_language) { 414061da546Spatrick m_options.m_script_language = GetDebugger().GetScriptLanguage(); 415061da546Spatrick m_options.m_use_script_language = true; 416061da546Spatrick } 417061da546Spatrick } 418061da546Spatrick 419061da546Spatrick std::vector<uint32_t> valid_wp_ids; 420061da546Spatrick if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 421061da546Spatrick valid_wp_ids)) { 422061da546Spatrick result.AppendError("Invalid watchpoints specification."); 423061da546Spatrick result.SetStatus(eReturnStatusFailed); 424061da546Spatrick return false; 425061da546Spatrick } 426061da546Spatrick 427061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult); 428061da546Spatrick const size_t count = valid_wp_ids.size(); 429061da546Spatrick for (size_t i = 0; i < count; ++i) { 430061da546Spatrick uint32_t cur_wp_id = valid_wp_ids.at(i); 431061da546Spatrick if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 432061da546Spatrick Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 433061da546Spatrick // Sanity check wp first. 434061da546Spatrick if (wp == nullptr) 435061da546Spatrick continue; 436061da546Spatrick 437061da546Spatrick WatchpointOptions *wp_options = wp->GetOptions(); 438061da546Spatrick // Skip this watchpoint if wp_options is not good. 439061da546Spatrick if (wp_options == nullptr) 440061da546Spatrick continue; 441061da546Spatrick 442061da546Spatrick // If we are using script language, get the script interpreter in order 443061da546Spatrick // to set or collect command callback. Otherwise, call the methods 444061da546Spatrick // associated with this object. 445061da546Spatrick if (m_options.m_use_script_language) { 446061da546Spatrick ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter( 447061da546Spatrick /*can_create=*/true, m_options.m_script_language); 448061da546Spatrick // Special handling for one-liner specified inline. 449061da546Spatrick if (m_options.m_use_one_liner) { 450061da546Spatrick script_interp->SetWatchpointCommandCallback( 451061da546Spatrick wp_options, m_options.m_one_liner.c_str()); 452061da546Spatrick } 453061da546Spatrick // Special handling for using a Python function by name instead of 454061da546Spatrick // extending the watchpoint callback data structures, we just 455061da546Spatrick // automatize what the user would do manually: make their watchpoint 456061da546Spatrick // command be a function call 457061da546Spatrick else if (!m_options.m_function_name.empty()) { 458061da546Spatrick std::string oneliner(m_options.m_function_name); 459061da546Spatrick oneliner += "(frame, wp, internal_dict)"; 460061da546Spatrick script_interp->SetWatchpointCommandCallback( 461061da546Spatrick wp_options, oneliner.c_str()); 462061da546Spatrick } else { 463061da546Spatrick script_interp->CollectDataForWatchpointCommandCallback(wp_options, 464061da546Spatrick result); 465061da546Spatrick } 466061da546Spatrick } else { 467061da546Spatrick // Special handling for one-liner specified inline. 468061da546Spatrick if (m_options.m_use_one_liner) 469061da546Spatrick SetWatchpointCommandCallback(wp_options, 470061da546Spatrick m_options.m_one_liner.c_str()); 471061da546Spatrick else 472061da546Spatrick CollectDataForWatchpointCommandCallback(wp_options, result); 473061da546Spatrick } 474061da546Spatrick } 475061da546Spatrick } 476061da546Spatrick 477061da546Spatrick return result.Succeeded(); 478061da546Spatrick } 479061da546Spatrick 480061da546Spatrick private: 481061da546Spatrick CommandOptions m_options; 482061da546Spatrick }; 483061da546Spatrick 484061da546Spatrick // CommandObjectWatchpointCommandDelete 485061da546Spatrick 486061da546Spatrick class CommandObjectWatchpointCommandDelete : public CommandObjectParsed { 487061da546Spatrick public: 488061da546Spatrick CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter) 489061da546Spatrick : CommandObjectParsed(interpreter, "delete", 490061da546Spatrick "Delete the set of commands from a watchpoint.", 491061da546Spatrick nullptr, eCommandRequiresTarget) { 492061da546Spatrick CommandArgumentEntry arg; 493061da546Spatrick CommandArgumentData wp_id_arg; 494061da546Spatrick 495061da546Spatrick // Define the first (and only) variant of this arg. 496061da546Spatrick wp_id_arg.arg_type = eArgTypeWatchpointID; 497061da546Spatrick wp_id_arg.arg_repetition = eArgRepeatPlain; 498061da546Spatrick 499061da546Spatrick // There is only one variant this argument could be; put it into the 500061da546Spatrick // argument entry. 501061da546Spatrick arg.push_back(wp_id_arg); 502061da546Spatrick 503061da546Spatrick // Push the data for the first argument into the m_arguments vector. 504061da546Spatrick m_arguments.push_back(arg); 505061da546Spatrick } 506061da546Spatrick 507061da546Spatrick ~CommandObjectWatchpointCommandDelete() override = default; 508061da546Spatrick 509061da546Spatrick protected: 510061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 511061da546Spatrick Target *target = &GetSelectedTarget(); 512061da546Spatrick 513061da546Spatrick const WatchpointList &watchpoints = target->GetWatchpointList(); 514061da546Spatrick size_t num_watchpoints = watchpoints.GetSize(); 515061da546Spatrick 516061da546Spatrick if (num_watchpoints == 0) { 517061da546Spatrick result.AppendError("No watchpoints exist to have commands deleted"); 518061da546Spatrick result.SetStatus(eReturnStatusFailed); 519061da546Spatrick return false; 520061da546Spatrick } 521061da546Spatrick 522061da546Spatrick if (command.GetArgumentCount() == 0) { 523061da546Spatrick result.AppendError( 524061da546Spatrick "No watchpoint specified from which to delete the commands"); 525061da546Spatrick result.SetStatus(eReturnStatusFailed); 526061da546Spatrick return false; 527061da546Spatrick } 528061da546Spatrick 529061da546Spatrick std::vector<uint32_t> valid_wp_ids; 530061da546Spatrick if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 531061da546Spatrick valid_wp_ids)) { 532061da546Spatrick result.AppendError("Invalid watchpoints specification."); 533061da546Spatrick result.SetStatus(eReturnStatusFailed); 534061da546Spatrick return false; 535061da546Spatrick } 536061da546Spatrick 537061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult); 538061da546Spatrick const size_t count = valid_wp_ids.size(); 539061da546Spatrick for (size_t i = 0; i < count; ++i) { 540061da546Spatrick uint32_t cur_wp_id = valid_wp_ids.at(i); 541061da546Spatrick if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 542061da546Spatrick Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 543061da546Spatrick if (wp) 544061da546Spatrick wp->ClearCallback(); 545061da546Spatrick } else { 546061da546Spatrick result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 547061da546Spatrick result.SetStatus(eReturnStatusFailed); 548061da546Spatrick return false; 549061da546Spatrick } 550061da546Spatrick } 551061da546Spatrick return result.Succeeded(); 552061da546Spatrick } 553061da546Spatrick }; 554061da546Spatrick 555061da546Spatrick // CommandObjectWatchpointCommandList 556061da546Spatrick 557061da546Spatrick class CommandObjectWatchpointCommandList : public CommandObjectParsed { 558061da546Spatrick public: 559061da546Spatrick CommandObjectWatchpointCommandList(CommandInterpreter &interpreter) 560061da546Spatrick : CommandObjectParsed(interpreter, "list", 561061da546Spatrick "List the script or set of commands to be executed " 562061da546Spatrick "when the watchpoint is hit.", 563061da546Spatrick nullptr, eCommandRequiresTarget) { 564061da546Spatrick CommandArgumentEntry arg; 565061da546Spatrick CommandArgumentData wp_id_arg; 566061da546Spatrick 567061da546Spatrick // Define the first (and only) variant of this arg. 568061da546Spatrick wp_id_arg.arg_type = eArgTypeWatchpointID; 569061da546Spatrick wp_id_arg.arg_repetition = eArgRepeatPlain; 570061da546Spatrick 571061da546Spatrick // There is only one variant this argument could be; put it into the 572061da546Spatrick // argument entry. 573061da546Spatrick arg.push_back(wp_id_arg); 574061da546Spatrick 575061da546Spatrick // Push the data for the first argument into the m_arguments vector. 576061da546Spatrick m_arguments.push_back(arg); 577061da546Spatrick } 578061da546Spatrick 579061da546Spatrick ~CommandObjectWatchpointCommandList() override = default; 580061da546Spatrick 581061da546Spatrick protected: 582061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override { 583061da546Spatrick Target *target = &GetSelectedTarget(); 584061da546Spatrick 585061da546Spatrick const WatchpointList &watchpoints = target->GetWatchpointList(); 586061da546Spatrick size_t num_watchpoints = watchpoints.GetSize(); 587061da546Spatrick 588061da546Spatrick if (num_watchpoints == 0) { 589061da546Spatrick result.AppendError("No watchpoints exist for which to list commands"); 590061da546Spatrick result.SetStatus(eReturnStatusFailed); 591061da546Spatrick return false; 592061da546Spatrick } 593061da546Spatrick 594061da546Spatrick if (command.GetArgumentCount() == 0) { 595061da546Spatrick result.AppendError( 596061da546Spatrick "No watchpoint specified for which to list the commands"); 597061da546Spatrick result.SetStatus(eReturnStatusFailed); 598061da546Spatrick return false; 599061da546Spatrick } 600061da546Spatrick 601061da546Spatrick std::vector<uint32_t> valid_wp_ids; 602061da546Spatrick if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 603061da546Spatrick valid_wp_ids)) { 604061da546Spatrick result.AppendError("Invalid watchpoints specification."); 605061da546Spatrick result.SetStatus(eReturnStatusFailed); 606061da546Spatrick return false; 607061da546Spatrick } 608061da546Spatrick 609061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult); 610061da546Spatrick const size_t count = valid_wp_ids.size(); 611061da546Spatrick for (size_t i = 0; i < count; ++i) { 612061da546Spatrick uint32_t cur_wp_id = valid_wp_ids.at(i); 613061da546Spatrick if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 614061da546Spatrick Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 615061da546Spatrick 616061da546Spatrick if (wp) { 617061da546Spatrick const WatchpointOptions *wp_options = wp->GetOptions(); 618061da546Spatrick if (wp_options) { 619061da546Spatrick // Get the callback baton associated with the current watchpoint. 620061da546Spatrick const Baton *baton = wp_options->GetBaton(); 621061da546Spatrick if (baton) { 622061da546Spatrick result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id); 623061da546Spatrick baton->GetDescription(result.GetOutputStream().AsRawOstream(), 624061da546Spatrick eDescriptionLevelFull, 625061da546Spatrick result.GetOutputStream().GetIndentLevel() + 626061da546Spatrick 2); 627061da546Spatrick } else { 628061da546Spatrick result.AppendMessageWithFormat( 629061da546Spatrick "Watchpoint %u does not have an associated command.\n", 630061da546Spatrick cur_wp_id); 631061da546Spatrick } 632061da546Spatrick } 633061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult); 634061da546Spatrick } else { 635061da546Spatrick result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 636061da546Spatrick cur_wp_id); 637061da546Spatrick result.SetStatus(eReturnStatusFailed); 638061da546Spatrick } 639061da546Spatrick } 640061da546Spatrick } 641061da546Spatrick 642061da546Spatrick return result.Succeeded(); 643061da546Spatrick } 644061da546Spatrick }; 645061da546Spatrick 646061da546Spatrick // CommandObjectWatchpointCommand 647061da546Spatrick 648061da546Spatrick CommandObjectWatchpointCommand::CommandObjectWatchpointCommand( 649061da546Spatrick CommandInterpreter &interpreter) 650061da546Spatrick : CommandObjectMultiword( 651061da546Spatrick interpreter, "command", 652061da546Spatrick "Commands for adding, removing and examining LLDB commands " 653061da546Spatrick "executed when the watchpoint is hit (watchpoint 'commands').", 654061da546Spatrick "command <sub-command> [<sub-command-options>] <watchpoint-id>") { 655061da546Spatrick CommandObjectSP add_command_object( 656061da546Spatrick new CommandObjectWatchpointCommandAdd(interpreter)); 657061da546Spatrick CommandObjectSP delete_command_object( 658061da546Spatrick new CommandObjectWatchpointCommandDelete(interpreter)); 659061da546Spatrick CommandObjectSP list_command_object( 660061da546Spatrick new CommandObjectWatchpointCommandList(interpreter)); 661061da546Spatrick 662061da546Spatrick add_command_object->SetCommandName("watchpoint command add"); 663061da546Spatrick delete_command_object->SetCommandName("watchpoint command delete"); 664061da546Spatrick list_command_object->SetCommandName("watchpoint command list"); 665061da546Spatrick 666061da546Spatrick LoadSubCommand("add", add_command_object); 667061da546Spatrick LoadSubCommand("delete", delete_command_object); 668061da546Spatrick LoadSubCommand("list", list_command_object); 669061da546Spatrick } 670061da546Spatrick 671061da546Spatrick CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default; 672