1254721Semaste//===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10254721Semaste#include "lldb/lldb-python.h" 11254721Semaste 12254721Semaste// C Includes 13254721Semaste// C++ Includes 14254721Semaste 15254721Semaste 16254721Semaste#include "CommandObjectWatchpointCommand.h" 17254721Semaste#include "CommandObjectWatchpoint.h" 18254721Semaste 19254721Semaste#include "lldb/Interpreter/CommandInterpreter.h" 20254721Semaste#include "lldb/Interpreter/CommandReturnObject.h" 21254721Semaste#include "lldb/Target/Target.h" 22254721Semaste#include "lldb/Target/Thread.h" 23254721Semaste#include "lldb/Breakpoint/Watchpoint.h" 24254721Semaste#include "lldb/Breakpoint/StoppointCallbackContext.h" 25254721Semaste#include "lldb/Core/State.h" 26254721Semaste 27254721Semaste#include <vector> 28254721Semaste 29254721Semasteusing namespace lldb; 30254721Semasteusing namespace lldb_private; 31254721Semaste 32254721Semaste//------------------------------------------------------------------------- 33254721Semaste// CommandObjectWatchpointCommandAdd 34254721Semaste//------------------------------------------------------------------------- 35254721Semaste 36254721Semaste 37254721Semasteclass CommandObjectWatchpointCommandAdd : public CommandObjectParsed 38254721Semaste{ 39254721Semastepublic: 40254721Semaste 41254721Semaste CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) : 42254721Semaste CommandObjectParsed (interpreter, 43254721Semaste "add", 44254721Semaste "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.", 45254721Semaste NULL), 46254721Semaste m_options (interpreter) 47254721Semaste { 48254721Semaste SetHelpLong ( 49254721Semaste"\nGeneral information about entering watchpoint commands \n\ 50254721Semaste------------------------------------------------------ \n\ 51254721Semaste \n\ 52254721SemasteThis command will cause you to be prompted to enter the command or set \n\ 53254721Semasteof commands you wish to be executed when the specified watchpoint is \n\ 54254721Semastehit. You will be told to enter your command(s), and will see a '> ' \n\ 55254721Semasteprompt. Because you can enter one or many commands to be executed when \n\ 56254721Semastea watchpoint is hit, you will continue to be prompted after each \n\ 57254721Semastenew-line that you enter, until you enter the word 'DONE', which will \n\ 58254721Semastecause the commands you have entered to be stored with the watchpoint \n\ 59254721Semasteand executed when the watchpoint is hit. \n\ 60254721Semaste \n\ 61254721SemasteSyntax checking is not necessarily done when watchpoint commands are \n\ 62254721Semasteentered. An improperly written watchpoint command will attempt to get \n\ 63254721Semasteexecuted when the watchpoint gets hit, and usually silently fail. If \n\ 64254721Semasteyour watchpoint command does not appear to be getting executed, go \n\ 65254721Semasteback and check your syntax. \n\ 66254721Semaste \n\ 67254721Semaste \n\ 68254721SemasteSpecial information about PYTHON watchpoint commands \n\ 69254721Semaste---------------------------------------------------- \n\ 70254721Semaste \n\ 71254721SemasteYou may enter either one line of Python or multiple lines of Python \n\ 72254721Semaste(including defining whole functions, if desired). If you enter a \n\ 73254721Semastesingle line of Python, that will be passed to the Python interpreter \n\ 74254721Semaste'as is' when the watchpoint gets hit. If you enter function \n\ 75254721Semastedefinitions, they will be passed to the Python interpreter as soon as \n\ 76254721Semasteyou finish entering the watchpoint command, and they can be called \n\ 77254721Semastelater (don't forget to add calls to them, if you want them called when \n\ 78254721Semastethe watchpoint is hit). If you enter multiple lines of Python that \n\ 79254721Semasteare not function definitions, they will be collected into a new, \n\ 80254721Semasteautomatically generated Python function, and a call to the newly \n\ 81254721Semastegenerated function will be attached to the watchpoint. \n\ 82254721Semaste \n\ 83254721SemasteThis auto-generated function is passed in two arguments: \n\ 84254721Semaste \n\ 85254721Semaste frame: an SBFrame object representing the frame which hit the watchpoint. \n\ 86254721Semaste From the frame you can get back to the thread and process. \n\ 87254721Semaste wp: the watchpoint that was hit. \n\ 88254721Semaste \n\ 89254721SemasteImportant Note: Because loose Python code gets collected into functions, \n\ 90254721Semasteif you want to access global variables in the 'loose' code, you need to \n\ 91254721Semastespecify that they are global, using the 'global' keyword. Be sure to \n\ 92254721Semasteuse correct Python syntax, including indentation, when entering Python \n\ 93254721Semastewatchpoint commands. \n\ 94254721Semaste \n\ 95254721SemasteAs a third option, you can pass the name of an already existing Python function \n\ 96254721Semasteand that function will be attached to the watchpoint. It will get passed the \n\ 97254721Semasteframe and wp_loc arguments mentioned above. \n\ 98254721Semaste \n\ 99254721SemasteExample Python one-line watchpoint command: \n\ 100254721Semaste \n\ 101254721Semaste(lldb) watchpoint command add -s python 1 \n\ 102254721SemasteEnter your Python command(s). Type 'DONE' to end. \n\ 103254721Semaste> print \"Hit this watchpoint!\" \n\ 104254721Semaste> DONE \n\ 105254721Semaste \n\ 106254721SemasteAs a convenience, this also works for a short Python one-liner: \n\ 107254721Semaste(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\ 108254721Semaste(lldb) run \n\ 109254721SemasteLaunching '.../a.out' (x86_64) \n\ 110254721Semaste(lldb) Fri Sep 10 12:17:45 2010 \n\ 111254721SemasteProcess 21778 Stopped \n\ 112254721Semaste* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\ 113254721Semaste 36 \n\ 114254721Semaste 37 int c(int val)\n\ 115254721Semaste 38 {\n\ 116254721Semaste 39 -> return val + 3;\n\ 117254721Semaste 40 }\n\ 118254721Semaste 41 \n\ 119254721Semaste 42 int main (int argc, char const *argv[])\n\ 120254721Semaste(lldb) \n\ 121254721Semaste \n\ 122254721SemasteExample multiple line Python watchpoint command, using function definition: \n\ 123254721Semaste \n\ 124254721Semaste(lldb) watchpoint command add -s python 1 \n\ 125254721SemasteEnter your Python command(s). Type 'DONE' to end. \n\ 126254721Semaste> def watchpoint_output (wp_no): \n\ 127254721Semaste> out_string = \"Hit watchpoint number \" + repr (wp_no) \n\ 128254721Semaste> print out_string \n\ 129254721Semaste> return True \n\ 130254721Semaste> watchpoint_output (1) \n\ 131254721Semaste> DONE \n\ 132254721Semaste \n\ 133254721Semaste \n\ 134254721SemasteExample multiple line Python watchpoint command, using 'loose' Python: \n\ 135254721Semaste \n\ 136254721Semaste(lldb) watchpoint command add -s p 1 \n\ 137254721SemasteEnter your Python command(s). Type 'DONE' to end. \n\ 138254721Semaste> global wp_count \n\ 139254721Semaste> wp_count = wp_count + 1 \n\ 140254721Semaste> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\ 141254721Semaste> DONE \n\ 142254721Semaste \n\ 143254721SemasteIn this case, since there is a reference to a global variable, \n\ 144254721Semaste'wp_count', you will also need to make sure 'wp_count' exists and is \n\ 145254721Semasteinitialized: \n\ 146254721Semaste \n\ 147254721Semaste(lldb) script \n\ 148254721Semaste>>> wp_count = 0 \n\ 149254721Semaste>>> quit() \n\ 150254721Semaste \n\ 151254721Semaste(lldb) \n\ 152254721Semaste \n\ 153254721Semaste \n\ 154254721SemasteFinal Note: If you get a warning that no watchpoint command was generated, \n\ 155254721Semastebut you did not get any syntax errors, you probably forgot to add a call \n\ 156254721Semasteto your functions. \n\ 157254721Semaste \n\ 158254721SemasteSpecial information about debugger command watchpoint commands \n\ 159254721Semaste-------------------------------------------------------------- \n\ 160254721Semaste \n\ 161254721SemasteYou may enter any debugger command, exactly as you would at the \n\ 162254721Semastedebugger prompt. You may enter as many debugger commands as you like, \n\ 163254721Semastebut do NOT enter more than one command per line. \n" ); 164254721Semaste 165254721Semaste CommandArgumentEntry arg; 166254721Semaste CommandArgumentData wp_id_arg; 167254721Semaste 168254721Semaste // Define the first (and only) variant of this arg. 169254721Semaste wp_id_arg.arg_type = eArgTypeWatchpointID; 170254721Semaste wp_id_arg.arg_repetition = eArgRepeatPlain; 171254721Semaste 172254721Semaste // There is only one variant this argument could be; put it into the argument entry. 173254721Semaste arg.push_back (wp_id_arg); 174254721Semaste 175254721Semaste // Push the data for the first argument into the m_arguments vector. 176254721Semaste m_arguments.push_back (arg); 177254721Semaste } 178254721Semaste 179254721Semaste virtual 180254721Semaste ~CommandObjectWatchpointCommandAdd () {} 181254721Semaste 182254721Semaste virtual Options * 183254721Semaste GetOptions () 184254721Semaste { 185254721Semaste return &m_options; 186254721Semaste } 187254721Semaste 188254721Semaste void 189254721Semaste CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, 190254721Semaste CommandReturnObject &result) 191254721Semaste { 192254721Semaste InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 193254721Semaste std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 194254721Semaste if (reader_sp && data_ap.get()) 195254721Semaste { 196254721Semaste BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 197254721Semaste wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 198254721Semaste 199254721Semaste Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback, 200254721Semaste wp_options, // callback_data 201254721Semaste eInputReaderGranularityLine, // token size, to pass to callback function 202254721Semaste "DONE", // end token 203254721Semaste "> ", // prompt 204254721Semaste true)); // echo input 205254721Semaste if (err.Success()) 206254721Semaste { 207254721Semaste m_interpreter.GetDebugger().PushInputReader (reader_sp); 208254721Semaste result.SetStatus (eReturnStatusSuccessFinishNoResult); 209254721Semaste } 210254721Semaste else 211254721Semaste { 212254721Semaste result.AppendError (err.AsCString()); 213254721Semaste result.SetStatus (eReturnStatusFailed); 214254721Semaste } 215254721Semaste } 216254721Semaste else 217254721Semaste { 218254721Semaste result.AppendError("out of memory"); 219254721Semaste result.SetStatus (eReturnStatusFailed); 220254721Semaste } 221254721Semaste 222254721Semaste } 223254721Semaste 224254721Semaste /// Set a one-liner as the callback for the watchpoint. 225254721Semaste void 226254721Semaste SetWatchpointCommandCallback (WatchpointOptions *wp_options, 227254721Semaste const char *oneliner) 228254721Semaste { 229254721Semaste std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); 230254721Semaste 231254721Semaste // It's necessary to set both user_source and script_source to the oneliner. 232254721Semaste // The former is used to generate callback description (as in watchpoint command list) 233254721Semaste // while the latter is used for Python to interpret during the actual callback. 234254721Semaste data_ap->user_source.AppendString (oneliner); 235254721Semaste data_ap->script_source.assign (oneliner); 236254721Semaste data_ap->stop_on_error = m_options.m_stop_on_error; 237254721Semaste 238254721Semaste BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); 239254721Semaste wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); 240254721Semaste 241254721Semaste return; 242254721Semaste } 243254721Semaste 244254721Semaste static size_t 245254721Semaste GenerateWatchpointCommandCallback (void *callback_data, 246254721Semaste InputReader &reader, 247254721Semaste lldb::InputReaderAction notification, 248254721Semaste const char *bytes, 249254721Semaste size_t bytes_len) 250254721Semaste { 251254721Semaste StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); 252254721Semaste bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); 253254721Semaste 254254721Semaste switch (notification) 255254721Semaste { 256254721Semaste case eInputReaderActivate: 257254721Semaste if (!batch_mode) 258254721Semaste { 259254721Semaste out_stream->Printf ("%s\n", g_reader_instructions); 260254721Semaste if (reader.GetPrompt()) 261254721Semaste out_stream->Printf ("%s", reader.GetPrompt()); 262254721Semaste out_stream->Flush(); 263254721Semaste } 264254721Semaste break; 265254721Semaste 266254721Semaste case eInputReaderDeactivate: 267254721Semaste break; 268254721Semaste 269254721Semaste case eInputReaderReactivate: 270254721Semaste if (reader.GetPrompt() && !batch_mode) 271254721Semaste { 272254721Semaste out_stream->Printf ("%s", reader.GetPrompt()); 273254721Semaste out_stream->Flush(); 274254721Semaste } 275254721Semaste break; 276254721Semaste 277254721Semaste case eInputReaderAsynchronousOutputWritten: 278254721Semaste break; 279254721Semaste 280254721Semaste case eInputReaderGotToken: 281254721Semaste if (bytes && bytes_len && callback_data) 282254721Semaste { 283254721Semaste WatchpointOptions *wp_options = (WatchpointOptions *) callback_data; 284254721Semaste if (wp_options) 285254721Semaste { 286254721Semaste Baton *wp_options_baton = wp_options->GetBaton(); 287254721Semaste if (wp_options_baton) 288254721Semaste ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 289254721Semaste } 290254721Semaste } 291254721Semaste if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) 292254721Semaste { 293254721Semaste out_stream->Printf ("%s", reader.GetPrompt()); 294254721Semaste out_stream->Flush(); 295254721Semaste } 296254721Semaste break; 297254721Semaste 298254721Semaste case eInputReaderInterrupt: 299254721Semaste { 300254721Semaste // Finish, and cancel the watchpoint command. 301254721Semaste reader.SetIsDone (true); 302254721Semaste WatchpointOptions *wp_options = (WatchpointOptions *) callback_data; 303254721Semaste if (wp_options) 304254721Semaste { 305254721Semaste Baton *wp_options_baton = wp_options->GetBaton (); 306254721Semaste if (wp_options_baton) 307254721Semaste { 308254721Semaste ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear(); 309254721Semaste ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear(); 310254721Semaste } 311254721Semaste } 312254721Semaste if (!batch_mode) 313254721Semaste { 314254721Semaste out_stream->Printf ("Warning: No command attached to watchpoint.\n"); 315254721Semaste out_stream->Flush(); 316254721Semaste } 317254721Semaste } 318254721Semaste break; 319254721Semaste 320254721Semaste case eInputReaderEndOfFile: 321254721Semaste reader.SetIsDone (true); 322254721Semaste break; 323254721Semaste 324254721Semaste case eInputReaderDone: 325254721Semaste break; 326254721Semaste } 327254721Semaste 328254721Semaste return bytes_len; 329254721Semaste } 330254721Semaste 331254721Semaste static bool 332254721Semaste WatchpointOptionsCallbackFunction (void *baton, 333254721Semaste StoppointCallbackContext *context, 334254721Semaste lldb::user_id_t watch_id) 335254721Semaste { 336254721Semaste bool ret_value = true; 337254721Semaste if (baton == NULL) 338254721Semaste return true; 339254721Semaste 340254721Semaste 341254721Semaste WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton; 342254721Semaste StringList &commands = data->user_source; 343254721Semaste 344254721Semaste if (commands.GetSize() > 0) 345254721Semaste { 346254721Semaste ExecutionContext exe_ctx (context->exe_ctx_ref); 347254721Semaste Target *target = exe_ctx.GetTargetPtr(); 348254721Semaste if (target) 349254721Semaste { 350254721Semaste CommandReturnObject result; 351254721Semaste Debugger &debugger = target->GetDebugger(); 352254721Semaste // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 353254721Semaste // if the debugger is set up that way. 354254721Semaste 355254721Semaste StreamSP output_stream (debugger.GetAsyncOutputStream()); 356254721Semaste StreamSP error_stream (debugger.GetAsyncErrorStream()); 357254721Semaste result.SetImmediateOutputStream (output_stream); 358254721Semaste result.SetImmediateErrorStream (error_stream); 359254721Semaste 360254721Semaste bool stop_on_continue = true; 361254721Semaste bool echo_commands = false; 362254721Semaste bool print_results = true; 363254721Semaste 364254721Semaste debugger.GetCommandInterpreter().HandleCommands (commands, 365254721Semaste &exe_ctx, 366254721Semaste stop_on_continue, 367254721Semaste data->stop_on_error, 368254721Semaste echo_commands, 369254721Semaste print_results, 370254721Semaste eLazyBoolNo, 371254721Semaste result); 372254721Semaste result.GetImmediateOutputStream()->Flush(); 373254721Semaste result.GetImmediateErrorStream()->Flush(); 374254721Semaste } 375254721Semaste } 376254721Semaste return ret_value; 377254721Semaste } 378254721Semaste 379254721Semaste class CommandOptions : public Options 380254721Semaste { 381254721Semaste public: 382254721Semaste 383254721Semaste CommandOptions (CommandInterpreter &interpreter) : 384254721Semaste Options (interpreter), 385254721Semaste m_use_commands (false), 386254721Semaste m_use_script_language (false), 387254721Semaste m_script_language (eScriptLanguageNone), 388254721Semaste m_use_one_liner (false), 389254721Semaste m_one_liner(), 390254721Semaste m_function_name() 391254721Semaste { 392254721Semaste } 393254721Semaste 394254721Semaste virtual 395254721Semaste ~CommandOptions () {} 396254721Semaste 397254721Semaste virtual Error 398254721Semaste SetOptionValue (uint32_t option_idx, const char *option_arg) 399254721Semaste { 400254721Semaste Error error; 401254721Semaste const int short_option = m_getopt_table[option_idx].val; 402254721Semaste 403254721Semaste switch (short_option) 404254721Semaste { 405254721Semaste case 'o': 406254721Semaste m_use_one_liner = true; 407254721Semaste m_one_liner = option_arg; 408254721Semaste break; 409254721Semaste 410254721Semaste case 's': 411254721Semaste m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 412254721Semaste g_option_table[option_idx].enum_values, 413254721Semaste eScriptLanguageNone, 414254721Semaste error); 415254721Semaste 416254721Semaste if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 417254721Semaste { 418254721Semaste m_use_script_language = true; 419254721Semaste } 420254721Semaste else 421254721Semaste { 422254721Semaste m_use_script_language = false; 423254721Semaste } 424254721Semaste break; 425254721Semaste 426254721Semaste case 'e': 427254721Semaste { 428254721Semaste bool success = false; 429254721Semaste m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 430254721Semaste if (!success) 431254721Semaste error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 432254721Semaste } 433254721Semaste break; 434254721Semaste 435254721Semaste case 'F': 436254721Semaste { 437254721Semaste m_use_one_liner = false; 438254721Semaste m_use_script_language = true; 439254721Semaste m_function_name.assign(option_arg); 440254721Semaste } 441254721Semaste break; 442254721Semaste 443254721Semaste default: 444254721Semaste break; 445254721Semaste } 446254721Semaste return error; 447254721Semaste } 448254721Semaste void 449254721Semaste OptionParsingStarting () 450254721Semaste { 451254721Semaste m_use_commands = true; 452254721Semaste m_use_script_language = false; 453254721Semaste m_script_language = eScriptLanguageNone; 454254721Semaste 455254721Semaste m_use_one_liner = false; 456254721Semaste m_stop_on_error = true; 457254721Semaste m_one_liner.clear(); 458254721Semaste m_function_name.clear(); 459254721Semaste } 460254721Semaste 461254721Semaste const OptionDefinition* 462254721Semaste GetDefinitions () 463254721Semaste { 464254721Semaste return g_option_table; 465254721Semaste } 466254721Semaste 467254721Semaste // Options table: Required for subclasses of Options. 468254721Semaste 469254721Semaste static OptionDefinition g_option_table[]; 470254721Semaste 471254721Semaste // Instance variables to hold the values for command options. 472254721Semaste 473254721Semaste bool m_use_commands; 474254721Semaste bool m_use_script_language; 475254721Semaste lldb::ScriptLanguage m_script_language; 476254721Semaste 477254721Semaste // Instance variables to hold the values for one_liner options. 478254721Semaste bool m_use_one_liner; 479254721Semaste std::string m_one_liner; 480254721Semaste bool m_stop_on_error; 481254721Semaste std::string m_function_name; 482254721Semaste }; 483254721Semaste 484254721Semasteprotected: 485254721Semaste virtual bool 486254721Semaste DoExecute (Args& command, CommandReturnObject &result) 487254721Semaste { 488254721Semaste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 489254721Semaste 490254721Semaste if (target == NULL) 491254721Semaste { 492254721Semaste result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands"); 493254721Semaste result.SetStatus (eReturnStatusFailed); 494254721Semaste return false; 495254721Semaste } 496254721Semaste 497254721Semaste const WatchpointList &watchpoints = target->GetWatchpointList(); 498254721Semaste size_t num_watchpoints = watchpoints.GetSize(); 499254721Semaste 500254721Semaste if (num_watchpoints == 0) 501254721Semaste { 502254721Semaste result.AppendError ("No watchpoints exist to have commands added"); 503254721Semaste result.SetStatus (eReturnStatusFailed); 504254721Semaste return false; 505254721Semaste } 506254721Semaste 507254721Semaste if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 508254721Semaste { 509254721Semaste result.AppendError ("need to enable scripting to have a function run as a watchpoint command"); 510254721Semaste result.SetStatus (eReturnStatusFailed); 511254721Semaste return false; 512254721Semaste } 513254721Semaste 514254721Semaste std::vector<uint32_t> valid_wp_ids; 515254721Semaste if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 516254721Semaste { 517254721Semaste result.AppendError("Invalid watchpoints specification."); 518254721Semaste result.SetStatus(eReturnStatusFailed); 519254721Semaste return false; 520254721Semaste } 521254721Semaste 522254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 523254721Semaste const size_t count = valid_wp_ids.size(); 524254721Semaste for (size_t i = 0; i < count; ++i) 525254721Semaste { 526254721Semaste uint32_t cur_wp_id = valid_wp_ids.at (i); 527254721Semaste if (cur_wp_id != LLDB_INVALID_WATCH_ID) 528254721Semaste { 529254721Semaste Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 530254721Semaste // Sanity check wp first. 531254721Semaste if (wp == NULL) continue; 532254721Semaste 533254721Semaste WatchpointOptions *wp_options = wp->GetOptions(); 534254721Semaste // Skip this watchpoint if wp_options is not good. 535254721Semaste if (wp_options == NULL) continue; 536254721Semaste 537254721Semaste // If we are using script language, get the script interpreter 538254721Semaste // in order to set or collect command callback. Otherwise, call 539254721Semaste // the methods associated with this object. 540254721Semaste if (m_options.m_use_script_language) 541254721Semaste { 542254721Semaste // Special handling for one-liner specified inline. 543254721Semaste if (m_options.m_use_one_liner) 544254721Semaste { 545254721Semaste m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 546254721Semaste m_options.m_one_liner.c_str()); 547254721Semaste } 548254721Semaste // Special handling for using a Python function by name 549254721Semaste // instead of extending the watchpoint callback data structures, we just automatize 550254721Semaste // what the user would do manually: make their watchpoint command be a function call 551254721Semaste else if (m_options.m_function_name.size()) 552254721Semaste { 553254721Semaste std::string oneliner(m_options.m_function_name); 554254721Semaste oneliner += "(frame, wp, internal_dict)"; 555254721Semaste m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options, 556254721Semaste oneliner.c_str()); 557254721Semaste } 558254721Semaste else 559254721Semaste { 560254721Semaste m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options, 561254721Semaste result); 562254721Semaste } 563254721Semaste } 564254721Semaste else 565254721Semaste { 566254721Semaste // Special handling for one-liner specified inline. 567254721Semaste if (m_options.m_use_one_liner) 568254721Semaste SetWatchpointCommandCallback (wp_options, 569254721Semaste m_options.m_one_liner.c_str()); 570254721Semaste else 571254721Semaste CollectDataForWatchpointCommandCallback (wp_options, 572254721Semaste result); 573254721Semaste } 574254721Semaste } 575254721Semaste } 576254721Semaste 577254721Semaste return result.Succeeded(); 578254721Semaste } 579254721Semaste 580254721Semasteprivate: 581254721Semaste CommandOptions m_options; 582254721Semaste static const char *g_reader_instructions; 583254721Semaste 584254721Semaste}; 585254721Semaste 586254721Semasteconst char * 587254721SemasteCommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 588254721Semaste 589254721Semaste// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 590254721Semaste// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 591254721Semaste 592254721Semastestatic OptionEnumValueElement 593254721Semasteg_script_option_enumeration[4] = 594254721Semaste{ 595254721Semaste { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 596254721Semaste { eScriptLanguagePython, "python", "Commands are in the Python language."}, 597254721Semaste { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 598254721Semaste { 0, NULL, NULL } 599254721Semaste}; 600254721Semaste 601254721SemasteOptionDefinition 602254721SemasteCommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] = 603254721Semaste{ 604254721Semaste { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner, 605254721Semaste "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." }, 606254721Semaste 607254721Semaste { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, 608254721Semaste "Specify whether watchpoint command execution should terminate on error." }, 609254721Semaste 610254721Semaste { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone, 611254721Semaste "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 612254721Semaste 613254721Semaste { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction, 614254721Semaste "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."}, 615254721Semaste 616254721Semaste { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 617254721Semaste}; 618254721Semaste 619254721Semaste//------------------------------------------------------------------------- 620254721Semaste// CommandObjectWatchpointCommandDelete 621254721Semaste//------------------------------------------------------------------------- 622254721Semaste 623254721Semasteclass CommandObjectWatchpointCommandDelete : public CommandObjectParsed 624254721Semaste{ 625254721Semastepublic: 626254721Semaste CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) : 627254721Semaste CommandObjectParsed (interpreter, 628254721Semaste "delete", 629254721Semaste "Delete the set of commands from a watchpoint.", 630254721Semaste NULL) 631254721Semaste { 632254721Semaste CommandArgumentEntry arg; 633254721Semaste CommandArgumentData wp_id_arg; 634254721Semaste 635254721Semaste // Define the first (and only) variant of this arg. 636254721Semaste wp_id_arg.arg_type = eArgTypeWatchpointID; 637254721Semaste wp_id_arg.arg_repetition = eArgRepeatPlain; 638254721Semaste 639254721Semaste // There is only one variant this argument could be; put it into the argument entry. 640254721Semaste arg.push_back (wp_id_arg); 641254721Semaste 642254721Semaste // Push the data for the first argument into the m_arguments vector. 643254721Semaste m_arguments.push_back (arg); 644254721Semaste } 645254721Semaste 646254721Semaste 647254721Semaste virtual 648254721Semaste ~CommandObjectWatchpointCommandDelete () {} 649254721Semaste 650254721Semasteprotected: 651254721Semaste virtual bool 652254721Semaste DoExecute (Args& command, CommandReturnObject &result) 653254721Semaste { 654254721Semaste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 655254721Semaste 656254721Semaste if (target == NULL) 657254721Semaste { 658254721Semaste result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands"); 659254721Semaste result.SetStatus (eReturnStatusFailed); 660254721Semaste return false; 661254721Semaste } 662254721Semaste 663254721Semaste const WatchpointList &watchpoints = target->GetWatchpointList(); 664254721Semaste size_t num_watchpoints = watchpoints.GetSize(); 665254721Semaste 666254721Semaste if (num_watchpoints == 0) 667254721Semaste { 668254721Semaste result.AppendError ("No watchpoints exist to have commands deleted"); 669254721Semaste result.SetStatus (eReturnStatusFailed); 670254721Semaste return false; 671254721Semaste } 672254721Semaste 673254721Semaste if (command.GetArgumentCount() == 0) 674254721Semaste { 675254721Semaste result.AppendError ("No watchpoint specified from which to delete the commands"); 676254721Semaste result.SetStatus (eReturnStatusFailed); 677254721Semaste return false; 678254721Semaste } 679254721Semaste 680254721Semaste std::vector<uint32_t> valid_wp_ids; 681254721Semaste if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 682254721Semaste { 683254721Semaste result.AppendError("Invalid watchpoints specification."); 684254721Semaste result.SetStatus(eReturnStatusFailed); 685254721Semaste return false; 686254721Semaste } 687254721Semaste 688254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 689254721Semaste const size_t count = valid_wp_ids.size(); 690254721Semaste for (size_t i = 0; i < count; ++i) 691254721Semaste { 692254721Semaste uint32_t cur_wp_id = valid_wp_ids.at (i); 693254721Semaste if (cur_wp_id != LLDB_INVALID_WATCH_ID) 694254721Semaste { 695254721Semaste Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 696254721Semaste if (wp) 697254721Semaste wp->ClearCallback(); 698254721Semaste } 699254721Semaste else 700254721Semaste { 701254721Semaste result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 702254721Semaste cur_wp_id); 703254721Semaste result.SetStatus (eReturnStatusFailed); 704254721Semaste return false; 705254721Semaste } 706254721Semaste } 707254721Semaste return result.Succeeded(); 708254721Semaste } 709254721Semaste}; 710254721Semaste 711254721Semaste//------------------------------------------------------------------------- 712254721Semaste// CommandObjectWatchpointCommandList 713254721Semaste//------------------------------------------------------------------------- 714254721Semaste 715254721Semasteclass CommandObjectWatchpointCommandList : public CommandObjectParsed 716254721Semaste{ 717254721Semastepublic: 718254721Semaste CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) : 719254721Semaste CommandObjectParsed (interpreter, 720254721Semaste "list", 721254721Semaste "List the script or set of commands to be executed when the watchpoint is hit.", 722254721Semaste NULL) 723254721Semaste { 724254721Semaste CommandArgumentEntry arg; 725254721Semaste CommandArgumentData wp_id_arg; 726254721Semaste 727254721Semaste // Define the first (and only) variant of this arg. 728254721Semaste wp_id_arg.arg_type = eArgTypeWatchpointID; 729254721Semaste wp_id_arg.arg_repetition = eArgRepeatPlain; 730254721Semaste 731254721Semaste // There is only one variant this argument could be; put it into the argument entry. 732254721Semaste arg.push_back (wp_id_arg); 733254721Semaste 734254721Semaste // Push the data for the first argument into the m_arguments vector. 735254721Semaste m_arguments.push_back (arg); 736254721Semaste } 737254721Semaste 738254721Semaste virtual 739254721Semaste ~CommandObjectWatchpointCommandList () {} 740254721Semaste 741254721Semasteprotected: 742254721Semaste virtual bool 743254721Semaste DoExecute (Args& command, 744254721Semaste CommandReturnObject &result) 745254721Semaste { 746254721Semaste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 747254721Semaste 748254721Semaste if (target == NULL) 749254721Semaste { 750254721Semaste result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands"); 751254721Semaste result.SetStatus (eReturnStatusFailed); 752254721Semaste return false; 753254721Semaste } 754254721Semaste 755254721Semaste const WatchpointList &watchpoints = target->GetWatchpointList(); 756254721Semaste size_t num_watchpoints = watchpoints.GetSize(); 757254721Semaste 758254721Semaste if (num_watchpoints == 0) 759254721Semaste { 760254721Semaste result.AppendError ("No watchpoints exist for which to list commands"); 761254721Semaste result.SetStatus (eReturnStatusFailed); 762254721Semaste return false; 763254721Semaste } 764254721Semaste 765254721Semaste if (command.GetArgumentCount() == 0) 766254721Semaste { 767254721Semaste result.AppendError ("No watchpoint specified for which to list the commands"); 768254721Semaste result.SetStatus (eReturnStatusFailed); 769254721Semaste return false; 770254721Semaste } 771254721Semaste 772254721Semaste std::vector<uint32_t> valid_wp_ids; 773254721Semaste if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) 774254721Semaste { 775254721Semaste result.AppendError("Invalid watchpoints specification."); 776254721Semaste result.SetStatus(eReturnStatusFailed); 777254721Semaste return false; 778254721Semaste } 779254721Semaste 780254721Semaste result.SetStatus(eReturnStatusSuccessFinishNoResult); 781254721Semaste const size_t count = valid_wp_ids.size(); 782254721Semaste for (size_t i = 0; i < count; ++i) 783254721Semaste { 784254721Semaste uint32_t cur_wp_id = valid_wp_ids.at (i); 785254721Semaste if (cur_wp_id != LLDB_INVALID_WATCH_ID) 786254721Semaste { 787254721Semaste Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get(); 788254721Semaste 789254721Semaste if (wp) 790254721Semaste { 791254721Semaste const WatchpointOptions *wp_options = wp->GetOptions(); 792254721Semaste if (wp_options) 793254721Semaste { 794254721Semaste // Get the callback baton associated with the current watchpoint. 795254721Semaste const Baton *baton = wp_options->GetBaton(); 796254721Semaste if (baton) 797254721Semaste { 798254721Semaste result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id); 799254721Semaste result.GetOutputStream().IndentMore (); 800254721Semaste baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 801254721Semaste result.GetOutputStream().IndentLess (); 802254721Semaste } 803254721Semaste else 804254721Semaste { 805254721Semaste result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n", 806254721Semaste cur_wp_id); 807254721Semaste } 808254721Semaste } 809254721Semaste result.SetStatus (eReturnStatusSuccessFinishResult); 810254721Semaste } 811254721Semaste else 812254721Semaste { 813254721Semaste result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); 814254721Semaste result.SetStatus (eReturnStatusFailed); 815254721Semaste } 816254721Semaste } 817254721Semaste } 818254721Semaste 819254721Semaste return result.Succeeded(); 820254721Semaste } 821254721Semaste}; 822254721Semaste 823254721Semaste//------------------------------------------------------------------------- 824254721Semaste// CommandObjectWatchpointCommand 825254721Semaste//------------------------------------------------------------------------- 826254721Semaste 827254721SemasteCommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) : 828254721Semaste CommandObjectMultiword (interpreter, 829254721Semaste "command", 830254721Semaste "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').", 831254721Semaste "command <sub-command> [<sub-command-options>] <watchpoint-id>") 832254721Semaste{ 833254721Semaste CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter)); 834254721Semaste CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter)); 835254721Semaste CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter)); 836254721Semaste 837254721Semaste add_command_object->SetCommandName ("watchpoint command add"); 838254721Semaste delete_command_object->SetCommandName ("watchpoint command delete"); 839254721Semaste list_command_object->SetCommandName ("watchpoint command list"); 840254721Semaste 841254721Semaste LoadSubCommand ("add", add_command_object); 842254721Semaste LoadSubCommand ("delete", delete_command_object); 843254721Semaste LoadSubCommand ("list", list_command_object); 844254721Semaste} 845254721Semaste 846254721SemasteCommandObjectWatchpointCommand::~CommandObjectWatchpointCommand () 847254721Semaste{ 848254721Semaste} 849254721Semaste 850254721Semaste 851