15ffd83dbSDimitry Andric //===-- CommandObjectWatchpointCommand.cpp --------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include <vector> 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "CommandObjectWatchpoint.h" 12*0b57cec5SDimitry Andric #include "CommandObjectWatchpointCommand.h" 13*0b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h" 14*0b57cec5SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h" 15*0b57cec5SDimitry Andric #include "lldb/Core/IOHandler.h" 16*0b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 17*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 18fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 19*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 20*0b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 21*0b57cec5SDimitry Andric #include "lldb/Target/Target.h" 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric using namespace lldb; 24*0b57cec5SDimitry Andric using namespace lldb_private; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric #define LLDB_OPTIONS_watchpoint_command_add 27*0b57cec5SDimitry Andric #include "CommandOptions.inc" 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandAdd : public CommandObjectParsed, 30*0b57cec5SDimitry Andric public IOHandlerDelegateMultiline { 31*0b57cec5SDimitry Andric public: 32*0b57cec5SDimitry Andric CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter) 33*0b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "add", 34*0b57cec5SDimitry Andric "Add a set of LLDB commands to a watchpoint, to be " 35fe6060f1SDimitry Andric "executed whenever the watchpoint is hit. " 36fe6060f1SDimitry Andric "The commands added to the watchpoint replace any " 37fe6060f1SDimitry Andric "commands previously added to it.", 389dba64beSDimitry Andric nullptr, eCommandRequiresTarget), 39*0b57cec5SDimitry Andric IOHandlerDelegateMultiline("DONE", 4004eeddc0SDimitry Andric IOHandlerDelegate::Completion::LLDBCommand) { 41*0b57cec5SDimitry Andric SetHelpLong( 42*0b57cec5SDimitry Andric R"( 43*0b57cec5SDimitry Andric General information about entering watchpoint commands 44*0b57cec5SDimitry Andric ------------------------------------------------------ 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric )" 47*0b57cec5SDimitry Andric "This command will prompt for commands to be executed when the specified \ 48*0b57cec5SDimitry Andric watchpoint is hit. Each command is typed on its own line following the '> ' \ 49*0b57cec5SDimitry Andric prompt until 'DONE' is entered." 50*0b57cec5SDimitry Andric R"( 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric )" 53*0b57cec5SDimitry Andric "Syntactic errors may not be detected when initially entered, and many \ 54*0b57cec5SDimitry Andric malformed commands can silently fail when executed. If your watchpoint commands \ 55*0b57cec5SDimitry Andric do not appear to be executing, double-check the command syntax." 56*0b57cec5SDimitry Andric R"( 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric )" 59*0b57cec5SDimitry Andric "Note: You may enter any debugger command exactly as you would at the debugger \ 60*0b57cec5SDimitry Andric prompt. There is no limit to the number of commands supplied, but do NOT enter \ 61*0b57cec5SDimitry Andric more than one command per line." 62*0b57cec5SDimitry Andric R"( 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric Special information about PYTHON watchpoint commands 65*0b57cec5SDimitry Andric ---------------------------------------------------- 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric )" 68*0b57cec5SDimitry Andric "You may enter either one or more lines of Python, including function \ 69*0b57cec5SDimitry Andric definitions or calls to functions that will have been imported by the time \ 70*0b57cec5SDimitry Andric the code executes. Single line watchpoint commands will be interpreted 'as is' \ 71*0b57cec5SDimitry Andric when the watchpoint is hit. Multiple lines of Python will be wrapped in a \ 72*0b57cec5SDimitry Andric generated function, and a call to the function will be attached to the watchpoint." 73*0b57cec5SDimitry Andric R"( 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric This auto-generated function is passed in three arguments: 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric frame: an lldb.SBFrame object for the frame which hit the watchpoint. 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric wp: the watchpoint that was hit. 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric )" 82*0b57cec5SDimitry Andric "When specifying a python function with the --python-function option, you need \ 83*0b57cec5SDimitry Andric to supply the function name prepended by the module name:" 84*0b57cec5SDimitry Andric R"( 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric --python-function myutils.watchpoint_callback 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric The function itself must have the following prototype: 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric def watchpoint_callback(frame, wp): 91*0b57cec5SDimitry Andric # Your code goes here 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric )" 94*0b57cec5SDimitry Andric "The arguments are the same as the arguments passed to generated functions as \ 95*0b57cec5SDimitry Andric described above. Note that the global variable 'lldb.frame' will NOT be updated when \ 96*0b57cec5SDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ 97*0b57cec5SDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \ 98*0b57cec5SDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \ 99*0b57cec5SDimitry Andric via process.GetTarget()." 100*0b57cec5SDimitry Andric R"( 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric )" 103*0b57cec5SDimitry Andric "Important Note: As Python code gets collected into functions, access to global \ 104*0b57cec5SDimitry Andric variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ 105*0b57cec5SDimitry Andric Python syntax, including indentation, when entering Python watchpoint commands." 106*0b57cec5SDimitry Andric R"( 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric Example Python one-line watchpoint command: 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 111*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 112*0b57cec5SDimitry Andric > print "Hit this watchpoint!" 113*0b57cec5SDimitry Andric > DONE 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric As a convenience, this also works for a short Python one-liner: 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()' 118*0b57cec5SDimitry Andric (lldb) run 119*0b57cec5SDimitry Andric Launching '.../a.out' (x86_64) 120*0b57cec5SDimitry Andric (lldb) Fri Sep 10 12:17:45 2010 121*0b57cec5SDimitry Andric Process 21778 Stopped 122*0b57cec5SDimitry Andric * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread 123*0b57cec5SDimitry Andric 36 124*0b57cec5SDimitry Andric 37 int c(int val) 125*0b57cec5SDimitry Andric 38 { 126*0b57cec5SDimitry Andric 39 -> return val + 3; 127*0b57cec5SDimitry Andric 40 } 128*0b57cec5SDimitry Andric 41 129*0b57cec5SDimitry Andric 42 int main (int argc, char const *argv[]) 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using function definition: 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 134*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 135*0b57cec5SDimitry Andric > def watchpoint_output (wp_no): 136*0b57cec5SDimitry Andric > out_string = "Hit watchpoint number " + repr (wp_no) 137*0b57cec5SDimitry Andric > print out_string 138*0b57cec5SDimitry Andric > return True 139*0b57cec5SDimitry Andric > watchpoint_output (1) 140*0b57cec5SDimitry Andric > DONE 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using 'loose' Python: 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric (lldb) watchpoint command add -s p 1 145*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 146*0b57cec5SDimitry Andric > global wp_count 147*0b57cec5SDimitry Andric > wp_count = wp_count + 1 148*0b57cec5SDimitry Andric > print "Hit this watchpoint " + repr(wp_count) + " times!" 149*0b57cec5SDimitry Andric > DONE 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric )" 152*0b57cec5SDimitry Andric "In this case, since there is a reference to a global variable, \ 153*0b57cec5SDimitry Andric 'wp_count', you will also need to make sure 'wp_count' exists and is \ 154*0b57cec5SDimitry Andric initialized:" 155*0b57cec5SDimitry Andric R"( 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric (lldb) script 158*0b57cec5SDimitry Andric >>> wp_count = 0 159*0b57cec5SDimitry Andric >>> quit() 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric )" 162*0b57cec5SDimitry Andric "Final Note: A warning that no watchpoint command was generated when there \ 163*0b57cec5SDimitry Andric are no syntax errors may indicate that a function was declared but never called."); 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric CommandArgumentEntry arg; 166*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 169*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 170*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 171*0b57cec5SDimitry Andric 172*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 173*0b57cec5SDimitry Andric // argument entry. 174*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 177*0b57cec5SDimitry Andric m_arguments.push_back(arg); 178*0b57cec5SDimitry Andric } 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandAdd() override = default; 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1859dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 186*0b57cec5SDimitry Andric if (output_sp && interactive) { 187*0b57cec5SDimitry Andric output_sp->PutCString( 188*0b57cec5SDimitry Andric "Enter your debugger command(s). Type 'DONE' to end.\n"); 189*0b57cec5SDimitry Andric output_sp->Flush(); 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 194*0b57cec5SDimitry Andric std::string &line) override { 195*0b57cec5SDimitry Andric io_handler.SetIsDone(true); 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric // The WatchpointOptions object is owned by the watchpoint or watchpoint 198*0b57cec5SDimitry Andric // location 199*0b57cec5SDimitry Andric WatchpointOptions *wp_options = 200*0b57cec5SDimitry Andric (WatchpointOptions *)io_handler.GetUserData(); 201*0b57cec5SDimitry Andric if (wp_options) { 202*0b57cec5SDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_up( 203*0b57cec5SDimitry Andric new WatchpointOptions::CommandData()); 204*0b57cec5SDimitry Andric if (data_up) { 205*0b57cec5SDimitry Andric data_up->user_source.SplitIntoLines(line); 206*0b57cec5SDimitry Andric auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>( 207*0b57cec5SDimitry Andric std::move(data_up)); 208*0b57cec5SDimitry Andric wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 209*0b57cec5SDimitry Andric } 210*0b57cec5SDimitry Andric } 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, 214*0b57cec5SDimitry Andric CommandReturnObject &result) { 215*0b57cec5SDimitry Andric m_interpreter.GetLLDBCommandsFromIOHandler( 216*0b57cec5SDimitry Andric "> ", // Prompt 217*0b57cec5SDimitry Andric *this, // IOHandlerDelegate 218*0b57cec5SDimitry Andric wp_options); // Baton for the "io_handler" that will be passed back into 219*0b57cec5SDimitry Andric // our IOHandlerDelegate functions 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric /// Set a one-liner as the callback for the watchpoint. 223*0b57cec5SDimitry Andric void SetWatchpointCommandCallback(WatchpointOptions *wp_options, 224*0b57cec5SDimitry Andric const char *oneliner) { 225*0b57cec5SDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_up( 226*0b57cec5SDimitry Andric new WatchpointOptions::CommandData()); 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric // It's necessary to set both user_source and script_source to the 229*0b57cec5SDimitry Andric // oneliner. The former is used to generate callback description (as in 230*0b57cec5SDimitry Andric // watchpoint command list) while the latter is used for Python to 231*0b57cec5SDimitry Andric // interpret during the actual callback. 232*0b57cec5SDimitry Andric data_up->user_source.AppendString(oneliner); 233*0b57cec5SDimitry Andric data_up->script_source.assign(oneliner); 234*0b57cec5SDimitry Andric data_up->stop_on_error = m_options.m_stop_on_error; 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric auto baton_sp = 237*0b57cec5SDimitry Andric std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 238*0b57cec5SDimitry Andric wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 239*0b57cec5SDimitry Andric } 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric static bool 242*0b57cec5SDimitry Andric WatchpointOptionsCallbackFunction(void *baton, 243*0b57cec5SDimitry Andric StoppointCallbackContext *context, 244*0b57cec5SDimitry Andric lldb::user_id_t watch_id) { 245*0b57cec5SDimitry Andric bool ret_value = true; 246*0b57cec5SDimitry Andric if (baton == nullptr) 247*0b57cec5SDimitry Andric return true; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric WatchpointOptions::CommandData *data = 250*0b57cec5SDimitry Andric (WatchpointOptions::CommandData *)baton; 251*0b57cec5SDimitry Andric StringList &commands = data->user_source; 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric if (commands.GetSize() > 0) { 254*0b57cec5SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 255*0b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 256*0b57cec5SDimitry Andric if (target) { 257*0b57cec5SDimitry Andric Debugger &debugger = target->GetDebugger(); 2585ffd83dbSDimitry Andric CommandReturnObject result(debugger.GetUseColor()); 2595ffd83dbSDimitry Andric 260*0b57cec5SDimitry Andric // Rig up the results secondary output stream to the debugger's, so the 261*0b57cec5SDimitry Andric // output will come out synchronously if the debugger is set up that 262*0b57cec5SDimitry Andric // way. 263*0b57cec5SDimitry Andric StreamSP output_stream(debugger.GetAsyncOutputStream()); 264*0b57cec5SDimitry Andric StreamSP error_stream(debugger.GetAsyncErrorStream()); 265*0b57cec5SDimitry Andric result.SetImmediateOutputStream(output_stream); 266*0b57cec5SDimitry Andric result.SetImmediateErrorStream(error_stream); 267*0b57cec5SDimitry Andric 268*0b57cec5SDimitry Andric CommandInterpreterRunOptions options; 269*0b57cec5SDimitry Andric options.SetStopOnContinue(true); 270*0b57cec5SDimitry Andric options.SetStopOnError(data->stop_on_error); 271*0b57cec5SDimitry Andric options.SetEchoCommands(false); 272*0b57cec5SDimitry Andric options.SetPrintResults(true); 273*0b57cec5SDimitry Andric options.SetPrintErrors(true); 274*0b57cec5SDimitry Andric options.SetAddToHistory(false); 275*0b57cec5SDimitry Andric 276fe6060f1SDimitry Andric debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx, 277*0b57cec5SDimitry Andric options, result); 278*0b57cec5SDimitry Andric result.GetImmediateOutputStream()->Flush(); 279*0b57cec5SDimitry Andric result.GetImmediateErrorStream()->Flush(); 280*0b57cec5SDimitry Andric } 281*0b57cec5SDimitry Andric } 282*0b57cec5SDimitry Andric return ret_value; 283*0b57cec5SDimitry Andric } 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric class CommandOptions : public Options { 286*0b57cec5SDimitry Andric public: 28781ad6265SDimitry Andric CommandOptions() = default; 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric ~CommandOptions() override = default; 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 292*0b57cec5SDimitry Andric ExecutionContext *execution_context) override { 293*0b57cec5SDimitry Andric Status error; 294*0b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric switch (short_option) { 297*0b57cec5SDimitry Andric case 'o': 298*0b57cec5SDimitry Andric m_use_one_liner = true; 2995ffd83dbSDimitry Andric m_one_liner = std::string(option_arg); 300*0b57cec5SDimitry Andric break; 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric case 's': 303*0b57cec5SDimitry Andric m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( 304*0b57cec5SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 305*0b57cec5SDimitry Andric eScriptLanguageNone, error); 306*0b57cec5SDimitry Andric 307480093f4SDimitry Andric switch (m_script_language) { 308480093f4SDimitry Andric case eScriptLanguagePython: 309480093f4SDimitry Andric case eScriptLanguageLua: 310480093f4SDimitry Andric m_use_script_language = true; 311480093f4SDimitry Andric break; 312480093f4SDimitry Andric case eScriptLanguageNone: 313480093f4SDimitry Andric case eScriptLanguageUnknown: 314480093f4SDimitry Andric m_use_script_language = false; 315480093f4SDimitry Andric break; 316480093f4SDimitry Andric } 317*0b57cec5SDimitry Andric break; 318*0b57cec5SDimitry Andric 319*0b57cec5SDimitry Andric case 'e': { 320*0b57cec5SDimitry Andric bool success = false; 321*0b57cec5SDimitry Andric m_stop_on_error = 322*0b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success); 323*0b57cec5SDimitry Andric if (!success) 324*0b57cec5SDimitry Andric error.SetErrorStringWithFormat( 325*0b57cec5SDimitry Andric "invalid value for stop-on-error: \"%s\"", 326*0b57cec5SDimitry Andric option_arg.str().c_str()); 327*0b57cec5SDimitry Andric } break; 328*0b57cec5SDimitry Andric 329*0b57cec5SDimitry Andric case 'F': 330*0b57cec5SDimitry Andric m_use_one_liner = false; 3315ffd83dbSDimitry Andric m_function_name.assign(std::string(option_arg)); 332*0b57cec5SDimitry Andric break; 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric default: 3359dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 336*0b57cec5SDimitry Andric } 337*0b57cec5SDimitry Andric return error; 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 341*0b57cec5SDimitry Andric m_use_commands = true; 342*0b57cec5SDimitry Andric m_use_script_language = false; 343*0b57cec5SDimitry Andric m_script_language = eScriptLanguageNone; 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric m_use_one_liner = false; 346*0b57cec5SDimitry Andric m_stop_on_error = true; 347*0b57cec5SDimitry Andric m_one_liner.clear(); 348*0b57cec5SDimitry Andric m_function_name.clear(); 349*0b57cec5SDimitry Andric } 350*0b57cec5SDimitry Andric 351*0b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 352*0b57cec5SDimitry Andric return llvm::makeArrayRef(g_watchpoint_command_add_options); 353*0b57cec5SDimitry Andric } 354*0b57cec5SDimitry Andric 355*0b57cec5SDimitry Andric // Instance variables to hold the values for command options. 356*0b57cec5SDimitry Andric 357fe6060f1SDimitry Andric bool m_use_commands = false; 358fe6060f1SDimitry Andric bool m_use_script_language = false; 359fe6060f1SDimitry Andric lldb::ScriptLanguage m_script_language = eScriptLanguageNone; 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric // Instance variables to hold the values for one_liner options. 362fe6060f1SDimitry Andric bool m_use_one_liner = false; 363*0b57cec5SDimitry Andric std::string m_one_liner; 364*0b57cec5SDimitry Andric bool m_stop_on_error; 365*0b57cec5SDimitry Andric std::string m_function_name; 366*0b57cec5SDimitry Andric }; 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric protected: 369*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 3709dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 373*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 376*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist to have commands added"); 377*0b57cec5SDimitry Andric return false; 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 380480093f4SDimitry Andric if (!m_options.m_function_name.empty()) { 381480093f4SDimitry Andric if (!m_options.m_use_script_language) { 382480093f4SDimitry Andric m_options.m_script_language = GetDebugger().GetScriptLanguage(); 383480093f4SDimitry Andric m_options.m_use_script_language = true; 384480093f4SDimitry Andric } 385*0b57cec5SDimitry Andric } 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 388*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 389*0b57cec5SDimitry Andric valid_wp_ids)) { 390*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 391*0b57cec5SDimitry Andric return false; 392*0b57cec5SDimitry Andric } 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 395*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 396*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 397*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 398*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 399*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 400*0b57cec5SDimitry Andric // Sanity check wp first. 401*0b57cec5SDimitry Andric if (wp == nullptr) 402*0b57cec5SDimitry Andric continue; 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric WatchpointOptions *wp_options = wp->GetOptions(); 405*0b57cec5SDimitry Andric // Skip this watchpoint if wp_options is not good. 406*0b57cec5SDimitry Andric if (wp_options == nullptr) 407*0b57cec5SDimitry Andric continue; 408*0b57cec5SDimitry Andric 409*0b57cec5SDimitry Andric // If we are using script language, get the script interpreter in order 410*0b57cec5SDimitry Andric // to set or collect command callback. Otherwise, call the methods 411*0b57cec5SDimitry Andric // associated with this object. 412*0b57cec5SDimitry Andric if (m_options.m_use_script_language) { 413480093f4SDimitry Andric ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter( 414480093f4SDimitry Andric /*can_create=*/true, m_options.m_script_language); 415*0b57cec5SDimitry Andric // Special handling for one-liner specified inline. 416*0b57cec5SDimitry Andric if (m_options.m_use_one_liner) { 417480093f4SDimitry Andric script_interp->SetWatchpointCommandCallback( 418*0b57cec5SDimitry Andric wp_options, m_options.m_one_liner.c_str()); 419*0b57cec5SDimitry Andric } 420*0b57cec5SDimitry Andric // Special handling for using a Python function by name instead of 421*0b57cec5SDimitry Andric // extending the watchpoint callback data structures, we just 422*0b57cec5SDimitry Andric // automatize what the user would do manually: make their watchpoint 423*0b57cec5SDimitry Andric // command be a function call 424*0b57cec5SDimitry Andric else if (!m_options.m_function_name.empty()) { 425*0b57cec5SDimitry Andric std::string oneliner(m_options.m_function_name); 426*0b57cec5SDimitry Andric oneliner += "(frame, wp, internal_dict)"; 427480093f4SDimitry Andric script_interp->SetWatchpointCommandCallback( 428*0b57cec5SDimitry Andric wp_options, oneliner.c_str()); 429*0b57cec5SDimitry Andric } else { 430480093f4SDimitry Andric script_interp->CollectDataForWatchpointCommandCallback(wp_options, 431480093f4SDimitry Andric result); 432*0b57cec5SDimitry Andric } 433*0b57cec5SDimitry Andric } else { 434*0b57cec5SDimitry Andric // Special handling for one-liner specified inline. 435*0b57cec5SDimitry Andric if (m_options.m_use_one_liner) 436*0b57cec5SDimitry Andric SetWatchpointCommandCallback(wp_options, 437*0b57cec5SDimitry Andric m_options.m_one_liner.c_str()); 438*0b57cec5SDimitry Andric else 439*0b57cec5SDimitry Andric CollectDataForWatchpointCommandCallback(wp_options, result); 440*0b57cec5SDimitry Andric } 441*0b57cec5SDimitry Andric } 442*0b57cec5SDimitry Andric } 443*0b57cec5SDimitry Andric 444*0b57cec5SDimitry Andric return result.Succeeded(); 445*0b57cec5SDimitry Andric } 446*0b57cec5SDimitry Andric 447*0b57cec5SDimitry Andric private: 448*0b57cec5SDimitry Andric CommandOptions m_options; 449*0b57cec5SDimitry Andric }; 450*0b57cec5SDimitry Andric 451*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandDelete 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandDelete : public CommandObjectParsed { 454*0b57cec5SDimitry Andric public: 455*0b57cec5SDimitry Andric CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter) 456*0b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "delete", 457*0b57cec5SDimitry Andric "Delete the set of commands from a watchpoint.", 4589dba64beSDimitry Andric nullptr, eCommandRequiresTarget) { 459*0b57cec5SDimitry Andric CommandArgumentEntry arg; 460*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 463*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 464*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 467*0b57cec5SDimitry Andric // argument entry. 468*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 469*0b57cec5SDimitry Andric 470*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 471*0b57cec5SDimitry Andric m_arguments.push_back(arg); 472*0b57cec5SDimitry Andric } 473*0b57cec5SDimitry Andric 474*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandDelete() override = default; 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric protected: 477*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 4789dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 481*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 484*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist to have commands deleted"); 485*0b57cec5SDimitry Andric return false; 486*0b57cec5SDimitry Andric } 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 489*0b57cec5SDimitry Andric result.AppendError( 490*0b57cec5SDimitry Andric "No watchpoint specified from which to delete the commands"); 491*0b57cec5SDimitry Andric return false; 492*0b57cec5SDimitry Andric } 493*0b57cec5SDimitry Andric 494*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 495*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 496*0b57cec5SDimitry Andric valid_wp_ids)) { 497*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 498*0b57cec5SDimitry Andric return false; 499*0b57cec5SDimitry Andric } 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 502*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 503*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 504*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 505*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 506*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 507*0b57cec5SDimitry Andric if (wp) 508*0b57cec5SDimitry Andric wp->ClearCallback(); 509*0b57cec5SDimitry Andric } else { 510*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 511*0b57cec5SDimitry Andric return false; 512*0b57cec5SDimitry Andric } 513*0b57cec5SDimitry Andric } 514*0b57cec5SDimitry Andric return result.Succeeded(); 515*0b57cec5SDimitry Andric } 516*0b57cec5SDimitry Andric }; 517*0b57cec5SDimitry Andric 518*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandList 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandList : public CommandObjectParsed { 521*0b57cec5SDimitry Andric public: 522*0b57cec5SDimitry Andric CommandObjectWatchpointCommandList(CommandInterpreter &interpreter) 5239dba64beSDimitry Andric : CommandObjectParsed(interpreter, "list", 5249dba64beSDimitry Andric "List the script or set of commands to be executed " 5259dba64beSDimitry Andric "when the watchpoint is hit.", 5269dba64beSDimitry Andric nullptr, eCommandRequiresTarget) { 527*0b57cec5SDimitry Andric CommandArgumentEntry arg; 528*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 529*0b57cec5SDimitry Andric 530*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 531*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 532*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 533*0b57cec5SDimitry Andric 534*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 535*0b57cec5SDimitry Andric // argument entry. 536*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 537*0b57cec5SDimitry Andric 538*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 539*0b57cec5SDimitry Andric m_arguments.push_back(arg); 540*0b57cec5SDimitry Andric } 541*0b57cec5SDimitry Andric 542*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandList() override = default; 543*0b57cec5SDimitry Andric 544*0b57cec5SDimitry Andric protected: 545*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 5469dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 549*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 550*0b57cec5SDimitry Andric 551*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 552*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist for which to list commands"); 553*0b57cec5SDimitry Andric return false; 554*0b57cec5SDimitry Andric } 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 557*0b57cec5SDimitry Andric result.AppendError( 558*0b57cec5SDimitry Andric "No watchpoint specified for which to list the commands"); 559*0b57cec5SDimitry Andric return false; 560*0b57cec5SDimitry Andric } 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 563*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 564*0b57cec5SDimitry Andric valid_wp_ids)) { 565*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 566*0b57cec5SDimitry Andric return false; 567*0b57cec5SDimitry Andric } 568*0b57cec5SDimitry Andric 569*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 570*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 571*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 572*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 573*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 574*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 575*0b57cec5SDimitry Andric 576*0b57cec5SDimitry Andric if (wp) { 577*0b57cec5SDimitry Andric const WatchpointOptions *wp_options = wp->GetOptions(); 578*0b57cec5SDimitry Andric if (wp_options) { 579*0b57cec5SDimitry Andric // Get the callback baton associated with the current watchpoint. 580*0b57cec5SDimitry Andric const Baton *baton = wp_options->GetBaton(); 581*0b57cec5SDimitry Andric if (baton) { 582*0b57cec5SDimitry Andric result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id); 583480093f4SDimitry Andric baton->GetDescription(result.GetOutputStream().AsRawOstream(), 584480093f4SDimitry Andric eDescriptionLevelFull, 585480093f4SDimitry Andric result.GetOutputStream().GetIndentLevel() + 586480093f4SDimitry Andric 2); 587*0b57cec5SDimitry Andric } else { 588*0b57cec5SDimitry Andric result.AppendMessageWithFormat( 589*0b57cec5SDimitry Andric "Watchpoint %u does not have an associated command.\n", 590*0b57cec5SDimitry Andric cur_wp_id); 591*0b57cec5SDimitry Andric } 592*0b57cec5SDimitry Andric } 593*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 594*0b57cec5SDimitry Andric } else { 595*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 596*0b57cec5SDimitry Andric cur_wp_id); 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric } 599*0b57cec5SDimitry Andric } 600*0b57cec5SDimitry Andric 601*0b57cec5SDimitry Andric return result.Succeeded(); 602*0b57cec5SDimitry Andric } 603*0b57cec5SDimitry Andric }; 604*0b57cec5SDimitry Andric 605*0b57cec5SDimitry Andric // CommandObjectWatchpointCommand 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::CommandObjectWatchpointCommand( 608*0b57cec5SDimitry Andric CommandInterpreter &interpreter) 609*0b57cec5SDimitry Andric : CommandObjectMultiword( 610*0b57cec5SDimitry Andric interpreter, "command", 611*0b57cec5SDimitry Andric "Commands for adding, removing and examining LLDB commands " 612*0b57cec5SDimitry Andric "executed when the watchpoint is hit (watchpoint 'commands').", 613*0b57cec5SDimitry Andric "command <sub-command> [<sub-command-options>] <watchpoint-id>") { 614*0b57cec5SDimitry Andric CommandObjectSP add_command_object( 615*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandAdd(interpreter)); 616*0b57cec5SDimitry Andric CommandObjectSP delete_command_object( 617*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandDelete(interpreter)); 618*0b57cec5SDimitry Andric CommandObjectSP list_command_object( 619*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandList(interpreter)); 620*0b57cec5SDimitry Andric 621*0b57cec5SDimitry Andric add_command_object->SetCommandName("watchpoint command add"); 622*0b57cec5SDimitry Andric delete_command_object->SetCommandName("watchpoint command delete"); 623*0b57cec5SDimitry Andric list_command_object->SetCommandName("watchpoint command list"); 624*0b57cec5SDimitry Andric 625*0b57cec5SDimitry Andric LoadSubCommand("add", add_command_object); 626*0b57cec5SDimitry Andric LoadSubCommand("delete", delete_command_object); 627*0b57cec5SDimitry Andric LoadSubCommand("list", list_command_object); 628*0b57cec5SDimitry Andric } 629*0b57cec5SDimitry Andric 630*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default; 631