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