Ejemplo n.º 1
0
void CmdPrint::help(DebuggerClient &client) {
  client.helpTitle("Print Command");
  client.helpCmds(
    "[p]rint {php}",              "prints result of PHP code",
    "[p]rint r {php}",            "prints result of PHP code, (print_r)",
    "[p]rint v {php}",            "prints result of PHP code, (var_dump)",
    "[p]rint x {php}",            "prints hex encoded string or number",
    "[p]rint [h]ex {php}",        "prints hex encoded string or number",
    "[p]rint [o]ct {php}",        "prints octal encoded string or number",
    "[p]rint [d]ec {php}",        "prints as signed integer",
    "[p]rint [u]nsigned {php}",   "prints as unsigned integer",
    "[p]rint [t]ime {php}",       "converts between time and timestamp",
    "",                           "",
    "[p]rint [a]lways {above}",   "adds a watch expression at break",
    "[p]rint [l]ist",             "lists watch expressions",
    "[p]rint [c]lear {index}",    "clears a watch expression",
    "[p]rint [c]lear [a]ll",      "clears all watch expressions",
    nullptr
  );
  client.helpBody(
    "Prints result of an expression in certain format. If '[a]lways' is "
    "specified, the expression will be added to a watch list. At every break, "
    "either at a breakpoint or caused by step commands, these expressions "
    "will be evaluated and printed out."
  );
}
Ejemplo n.º 2
0
// The text to display when the debugger client processes "help list".
void CmdList::help(DebuggerClient &client) {
  client.helpTitle("List Command");
  client.helpCmds(
    "list",                   "displays current block of source code",
    "list {line}",            "displays code around specified line",
    "list {line1}-{line2}",   "displays specified block of source code",
    "list {line1}-",          "displays code starting with the line",
    "list -{line2}",          "displays code ending with the line",
    "list {file}",            "displays beginning lines of the file",
    "list {cls}",             "displays beginning lines of the class",
    "list {function}",        "displays beginning lines of the function",
    "list {cls::method}",     "displays beginning lines of the method",
    "list {file}:{line}",     "displays code around specified file:line",
    "list {file}:{l1}-{l2}",  "displays specified block in the file",
    "list {file}:{l1}-",      "displays specified block in the file",
    "list {file}:-{l2}",      "displays specified block in the file",
    "list {directory}",       "sets PHP source root directory",
    nullptr
  );
  client.helpBody(
    "Use list command to display PHP source code. In remote debugging, this "
    "is displaying source code on server side. When server side cannot find "
    "the file, it will fall back to local files.\n"
    "\n"
    "Hit return to display more lines of code after current display.\n"
    "\n"
    "When a directory name is specified, this will become a root directory "
    "for resolving relative paths of PHP files. Files with absolute paths "
    "will not be affected by this setting. This directory will be stored "
    "in configuration file for future sessions as well."
  );
}
Ejemplo n.º 3
0
void CmdShell::help(DebuggerClient &client) {
  client.helpTitle("Shell Command");
  client.help("! {cmd} {arg1} {arg2} ...    remotely executes shell command");
  client.helpBody(
    "Executes the shell command on connected machine.\n"
    "\n"
    "The space between ! and command is not needed. '!ls' works as well."
  );
}
Ejemplo n.º 4
0
void CmdComplete::help(DebuggerClient &client) {
  client.helpTitle("Complete");
  client.help("complete <cmd>");
  client.helpBody(
    "This command provides the same results as TAB completion does on the"
    " command line, but bypasses the complexity of interacting with the"
    " readline library. This help is primarily for use by programs that"
    " need to access completion functionality."
  );
}
Ejemplo n.º 5
0
void CmdContinue::help(DebuggerClient &client) {
  client.helpTitle("Continue Command");
  client.helpCmds(
    "[c]ontinue {count=1}", "continues program execution",
    nullptr
  );
  client.helpBody(
    "Use this command at break to resume program execution. Specify a "
    "count to repeat the same command many times."
  );
}
Ejemplo n.º 6
0
void CmdStep::help(DebuggerClient &client) {
  client.helpTitle("Step Command");
  client.helpCmds(
    "[s]tep {count=1}", "steps into lines of code",
    nullptr
  );
  client.helpBody(
    "Use this command at break to step into lines of code. Specify a "
    "count to step more than once."
  );
}
Ejemplo n.º 7
0
void CmdOut::help(DebuggerClient &client) {
  client.helpTitle("Out Command");
  client.helpCmds(
    "[o]ut {count=1}", "steps out function calls",
    nullptr
  );
  client.helpBody(
    "Use this command at break to step out function calls. Specify a "
    "count to step out more than one level of function calls."
  );
}
Ejemplo n.º 8
0
void CmdHelp::HelpAll(DebuggerClient &client) {
  client.helpCmds(
    "Session Commands", "",
    "[m]achine",    "connects to an HHVM server",
    "[t]hread",     "switches between different threads",
    "[q]uit",       "quits debugger",

    "Program Flow Control", "",
    "[b]reak",      "sets/clears/displays breakpoints",
    "[e]xception",  "catches/clears exceptions",
    "[r]un",        "starts over a program",
    "<Ctrl-C>",     "breaks program execution",
    "[c]ontinue *", "continues program execution",
    "[s]tep     *", "steps into a function call or an expression",
    "[n]ext     *", "steps over a function call or a line",
    "[o]ut      *", "steps out a function call",

    "Display Commands", "",
    "[p]rint",      "prints a variable's value",
    "[w]here",      "displays stacktrace",
    "[u]p",         "goes up by frame(s)",
    "[d]own",       "goes down by frame(s)",
    "[f]rame",      "goes to a frame",
    "[v]ariable",   "lists all local variables",
    "[g]lobal",     "lists all global variables",
    "[k]onstant",   "lists all constants",

    "Evaluation Commands", "",
    "@",            "evaluates one line of PHP code",
    "=",            "prints right-hand-side's value, assigns to $_",
    "${name}=",     "assigns a value to left-hand-side",
    "[<?]php",      "starts input of a block of PHP code",
    "?>",           "ends and evaluates a block a PHP code",
    "[a]bort",      "aborts input of a block of PHP code",
    "[z]end",       "evaluates the last snippet in Zend PHP",

    "Documentation and Source Code", "",
    "[i]nfo",       "displays documentations and other information",
    "[l]ist     *", "displays source codes",
    "[h]elp    **", "displays this help",
    "?",            "displays this help",

    "Shell and Extended Commands", "",
    "! {cmd}",      "executes a shell command",
    "& {cmd}",      "records and replays macros",
    "x {cmd}",      "extended commands",
    "y {cmd}",      "user extended commands",

    nullptr
  );

  client.helpBody("* These commands are replayable by just hitting return.\n"
      "** Type \"help help\" to get more help.");
}
Ejemplo n.º 9
0
void CmdNext::help(DebuggerClient& client) {
  client.helpTitle("Next Command");
  client.helpCmds(
    "[n]ext {count=1}", "steps over lines of code",
    nullptr
  );
  client.helpBody(
    "Use this command at break to step over lines of code. Specify a "
    "count to step over more than one line of code."
  );
}
Ejemplo n.º 10
0
// The text to display when the debugger client processes "help quit".
void CmdQuit::help(DebuggerClient &client) {
  TRACE(2, "CmdQuit::help\n");
  client.helpTitle("Quit Command");
  client.helpCmds(
    "[q]uit", "quits this program",
    nullptr
  );
  client.helpBody(
    "After you type this command, you will not see me anymore."
  );
}
Ejemplo n.º 11
0
void CmdFrame::help(DebuggerClient &client) {
  client.helpTitle("Frame Command");
  client.helpCmds(
    "[f]rame {index}",  "jumps to one particular frame",
    nullptr
  );
  client.helpBody(
    "Use '[w]here' command to find out the frame number. Use 'f 0' to jump "
    "back to the most recent frame or the innermost frame. Use 'f 999' or "
    "some big number to jump to the outermost frame."
  );
}
Ejemplo n.º 12
0
void CmdMachine::help(DebuggerClient &client) {
  client.helpTitle("Machine Command");
  client.helpCmds(
    "[m]achine [c]onnect {host}",         "debugging remote server natively",
    "[m]achine [c]onnect {host}:{port}",  "debugging remote server natively",
    "[m]achine [r]pc {host}",             "debugging remote server with RPC",
    "[m]achine [r]pc {host}:{port}",      "debugging remote server with RPC",
    "[m]achine [d]isconnect",             "disconnect, debugging local script",
    "[m]achine [l]ist",                   "list all sandboxes",
    "[m]achine [a]ttach {index}",         "attach to a sandbox",
    "[m]achine [a]ttach {sandbox}",       "attach to my sandbox by name",
    "[m]achine [a]ttach {user} {sandbox}",
    "attach to a sandbox by user and name",
    "[m]achine [a]ttach [f]orce {index|sandbox|user sandbox}",
    "force attach to a sandbox (see below)",
    nullptr
  );
  client.helpBody(
    "Use this command to switch between different machines or "
    "sandboxes.\n"
    "\n"
    "If command prompt says \"hphpd\", all evaluation of PHP code happens "
    "locally within the debugger. This is the mode when debugger is started "
    "without a remote server name. No user libraries are pre-loaded in this "
    "mode.\n"
    "\n"
    "When connecting to a remote server, it will automatically attach "
    "to \"default\" sandbox under current user. If \"default\" sandbox "
    "does not exist, it will attach to a random sandbox under current "
    "user. In sandbox mode, a file specified in server's configuration "
    "of \"Eval.Debugger.StartupDocument\" is pre-loaded.\n"
    "\n"
    "If there is no sandbox available, it will create a \"dummy\" "
    "sandbox and attach to it.\n"
    "\n"
    "When your sandbox is not available, please hit it at least once "
    "from your browser. Then run '[m]achine [l]ist' command again.\n"
    "\n"
    "If another debugger client is already attached to your sandbox you can "
    "use the '[f]orce' option to '[m]achine [a]ttach'. This will disconnect "
    "the other client and force your client to connect.\n"
    "\n"
    "If a HipHop server has RPC port open, one can also debug the server in "
    "a very special RPC mode. In this mode, one can type in PHP scripts to "
    "run, but all functions will be executed on server through RPC. Because "
    "states are still maintained locally and only functions are executed "
    "remotely, it may not work with functions or scripts that depend on "
    "global variables or low-level raw resource pointers. As a simple rule, "
    "stateless functions will work just fine. This is true to objects and "
    "method calls as well, except classes will have to be loaded on client "
    "side by '=include(\"file-containing-the-class.php\")'."
  );
}
Ejemplo n.º 13
0
void CmdDown::help(DebuggerClient &client) {
  client.helpTitle("Down Command");
  client.helpCmds(
    "[d]own {num=1}", "moves to inner frames (callees) on stacktrace",
    nullptr
  );
  client.helpBody(
    "Use this command to walk down on stacktrace to find out inner callees of "
    "current frame. By default it moves down by one level. Specify a number "
    "to move down several levels a time."
  );
}
Ejemplo n.º 14
0
void CmdWhere::help(DebuggerClient &client) {
  client.helpTitle("Where Command");
  client.helpCmds(
    "[w]here",           "displays current stacktrace",
    "[w]here {num}",     "displays number of innermost frames",
    "[w]here -{num}",    "displays number of outermost frames",
    nullptr
  );
  client.helpBody(
    "Use '[u]p {num}' or '[d]own {num}' to walk up or down the stacktrace. "
    "Use '[f]rame {index}' to jump to one particular frame. At any frame, "
    "use '[v]ariable' command to display all local variables."
  );
}
Ejemplo n.º 15
0
void CmdGlobal::help(DebuggerClient &client) {
  client.helpTitle("Global Command");
  client.helpCmds(
    "[g]lobal",           "lists all global variables",
    "[g]lobal {text}",    "full-text search global variables",
    nullptr
  );
  client.helpBody(
    "This will print names and values of all global variables, if {text} is "
    "not speified. Otherwise, it will print global variables that contain the "
    "text in their names or values. The search is case-insensitive and "
    "string-based."
  );
}
Ejemplo n.º 16
0
void CmdZend::help(DebuggerClient &client) {
  client.helpTitle("Zend Command");
  client.helpCmds(
    "[z]end", "running the most recent code snippet in Zend PHP",
    nullptr
  );
  client.helpBody(
    "This is mainly for comparing results from PHP vs. HipHop. After you type "
    "in some PHP code, it will be evaluated immediately in HipHop. Then you "
    "can type '[z]end' command to re-run the same script with your "
    "system-default PHP. Please note that only the most recent block of code "
    "you manually typed in is evaluated, not any earlier ones, nor the ones "
    "from a PHP file."
  );
}
Ejemplo n.º 17
0
void CmdExtension::help(DebuggerClient &client) {
  client.helpTitle("Extension Command");
  client.helpCmds(
    "x [t]ension",                 "lists all extensions",
    "x [t]ension {name}",          "shows summary info of the extension",
    "x [t]ension {name} dump",     "shows detailed info of the extension",
    "x [t]ension {name} {verb} {args} ...",   "executes an action",
    nullptr
  );
  client.helpBody(
    "In PHP, a lot of library functions are implemented as \"extensions\". "
    "This command allows extensions to support debugger by providing their "
    "version numbers, current status and cached data and by providing "
    "additional verbs to update runtime states for debugging purposes."
  );
}
Ejemplo n.º 18
0
void CmdInstrument::help(DebuggerClient &client) {
  client.helpTitle("Instrument Command");
  // TODO: more functionalities
  client.helpCmds("inst here <file> [desc]",
                   "inject <file> to here",
                   "inst <func>() <file> [desc]",
                   "inject <file> to the entry point of <func>",
                   "inst [l]ist",
                   "list injections",
                   "inst [c]lear",
                   "clear all injections",
                   nullptr);
  client.helpBody(
    "Use this command to instrument the program"
  );
}
Ejemplo n.º 19
0
void CmdRun::help(DebuggerClient &client) {
  client.helpTitle("Run Command");
  client.helpCmds(
    "[r]un",                             "restarts program",
    "[r]un {file} {arg1} {arg2} ...",    "starts a new program",
    nullptr
  );
  client.helpBody(
    "Aborts current execution and restarts program with specified arguments. "
    "If no arguments are specified, it will reuse the PHP file and old "
    "arguments. If arguments are to be changed, please include file name, "
    "even if it is the same, as the first one.\n"
    "\n"
    "In server mode, this command will simply abort current page handling "
    "without restarting anything."
  );
}
Ejemplo n.º 20
0
void CmdHeaptrace::help(DebuggerClient &client) {
  client.helpTitle("Heaptrace Command");
  client.helpCmds(
    "[h]eaptrace",                     "dumps all currently reachable values",
    "[h]eaptrace {format} {filename}", "dumps heap to graph file",
    nullptr
  );
  client.helpBody(
    "This will print the locations and types of all reachable values "
    "in the heap. The long form dumps it to a file of a supported format.\n"
    "Supported formats are currently:\n"
    " - graphviz : Dumps to a GraphViz file, which can be used with e.g. "
    "dot, twopi or some other GraphViz tool to render an image.\n"
    " - gml      : Dumps to a GML (Graph Modelling Language) file, which can "
    "be viewed interactively with programs like yEd. yEd can be found at "
    "www.yworks.com."
  );
}
Ejemplo n.º 21
0
void CmdVariable::help(DebuggerClient &client) {
  client.helpTitle("Variable Command");
  client.helpCmds(
    "[v]ariable",           "lists all local variables on stack",
    "[v]ariable {text}",    "full-text search local variables",
    nullptr
  );
  client.helpBody(
    "This will print names and values of all variables that are currently "
    "accessible by simple names. Use '[w]here', '[u]p {num}', '[d]own {num}', "
    "'[f]rame {index}' commands to choose a different frame to view variables "
    "at different level of the stack.\n"
    "\n"
    "Specify some free text to print local variables that contain the text "
    "either in their names or values. The search is case-insensitive and "
    "string-based."
  );
}
void CmdInternalTesting::help(DebuggerClient &client) {
  TRACE(2, "CmdInternalTesting::help\n");
  client.helpTitle("Internal Testing Command");
  client.helpCmds(
    "badcmdtypesend", "Send a bad command type to the proxy",
    "badcmdtypereceive", "Receive a bad command type from the proxy",
    "shortcmdsend", "Send less data that the proxy expects",
    "shortcmdreceive", "Receive less data than the client expects",
    "segfaultClient", "Segfault on the client",
    "segfaultServer", "Segfault on the server",
    nullptr
  );
  client.helpBody(
    "This command is only for internal testing of the debugger, both client "
    "and server. If you're using this command and you're not trying to test "
    "the debugger, then you're making a really big mistake."
  );
}
Ejemplo n.º 23
0
void CmdConfig::help(DebuggerClient &client) {
  client.helpTitle("Set Command");
  client.helpCmds(
    "set bac on/off","on makes debugger bypass access checks on class members",
    "set lf path/off","turn logging on and specify log file",
    "set pl level","if level > 0, only print out object trees to that depth",
    "set cc count","display at most count characters when doing = command",
    "set ss on/off",
      "on makes the debugger take small steps (not entire lines)",
    "set sa on/off","on makes where command display argument values",
    "set mcl limit","display at most limit source lines at breakpoints",
    nullptr);
  client.helpBody(
    "Use this command to change default settings. "
    "The new values are persisted into "
    "the configuration file that normally can be found at ~/.hphpd.ini. "
    "Level, count and limit can be <= 0, in which case they are unlimited."
  );
}
Ejemplo n.º 24
0
void CmdWhere::help(DebuggerClient &client) {
  client.helpTitle("Where Command");
  client.helpCmds(
    "[w]here", "displays current stacktrace",
    "[w]here [a]sync", "displays the current async stacktrace",
    "wa", "shortcut for [w]here [a]sync",
    "[w]here {[a]sync]} {num}", "displays number of innermost frames",
    "[w]here {[a]sync]} -{num}", "displays number of outermost frames",
    nullptr
  );
  client.helpBody(
    "Use '[u]p {num}' or '[d]own {num}' to walk up or down the stacktrace. "
    "Use '[f]rame {index}' to jump to one particular frame. At any frame, "
    "Use '[v]ariable' command to display all local variables.\n"
    "\n"
    "Use '[w]here [a]sync' from within an async method, like a generator, "
    "to get the current stack of async methods."
  );
}
Ejemplo n.º 25
0
void CmdHelp::help(DebuggerClient &client) {
  client.helpTitle("Help Command");
  client.helpCmds(
    "[h]elp [s]tart", "displays material for getting started",
    "[h]elp [t]utorial on|off|auto", "changing tutorial modes",
    nullptr
  );
  client.helpBody(
    "Please read \"Getting Started\" material with '[h]elp [s]tart' for "
    "first time use to get yourself familiar with basics.\n"
    "\n"
    "Tutorial mode displays extra information when something didn't work "
    "as you expected. \"auto\" mode will display the same information just "
    "once. \"on\" mode will display it as long as you run into the same "
    "situation. \"off\" mode completely turns off all tutorial texts.\n"
    "\n"
    "To get detailed information of a command, type '{cmd} [h]elp' or '{cmd} "
    "?' or 'help {cmd}' or '? {cmd}'."
  );
}
Ejemplo n.º 26
0
void CmdThread::help(DebuggerClient &client) {
  client.helpTitle("Thread Command");
  client.helpCmds(
    "[t]hread",                 "displays current thread's information",
    "[t]hread [l]ist",          "lists all threads at break",
    "[t]hread {index}",         "switches to the specified thread",
    "[t]hread [n]ormal",        "breaks all threads",
    "[t]hread [s]ticky",        "only send command to current thread",
    "[t]hread [e]xclusive",     "only break current thread",
    nullptr
  );
  client.helpBody(
    "Use '[t]hread' alone to display information of current thread.\n"
    "\n"
    "When a thread is at break, you may specify how other threads should "
    "behave if they also happen to hit some breakpoints. Normally, other "
    "threads will also break, and they will interrupt debugger session "
    "with their breakpoints. So breaks from different threads may interleave. "
    "If '[t]hread [s]ticky' is specified, all other threads will wait until "
    "current thread is finished. This will help debugging to focus on just "
    "one thread without losing breaks from other threads. If there is no need "
    "to hold up any other threads, use '[t]hread [e]xclusive'. Then other "
    "threads will not break at all. This mode is useful for live debugging "
    "a production server, without interrupting many threads at a time. Use "
    "'[t]hread [n]ormal' to change thread mode back to normal.\n"
    "\n"
    "Some debugging commands will automatically turn thread mode to sticky. "
    "These include continue, step, next or out commands with a counter of "
    "more than 1. These commands imply non-interruption from another thread. "
    "The mode will remain even after these commands until '[t]hread [n]ormal' "
    "is issued."
    "\n"
    "When multple threads hit breakpoints at the same time, use '[t]hread "
    "[l]ist' command to display their indices, which can be used to switch "
    "between them with '[t]hread {index}'."
  );
}
Ejemplo n.º 27
0
void CmdMacro::help(DebuggerClient &client) {
  client.helpTitle("Macro Command");
  client.helpCmds(
    "& [s]tart",            "starts recording of default macro",
    "& [s]tart {name}",     "starts recording of a named macro",
    "& [e]nd",              "stops and saves recorded macro",
    "& [r]eplay",           "replays default macro",
    "& [r]eplay {name}",    "replays a named macro",
    "& [l]ist",             "lists all macros",
    "& [c]lear {index}",    "deletes a macro",
    nullptr
  );
  client.helpBody(
    "Macro command allows you to record a series of debugger command, so "
    "you can replay later by its name. When name is not specified, it will "
    "use \"default\" as the name.\n"
    "\n"
    "There is also a special macro \"startup\" that will be replayed "
    "every time when debugger is just started. Use startup macro to load "
    "certain PHP files or perform certain debugging environment setup.\n"
    "\n"
    "The space between & and command is not needed. '&s' works as well."
  );
}
Ejemplo n.º 28
0
void CmdHelp::HelpStarted(DebuggerClient &client) {
  client.helpTitle("Getting Started with Debugger");

  client.helpBody(
    "1. Quick Overview\n"
    "\n"
    "(1) from A to Z\n"
    "\n"
    "All built-in debugger commands are un-ambiguous with their first "
    "letters. Therefore, a single letter is sufficient to issue the "
    "command.\n"
    "\n"
    "(2) tab, tab, tab\n"
    "\n"
    "Use TAB to auto-complete.\n"
    "\n"
    "(3) input PHP code\n"
    "\n"
    "For single line of PHP code, use \"=\" to print an expression's value, "
    "OR, use \"@\" to execute an expression or statement without printing "
    "return values, OR, start an assignment with \"$\" variable name.\n\n"
    "For multi-line PHP code, type \"<\" then TAB. Now you can type or paste "
    "multiple lines of code. Hit return to start a new line, then TAB. That "
    "will auto-complete \"?>\" to finish the block. Hit return to execute.\n"
    "\n"
    "(4) help\n"
    "\n"
    "Use \"help\" to read more about command details.\n"
    "\n"
    "(5) info and list\n"
    "\n"
    "Use \"info\" and \"list\" commands to read more about source code.\n"
    "\n"
    "(6) readline\n"
    "\n"
    "Debugger is written with readline library, which has rich feature set, "
    "including switching between emacs and vi editing mode. Please read its "
    "[[ http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC1 | "
    "documentation]] for more details."
  );

  client.helpBody(
    "2. Debugging local script\n"
    "\n"
    "The command to run a script normally looks like this,\n"
    "\n"
    "  hhvm myscript.php\n"
    "\n"
    "Simply add \"-m debug\" to run the script in debugger,\n\n"
    "\n"
    "  hhvm -m debug myscript.php\n"
    "\n"
    "Once started, set breakpoints like this,\n"
    "\n"
    "  hphpd> break myscript.php:10\n"
    "  hphpd> break foo()\n"
    "\n"
    "Then let it run, until it hits the breakpoints,\n"
    "\n"
    "  hphpd> run\n"
    "\n"
    "The debugger will highlight current statement or expression that is "
    "just about to evaluate. Sometimes a statement is highlighted first, then "
    "sub-expressions inside the statement are highlighted one after another "
    "while repeating step commands.\n"
    "\n"
    "At any breakpoints, examine variables or evaluate expressions,\n"
    "\n"
    "  hphpd> variable\n"
    "  hphpd> print $a\n"
    "  hphpd> =$a\n"
    "  hphpd> <?php print $a; ?>\n"
    "  hphpd> <?php\n"
    "   ..... print $a;\n"
    "   ..... ?>\n"
    "\n"
    "Optionally, modify variables like this,\n"
    "\n"
    "  hphpd> $a = 10\n"
    "  hphpd> <?php $a = 10; ?>\n"
    "  hphpd> <?php\n"
    "   ..... $a = 10;\n"
    "   ..... ?>\n"
    "\n"
    "Then let it continue, until it hits more breakpoints,\n"
    "\n"
    "  hphpd> continue\n"
    "\n"
    "Finally, quit debugger,\n"
    "\n"
    "  hphpd> quit"
  );

  client.helpBody(
    "3. Debugging sandbox\n"
    "\n"
    "Connect to an HHVM server from command line,\n"
    "\n"
    "  hhvm -m debug -h mymachine.com\n"
    "\n"
    "Or, connect from within debugger,\n"
    "\n"
    "  hphpd> machine connect mymachine.com\n"
    "\n"
    "This will try to attach to a default sandbox on that machine. "
    "\"Attaching\" means it will only debug web requests hitting that "
    "sandbox. To switch to a different sandbox,\n"
    "\n"
    "  mymachine> machine list\n"
    "  mymachine> machine attach 2\n"
    "\n"
    "In remote debugging mode, a breakpoint can be specific about an URL,\n"
    "\n"
    "  mymachine> break myscript.php:[email protected]\n"
    "  mymachine> break foo()@index.php\n"
    "\n"
    "You may connect to more than one machine and breakpoints will be "
    "shared by all of them."
  );

  client.helpBody(
    "4. Understanding dummy sandbox\n"
    "\n"
    "When a web request hits a breakpoint, debugger will run in a "
    "\"Web Request\" thread. Use \"thread\" command to display this "
    "information,\n"
    "\n"
    "  mymachine> thread\n"
    "\n"
    "What will debugger use when there is no web request thread that's "
    "active, but we need to set a breakpoint? We created so-called "
    "\"dummy sandbox\", purely for taking debugger commands when there is "
    "no active web request. When there is no active request, hit Ctrl-C to "
    "break debugger, and use \"thread\" to display dummy sandbox thread's "
    "information.\n"
    "\n"
    "  Ctrl-C\n"
    "  mymachine> thread\n"
    "\n"
    "In dummy sandbox, a PHP file can be pre-loaded, so that we can "
    "\"info\" functions and classes and execute certain code. This file is "
    "specified on server side by\n"
    "\n"
    "  Eval.Debugger.StartupDocument = scripts/startup.php\n"
    "\n"
    "Dummy sandbox will always use currently attached sandbox's PHP files. "
    "When files are modified, simply reload them by\n"
    "\n"
    "  mymachine> continue\n"
    "  Ctrl-C"
  );

  client.helpBody(
    "5. Colors and Configuration\n"
    "\n"
    "By default, it will use emacs colors for dark background. To change "
    "them, run debugger at least once, then look for ~/.hphpd.hdf file. "
    "Replace \"Code\" node with,\n"
    "\n"
    "  Color {\n"
    "    Code : Color.Palette.vim\n"
    "  }\n"
    "\n"
    "Or, specify your own colors in different places of the configuration "
    "file."
  );
}