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" 18*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 19*0b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 20*0b57cec5SDimitry Andric #include "lldb/Target/Target.h" 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric using namespace lldb; 23*0b57cec5SDimitry Andric using namespace lldb_private; 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric // FIXME: "script-type" needs to have its contents determined dynamically, so 269dba64beSDimitry Andric // somebody can add a new scripting language to lldb and have it pickable here 279dba64beSDimitry Andric // without having to change this enumeration by hand and rebuild lldb proper. 28*0b57cec5SDimitry Andric static constexpr OptionEnumValueElement g_script_option_enumeration[] = { 299dba64beSDimitry Andric { 309dba64beSDimitry Andric eScriptLanguageNone, 319dba64beSDimitry Andric "command", 329dba64beSDimitry Andric "Commands are in the lldb command interpreter language", 339dba64beSDimitry Andric }, 349dba64beSDimitry Andric { 359dba64beSDimitry Andric eScriptLanguagePython, 369dba64beSDimitry Andric "python", 379dba64beSDimitry Andric "Commands are in the Python language.", 389dba64beSDimitry Andric }, 399dba64beSDimitry Andric { 40480093f4SDimitry Andric eScriptLanguageLua, 41480093f4SDimitry Andric "lua", 425ffd83dbSDimitry Andric "Commands are in the Lua language.", 43480093f4SDimitry Andric }, 44480093f4SDimitry Andric { 459dba64beSDimitry Andric eSortOrderByName, 469dba64beSDimitry Andric "default-script", 479dba64beSDimitry Andric "Commands are in the default scripting language.", 489dba64beSDimitry Andric }, 499dba64beSDimitry Andric }; 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric static constexpr OptionEnumValues ScriptOptionEnum() { 52*0b57cec5SDimitry Andric return OptionEnumValues(g_script_option_enumeration); 53*0b57cec5SDimitry Andric } 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric #define LLDB_OPTIONS_watchpoint_command_add 56*0b57cec5SDimitry Andric #include "CommandOptions.inc" 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandAdd : public CommandObjectParsed, 59*0b57cec5SDimitry Andric public IOHandlerDelegateMultiline { 60*0b57cec5SDimitry Andric public: 61*0b57cec5SDimitry Andric CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter) 62*0b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "add", 63*0b57cec5SDimitry Andric "Add a set of LLDB commands to a watchpoint, to be " 64fe6060f1SDimitry Andric "executed whenever the watchpoint is hit. " 65fe6060f1SDimitry Andric "The commands added to the watchpoint replace any " 66fe6060f1SDimitry Andric "commands previously added to it.", 679dba64beSDimitry Andric nullptr, eCommandRequiresTarget), 68*0b57cec5SDimitry Andric IOHandlerDelegateMultiline("DONE", 6904eeddc0SDimitry Andric IOHandlerDelegate::Completion::LLDBCommand) { 70*0b57cec5SDimitry Andric SetHelpLong( 71*0b57cec5SDimitry Andric R"( 72*0b57cec5SDimitry Andric General information about entering watchpoint commands 73*0b57cec5SDimitry Andric ------------------------------------------------------ 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric )" 76*0b57cec5SDimitry Andric "This command will prompt for commands to be executed when the specified \ 77*0b57cec5SDimitry Andric watchpoint is hit. Each command is typed on its own line following the '> ' \ 78*0b57cec5SDimitry Andric prompt until 'DONE' is entered." 79*0b57cec5SDimitry Andric R"( 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric )" 82*0b57cec5SDimitry Andric "Syntactic errors may not be detected when initially entered, and many \ 83*0b57cec5SDimitry Andric malformed commands can silently fail when executed. If your watchpoint commands \ 84*0b57cec5SDimitry Andric do not appear to be executing, double-check the command syntax." 85*0b57cec5SDimitry Andric R"( 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric )" 88*0b57cec5SDimitry Andric "Note: You may enter any debugger command exactly as you would at the debugger \ 89*0b57cec5SDimitry Andric prompt. There is no limit to the number of commands supplied, but do NOT enter \ 90*0b57cec5SDimitry Andric more than one command per line." 91*0b57cec5SDimitry Andric R"( 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric Special information about PYTHON watchpoint commands 94*0b57cec5SDimitry Andric ---------------------------------------------------- 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric )" 97*0b57cec5SDimitry Andric "You may enter either one or more lines of Python, including function \ 98*0b57cec5SDimitry Andric definitions or calls to functions that will have been imported by the time \ 99*0b57cec5SDimitry Andric the code executes. Single line watchpoint commands will be interpreted 'as is' \ 100*0b57cec5SDimitry Andric when the watchpoint is hit. Multiple lines of Python will be wrapped in a \ 101*0b57cec5SDimitry Andric generated function, and a call to the function will be attached to the watchpoint." 102*0b57cec5SDimitry Andric R"( 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric This auto-generated function is passed in three arguments: 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric frame: an lldb.SBFrame object for the frame which hit the watchpoint. 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric wp: the watchpoint that was hit. 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric )" 111*0b57cec5SDimitry Andric "When specifying a python function with the --python-function option, you need \ 112*0b57cec5SDimitry Andric to supply the function name prepended by the module name:" 113*0b57cec5SDimitry Andric R"( 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric --python-function myutils.watchpoint_callback 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric The function itself must have the following prototype: 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric def watchpoint_callback(frame, wp): 120*0b57cec5SDimitry Andric # Your code goes here 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric )" 123*0b57cec5SDimitry Andric "The arguments are the same as the arguments passed to generated functions as \ 124*0b57cec5SDimitry Andric described above. Note that the global variable 'lldb.frame' will NOT be updated when \ 125*0b57cec5SDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ 126*0b57cec5SDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \ 127*0b57cec5SDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \ 128*0b57cec5SDimitry Andric via process.GetTarget()." 129*0b57cec5SDimitry Andric R"( 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric )" 132*0b57cec5SDimitry Andric "Important Note: As Python code gets collected into functions, access to global \ 133*0b57cec5SDimitry Andric variables requires explicit scoping using the 'global' keyword. Be sure to use correct \ 134*0b57cec5SDimitry Andric Python syntax, including indentation, when entering Python watchpoint commands." 135*0b57cec5SDimitry Andric R"( 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric Example Python one-line watchpoint command: 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 140*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 141*0b57cec5SDimitry Andric > print "Hit this watchpoint!" 142*0b57cec5SDimitry Andric > DONE 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric As a convenience, this also works for a short Python one-liner: 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()' 147*0b57cec5SDimitry Andric (lldb) run 148*0b57cec5SDimitry Andric Launching '.../a.out' (x86_64) 149*0b57cec5SDimitry Andric (lldb) Fri Sep 10 12:17:45 2010 150*0b57cec5SDimitry Andric Process 21778 Stopped 151*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 152*0b57cec5SDimitry Andric 36 153*0b57cec5SDimitry Andric 37 int c(int val) 154*0b57cec5SDimitry Andric 38 { 155*0b57cec5SDimitry Andric 39 -> return val + 3; 156*0b57cec5SDimitry Andric 40 } 157*0b57cec5SDimitry Andric 41 158*0b57cec5SDimitry Andric 42 int main (int argc, char const *argv[]) 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using function definition: 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 163*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 164*0b57cec5SDimitry Andric > def watchpoint_output (wp_no): 165*0b57cec5SDimitry Andric > out_string = "Hit watchpoint number " + repr (wp_no) 166*0b57cec5SDimitry Andric > print out_string 167*0b57cec5SDimitry Andric > return True 168*0b57cec5SDimitry Andric > watchpoint_output (1) 169*0b57cec5SDimitry Andric > DONE 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using 'loose' Python: 172*0b57cec5SDimitry Andric 173*0b57cec5SDimitry Andric (lldb) watchpoint command add -s p 1 174*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end. 175*0b57cec5SDimitry Andric > global wp_count 176*0b57cec5SDimitry Andric > wp_count = wp_count + 1 177*0b57cec5SDimitry Andric > print "Hit this watchpoint " + repr(wp_count) + " times!" 178*0b57cec5SDimitry Andric > DONE 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric )" 181*0b57cec5SDimitry Andric "In this case, since there is a reference to a global variable, \ 182*0b57cec5SDimitry Andric 'wp_count', you will also need to make sure 'wp_count' exists and is \ 183*0b57cec5SDimitry Andric initialized:" 184*0b57cec5SDimitry Andric R"( 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric (lldb) script 187*0b57cec5SDimitry Andric >>> wp_count = 0 188*0b57cec5SDimitry Andric >>> quit() 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric )" 191*0b57cec5SDimitry Andric "Final Note: A warning that no watchpoint command was generated when there \ 192*0b57cec5SDimitry Andric are no syntax errors may indicate that a function was declared but never called."); 193*0b57cec5SDimitry Andric 194*0b57cec5SDimitry Andric CommandArgumentEntry arg; 195*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 198*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 199*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 202*0b57cec5SDimitry Andric // argument entry. 203*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 206*0b57cec5SDimitry Andric m_arguments.push_back(arg); 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandAdd() override = default; 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 2149dba64beSDimitry Andric StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 215*0b57cec5SDimitry Andric if (output_sp && interactive) { 216*0b57cec5SDimitry Andric output_sp->PutCString( 217*0b57cec5SDimitry Andric "Enter your debugger command(s). Type 'DONE' to end.\n"); 218*0b57cec5SDimitry Andric output_sp->Flush(); 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 223*0b57cec5SDimitry Andric std::string &line) override { 224*0b57cec5SDimitry Andric io_handler.SetIsDone(true); 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric // The WatchpointOptions object is owned by the watchpoint or watchpoint 227*0b57cec5SDimitry Andric // location 228*0b57cec5SDimitry Andric WatchpointOptions *wp_options = 229*0b57cec5SDimitry Andric (WatchpointOptions *)io_handler.GetUserData(); 230*0b57cec5SDimitry Andric if (wp_options) { 231*0b57cec5SDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_up( 232*0b57cec5SDimitry Andric new WatchpointOptions::CommandData()); 233*0b57cec5SDimitry Andric if (data_up) { 234*0b57cec5SDimitry Andric data_up->user_source.SplitIntoLines(line); 235*0b57cec5SDimitry Andric auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>( 236*0b57cec5SDimitry Andric std::move(data_up)); 237*0b57cec5SDimitry Andric wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 238*0b57cec5SDimitry Andric } 239*0b57cec5SDimitry Andric } 240*0b57cec5SDimitry Andric } 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, 243*0b57cec5SDimitry Andric CommandReturnObject &result) { 244*0b57cec5SDimitry Andric m_interpreter.GetLLDBCommandsFromIOHandler( 245*0b57cec5SDimitry Andric "> ", // Prompt 246*0b57cec5SDimitry Andric *this, // IOHandlerDelegate 247*0b57cec5SDimitry Andric wp_options); // Baton for the "io_handler" that will be passed back into 248*0b57cec5SDimitry Andric // our IOHandlerDelegate functions 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric /// Set a one-liner as the callback for the watchpoint. 252*0b57cec5SDimitry Andric void SetWatchpointCommandCallback(WatchpointOptions *wp_options, 253*0b57cec5SDimitry Andric const char *oneliner) { 254*0b57cec5SDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_up( 255*0b57cec5SDimitry Andric new WatchpointOptions::CommandData()); 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric // It's necessary to set both user_source and script_source to the 258*0b57cec5SDimitry Andric // oneliner. The former is used to generate callback description (as in 259*0b57cec5SDimitry Andric // watchpoint command list) while the latter is used for Python to 260*0b57cec5SDimitry Andric // interpret during the actual callback. 261*0b57cec5SDimitry Andric data_up->user_source.AppendString(oneliner); 262*0b57cec5SDimitry Andric data_up->script_source.assign(oneliner); 263*0b57cec5SDimitry Andric data_up->stop_on_error = m_options.m_stop_on_error; 264*0b57cec5SDimitry Andric 265*0b57cec5SDimitry Andric auto baton_sp = 266*0b57cec5SDimitry Andric std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up)); 267*0b57cec5SDimitry Andric wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp); 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric static bool 271*0b57cec5SDimitry Andric WatchpointOptionsCallbackFunction(void *baton, 272*0b57cec5SDimitry Andric StoppointCallbackContext *context, 273*0b57cec5SDimitry Andric lldb::user_id_t watch_id) { 274*0b57cec5SDimitry Andric bool ret_value = true; 275*0b57cec5SDimitry Andric if (baton == nullptr) 276*0b57cec5SDimitry Andric return true; 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric WatchpointOptions::CommandData *data = 279*0b57cec5SDimitry Andric (WatchpointOptions::CommandData *)baton; 280*0b57cec5SDimitry Andric StringList &commands = data->user_source; 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric if (commands.GetSize() > 0) { 283*0b57cec5SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 284*0b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 285*0b57cec5SDimitry Andric if (target) { 286*0b57cec5SDimitry Andric Debugger &debugger = target->GetDebugger(); 2875ffd83dbSDimitry Andric CommandReturnObject result(debugger.GetUseColor()); 2885ffd83dbSDimitry Andric 289*0b57cec5SDimitry Andric // Rig up the results secondary output stream to the debugger's, so the 290*0b57cec5SDimitry Andric // output will come out synchronously if the debugger is set up that 291*0b57cec5SDimitry Andric // way. 292*0b57cec5SDimitry Andric StreamSP output_stream(debugger.GetAsyncOutputStream()); 293*0b57cec5SDimitry Andric StreamSP error_stream(debugger.GetAsyncErrorStream()); 294*0b57cec5SDimitry Andric result.SetImmediateOutputStream(output_stream); 295*0b57cec5SDimitry Andric result.SetImmediateErrorStream(error_stream); 296*0b57cec5SDimitry Andric 297*0b57cec5SDimitry Andric CommandInterpreterRunOptions options; 298*0b57cec5SDimitry Andric options.SetStopOnContinue(true); 299*0b57cec5SDimitry Andric options.SetStopOnError(data->stop_on_error); 300*0b57cec5SDimitry Andric options.SetEchoCommands(false); 301*0b57cec5SDimitry Andric options.SetPrintResults(true); 302*0b57cec5SDimitry Andric options.SetPrintErrors(true); 303*0b57cec5SDimitry Andric options.SetAddToHistory(false); 304*0b57cec5SDimitry Andric 305fe6060f1SDimitry Andric debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx, 306*0b57cec5SDimitry Andric options, result); 307*0b57cec5SDimitry Andric result.GetImmediateOutputStream()->Flush(); 308*0b57cec5SDimitry Andric result.GetImmediateErrorStream()->Flush(); 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric } 311*0b57cec5SDimitry Andric return ret_value; 312*0b57cec5SDimitry Andric } 313*0b57cec5SDimitry Andric 314*0b57cec5SDimitry Andric class CommandOptions : public Options { 315*0b57cec5SDimitry Andric public: 31604eeddc0SDimitry Andric CommandOptions() {} 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric ~CommandOptions() override = default; 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 321*0b57cec5SDimitry Andric ExecutionContext *execution_context) override { 322*0b57cec5SDimitry Andric Status error; 323*0b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 324*0b57cec5SDimitry Andric 325*0b57cec5SDimitry Andric switch (short_option) { 326*0b57cec5SDimitry Andric case 'o': 327*0b57cec5SDimitry Andric m_use_one_liner = true; 3285ffd83dbSDimitry Andric m_one_liner = std::string(option_arg); 329*0b57cec5SDimitry Andric break; 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric case 's': 332*0b57cec5SDimitry Andric m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( 333*0b57cec5SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 334*0b57cec5SDimitry Andric eScriptLanguageNone, error); 335*0b57cec5SDimitry Andric 336480093f4SDimitry Andric switch (m_script_language) { 337480093f4SDimitry Andric case eScriptLanguagePython: 338480093f4SDimitry Andric case eScriptLanguageLua: 339480093f4SDimitry Andric m_use_script_language = true; 340480093f4SDimitry Andric break; 341480093f4SDimitry Andric case eScriptLanguageNone: 342480093f4SDimitry Andric case eScriptLanguageUnknown: 343480093f4SDimitry Andric m_use_script_language = false; 344480093f4SDimitry Andric break; 345480093f4SDimitry Andric } 346*0b57cec5SDimitry Andric break; 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric case 'e': { 349*0b57cec5SDimitry Andric bool success = false; 350*0b57cec5SDimitry Andric m_stop_on_error = 351*0b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success); 352*0b57cec5SDimitry Andric if (!success) 353*0b57cec5SDimitry Andric error.SetErrorStringWithFormat( 354*0b57cec5SDimitry Andric "invalid value for stop-on-error: \"%s\"", 355*0b57cec5SDimitry Andric option_arg.str().c_str()); 356*0b57cec5SDimitry Andric } break; 357*0b57cec5SDimitry Andric 358*0b57cec5SDimitry Andric case 'F': 359*0b57cec5SDimitry Andric m_use_one_liner = false; 3605ffd83dbSDimitry Andric m_function_name.assign(std::string(option_arg)); 361*0b57cec5SDimitry Andric break; 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric default: 3649dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric return error; 367*0b57cec5SDimitry Andric } 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 370*0b57cec5SDimitry Andric m_use_commands = true; 371*0b57cec5SDimitry Andric m_use_script_language = false; 372*0b57cec5SDimitry Andric m_script_language = eScriptLanguageNone; 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric m_use_one_liner = false; 375*0b57cec5SDimitry Andric m_stop_on_error = true; 376*0b57cec5SDimitry Andric m_one_liner.clear(); 377*0b57cec5SDimitry Andric m_function_name.clear(); 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 381*0b57cec5SDimitry Andric return llvm::makeArrayRef(g_watchpoint_command_add_options); 382*0b57cec5SDimitry Andric } 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric // Instance variables to hold the values for command options. 385*0b57cec5SDimitry Andric 386fe6060f1SDimitry Andric bool m_use_commands = false; 387fe6060f1SDimitry Andric bool m_use_script_language = false; 388fe6060f1SDimitry Andric lldb::ScriptLanguage m_script_language = eScriptLanguageNone; 389*0b57cec5SDimitry Andric 390*0b57cec5SDimitry Andric // Instance variables to hold the values for one_liner options. 391fe6060f1SDimitry Andric bool m_use_one_liner = false; 392*0b57cec5SDimitry Andric std::string m_one_liner; 393*0b57cec5SDimitry Andric bool m_stop_on_error; 394*0b57cec5SDimitry Andric std::string m_function_name; 395*0b57cec5SDimitry Andric }; 396*0b57cec5SDimitry Andric 397*0b57cec5SDimitry Andric protected: 398*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 3999dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 402*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 405*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist to have commands added"); 406*0b57cec5SDimitry Andric return false; 407*0b57cec5SDimitry Andric } 408*0b57cec5SDimitry Andric 409480093f4SDimitry Andric if (!m_options.m_function_name.empty()) { 410480093f4SDimitry Andric if (!m_options.m_use_script_language) { 411480093f4SDimitry Andric m_options.m_script_language = GetDebugger().GetScriptLanguage(); 412480093f4SDimitry Andric m_options.m_use_script_language = true; 413480093f4SDimitry Andric } 414*0b57cec5SDimitry Andric } 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 417*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 418*0b57cec5SDimitry Andric valid_wp_ids)) { 419*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 420*0b57cec5SDimitry Andric return false; 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric 423*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 424*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 425*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 426*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 427*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 428*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 429*0b57cec5SDimitry Andric // Sanity check wp first. 430*0b57cec5SDimitry Andric if (wp == nullptr) 431*0b57cec5SDimitry Andric continue; 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric WatchpointOptions *wp_options = wp->GetOptions(); 434*0b57cec5SDimitry Andric // Skip this watchpoint if wp_options is not good. 435*0b57cec5SDimitry Andric if (wp_options == nullptr) 436*0b57cec5SDimitry Andric continue; 437*0b57cec5SDimitry Andric 438*0b57cec5SDimitry Andric // If we are using script language, get the script interpreter in order 439*0b57cec5SDimitry Andric // to set or collect command callback. Otherwise, call the methods 440*0b57cec5SDimitry Andric // associated with this object. 441*0b57cec5SDimitry Andric if (m_options.m_use_script_language) { 442480093f4SDimitry Andric ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter( 443480093f4SDimitry Andric /*can_create=*/true, m_options.m_script_language); 444*0b57cec5SDimitry Andric // Special handling for one-liner specified inline. 445*0b57cec5SDimitry Andric if (m_options.m_use_one_liner) { 446480093f4SDimitry Andric script_interp->SetWatchpointCommandCallback( 447*0b57cec5SDimitry Andric wp_options, m_options.m_one_liner.c_str()); 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric // Special handling for using a Python function by name instead of 450*0b57cec5SDimitry Andric // extending the watchpoint callback data structures, we just 451*0b57cec5SDimitry Andric // automatize what the user would do manually: make their watchpoint 452*0b57cec5SDimitry Andric // command be a function call 453*0b57cec5SDimitry Andric else if (!m_options.m_function_name.empty()) { 454*0b57cec5SDimitry Andric std::string oneliner(m_options.m_function_name); 455*0b57cec5SDimitry Andric oneliner += "(frame, wp, internal_dict)"; 456480093f4SDimitry Andric script_interp->SetWatchpointCommandCallback( 457*0b57cec5SDimitry Andric wp_options, oneliner.c_str()); 458*0b57cec5SDimitry Andric } else { 459480093f4SDimitry Andric script_interp->CollectDataForWatchpointCommandCallback(wp_options, 460480093f4SDimitry Andric result); 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric } else { 463*0b57cec5SDimitry Andric // Special handling for one-liner specified inline. 464*0b57cec5SDimitry Andric if (m_options.m_use_one_liner) 465*0b57cec5SDimitry Andric SetWatchpointCommandCallback(wp_options, 466*0b57cec5SDimitry Andric m_options.m_one_liner.c_str()); 467*0b57cec5SDimitry Andric else 468*0b57cec5SDimitry Andric CollectDataForWatchpointCommandCallback(wp_options, result); 469*0b57cec5SDimitry Andric } 470*0b57cec5SDimitry Andric } 471*0b57cec5SDimitry Andric } 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric return result.Succeeded(); 474*0b57cec5SDimitry Andric } 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric private: 477*0b57cec5SDimitry Andric CommandOptions m_options; 478*0b57cec5SDimitry Andric }; 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandDelete 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandDelete : public CommandObjectParsed { 483*0b57cec5SDimitry Andric public: 484*0b57cec5SDimitry Andric CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter) 485*0b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "delete", 486*0b57cec5SDimitry Andric "Delete the set of commands from a watchpoint.", 4879dba64beSDimitry Andric nullptr, eCommandRequiresTarget) { 488*0b57cec5SDimitry Andric CommandArgumentEntry arg; 489*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 490*0b57cec5SDimitry Andric 491*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 492*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 493*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 494*0b57cec5SDimitry Andric 495*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 496*0b57cec5SDimitry Andric // argument entry. 497*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 498*0b57cec5SDimitry Andric 499*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 500*0b57cec5SDimitry Andric m_arguments.push_back(arg); 501*0b57cec5SDimitry Andric } 502*0b57cec5SDimitry Andric 503*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandDelete() override = default; 504*0b57cec5SDimitry Andric 505*0b57cec5SDimitry Andric protected: 506*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 5079dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 508*0b57cec5SDimitry Andric 509*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 510*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 511*0b57cec5SDimitry Andric 512*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 513*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist to have commands deleted"); 514*0b57cec5SDimitry Andric return false; 515*0b57cec5SDimitry Andric } 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 518*0b57cec5SDimitry Andric result.AppendError( 519*0b57cec5SDimitry Andric "No watchpoint specified from which to delete the commands"); 520*0b57cec5SDimitry Andric return false; 521*0b57cec5SDimitry Andric } 522*0b57cec5SDimitry Andric 523*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 524*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 525*0b57cec5SDimitry Andric valid_wp_ids)) { 526*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 527*0b57cec5SDimitry Andric return false; 528*0b57cec5SDimitry Andric } 529*0b57cec5SDimitry Andric 530*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 531*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 532*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 533*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 534*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 535*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 536*0b57cec5SDimitry Andric if (wp) 537*0b57cec5SDimitry Andric wp->ClearCallback(); 538*0b57cec5SDimitry Andric } else { 539*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 540*0b57cec5SDimitry Andric return false; 541*0b57cec5SDimitry Andric } 542*0b57cec5SDimitry Andric } 543*0b57cec5SDimitry Andric return result.Succeeded(); 544*0b57cec5SDimitry Andric } 545*0b57cec5SDimitry Andric }; 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandList 548*0b57cec5SDimitry Andric 549*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandList : public CommandObjectParsed { 550*0b57cec5SDimitry Andric public: 551*0b57cec5SDimitry Andric CommandObjectWatchpointCommandList(CommandInterpreter &interpreter) 5529dba64beSDimitry Andric : CommandObjectParsed(interpreter, "list", 5539dba64beSDimitry Andric "List the script or set of commands to be executed " 5549dba64beSDimitry Andric "when the watchpoint is hit.", 5559dba64beSDimitry Andric nullptr, eCommandRequiresTarget) { 556*0b57cec5SDimitry Andric CommandArgumentEntry arg; 557*0b57cec5SDimitry Andric CommandArgumentData wp_id_arg; 558*0b57cec5SDimitry Andric 559*0b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 560*0b57cec5SDimitry Andric wp_id_arg.arg_type = eArgTypeWatchpointID; 561*0b57cec5SDimitry Andric wp_id_arg.arg_repetition = eArgRepeatPlain; 562*0b57cec5SDimitry Andric 563*0b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 564*0b57cec5SDimitry Andric // argument entry. 565*0b57cec5SDimitry Andric arg.push_back(wp_id_arg); 566*0b57cec5SDimitry Andric 567*0b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 568*0b57cec5SDimitry Andric m_arguments.push_back(arg); 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric 571*0b57cec5SDimitry Andric ~CommandObjectWatchpointCommandList() override = default; 572*0b57cec5SDimitry Andric 573*0b57cec5SDimitry Andric protected: 574*0b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 5759dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 576*0b57cec5SDimitry Andric 577*0b57cec5SDimitry Andric const WatchpointList &watchpoints = target->GetWatchpointList(); 578*0b57cec5SDimitry Andric size_t num_watchpoints = watchpoints.GetSize(); 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric if (num_watchpoints == 0) { 581*0b57cec5SDimitry Andric result.AppendError("No watchpoints exist for which to list commands"); 582*0b57cec5SDimitry Andric return false; 583*0b57cec5SDimitry Andric } 584*0b57cec5SDimitry Andric 585*0b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 586*0b57cec5SDimitry Andric result.AppendError( 587*0b57cec5SDimitry Andric "No watchpoint specified for which to list the commands"); 588*0b57cec5SDimitry Andric return false; 589*0b57cec5SDimitry Andric } 590*0b57cec5SDimitry Andric 591*0b57cec5SDimitry Andric std::vector<uint32_t> valid_wp_ids; 592*0b57cec5SDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, 593*0b57cec5SDimitry Andric valid_wp_ids)) { 594*0b57cec5SDimitry Andric result.AppendError("Invalid watchpoints specification."); 595*0b57cec5SDimitry Andric return false; 596*0b57cec5SDimitry Andric } 597*0b57cec5SDimitry Andric 598*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 599*0b57cec5SDimitry Andric const size_t count = valid_wp_ids.size(); 600*0b57cec5SDimitry Andric for (size_t i = 0; i < count; ++i) { 601*0b57cec5SDimitry Andric uint32_t cur_wp_id = valid_wp_ids.at(i); 602*0b57cec5SDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) { 603*0b57cec5SDimitry Andric Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get(); 604*0b57cec5SDimitry Andric 605*0b57cec5SDimitry Andric if (wp) { 606*0b57cec5SDimitry Andric const WatchpointOptions *wp_options = wp->GetOptions(); 607*0b57cec5SDimitry Andric if (wp_options) { 608*0b57cec5SDimitry Andric // Get the callback baton associated with the current watchpoint. 609*0b57cec5SDimitry Andric const Baton *baton = wp_options->GetBaton(); 610*0b57cec5SDimitry Andric if (baton) { 611*0b57cec5SDimitry Andric result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id); 612480093f4SDimitry Andric baton->GetDescription(result.GetOutputStream().AsRawOstream(), 613480093f4SDimitry Andric eDescriptionLevelFull, 614480093f4SDimitry Andric result.GetOutputStream().GetIndentLevel() + 615480093f4SDimitry Andric 2); 616*0b57cec5SDimitry Andric } else { 617*0b57cec5SDimitry Andric result.AppendMessageWithFormat( 618*0b57cec5SDimitry Andric "Watchpoint %u does not have an associated command.\n", 619*0b57cec5SDimitry Andric cur_wp_id); 620*0b57cec5SDimitry Andric } 621*0b57cec5SDimitry Andric } 622*0b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 623*0b57cec5SDimitry Andric } else { 624*0b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 625*0b57cec5SDimitry Andric cur_wp_id); 626*0b57cec5SDimitry Andric } 627*0b57cec5SDimitry Andric } 628*0b57cec5SDimitry Andric } 629*0b57cec5SDimitry Andric 630*0b57cec5SDimitry Andric return result.Succeeded(); 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric }; 633*0b57cec5SDimitry Andric 634*0b57cec5SDimitry Andric // CommandObjectWatchpointCommand 635*0b57cec5SDimitry Andric 636*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::CommandObjectWatchpointCommand( 637*0b57cec5SDimitry Andric CommandInterpreter &interpreter) 638*0b57cec5SDimitry Andric : CommandObjectMultiword( 639*0b57cec5SDimitry Andric interpreter, "command", 640*0b57cec5SDimitry Andric "Commands for adding, removing and examining LLDB commands " 641*0b57cec5SDimitry Andric "executed when the watchpoint is hit (watchpoint 'commands').", 642*0b57cec5SDimitry Andric "command <sub-command> [<sub-command-options>] <watchpoint-id>") { 643*0b57cec5SDimitry Andric CommandObjectSP add_command_object( 644*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandAdd(interpreter)); 645*0b57cec5SDimitry Andric CommandObjectSP delete_command_object( 646*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandDelete(interpreter)); 647*0b57cec5SDimitry Andric CommandObjectSP list_command_object( 648*0b57cec5SDimitry Andric new CommandObjectWatchpointCommandList(interpreter)); 649*0b57cec5SDimitry Andric 650*0b57cec5SDimitry Andric add_command_object->SetCommandName("watchpoint command add"); 651*0b57cec5SDimitry Andric delete_command_object->SetCommandName("watchpoint command delete"); 652*0b57cec5SDimitry Andric list_command_object->SetCommandName("watchpoint command list"); 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric LoadSubCommand("add", add_command_object); 655*0b57cec5SDimitry Andric LoadSubCommand("delete", delete_command_object); 656*0b57cec5SDimitry Andric LoadSubCommand("list", list_command_object); 657*0b57cec5SDimitry Andric } 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default; 660