void CmdInstrument::listInst(DebuggerClient &client) { m_type = ActionRead; m_instPoints = client.getInstPoints(); CmdInstrumentPtr instCmdPtr = client.xend<CmdInstrument>(this); client.setInstPoints(instCmdPtr->m_ips); PrintInstPoints(client); }
bool CmdMachine::AttachSandbox(DebuggerClient &client, DSandboxInfoPtr sandbox, bool force /* = false */) { if (client.isLocal()) { client.error("Local script doesn't have sandbox to attach to."); return false; } CmdMachine cmd; cmd.m_body = "attach"; cmd.m_sandboxes.push_back(sandbox); cmd.m_force = force; client.info("Attaching to %s and pre-loading, please wait...", sandbox->desc().c_str()); CmdMachinePtr cmdMachine = client.xend<CmdMachine>(&cmd); if (cmdMachine->m_succeed) { client.playMacro("startup"); } else { // Note: it would be nice to give them more info about the process we think // is debugging this sandbox: what machine it's on, what it's pid is, etc. // Unfortunately, we don't have any of that data. We'd need a protocol // change to have the client give us more info when it attaches. client.error( "Failed to attach to the sandbox. Maybe another client is debugging, \n" "or a client failed to detach cleanly.\n" "You can attach to another sandbox, or exit the other attached client, \n" "or force this client to take over the sandbox with: \n" "\n" "\t[m]achine [a]ttach [f]orce %s %s" "\n", sandbox->m_user.c_str(), sandbox->m_name.c_str()); } return cmdMachine->m_succeed; }
void CmdHeaptrace::onClient(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; String format; String file; if (client.argCount() == 3) { format = client.argValue(2); file = client.argValue(3); } else if (client.argCount() != 1) { help(client); return; } CmdHeaptracePtr cmd = client.xend<CmdHeaptrace>(this); if (file.empty()) { cmd->printHeap(client); } else { std::string formatStr = format->data(); const auto it = s_formatMap.find(formatStr); if (it == s_formatMap.end()) { client.print("Unsupported format type"); return; } cmd->printGraphToFile(client, file, it->second); } }
void CmdMachine::list(DebuggerClient &client) { if (client.argCount() == 0) { static const char *keywords[] = { "disconnect", "connect", "rpc", "list", "attach", nullptr }; client.addCompletion(keywords); } }
void CmdException::onClientImpl(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; if (client.argCount() == 0) { help(client); return; } bool regex = false; BreakPointInfo::State state = BreakPointInfo::Always; int index = 1; if (client.arg(1, "regex")) { regex = true; index++; } else if (client.arg(1, "once")) { state = BreakPointInfo::Once; index++; } BreakPointInfoPtr bpi(new BreakPointInfo(regex, state, ExceptionThrown, client.argValue(index), "")); if (!addToBreakpointListAndUpdateServer(client, bpi, index)) { client.tutorial( "This is the order of different arguments:\n" "\n" "\t[e]xception [r]egex|[o]nce {exp} if|&& {php}\n" "\n" "These are the components in an exception {exp}:\n" "\n" "\terror@{url}" "\t{namespace}::{cls}@{url}" "\n" ); } }
bool CmdMachine::processList(DebuggerClient &client, bool output /* = true */) { m_body = "list"; CmdMachinePtr res = client.xend<CmdMachine>(this); client.updateSandboxes(res->m_sandboxes); if (!output) return true; if (res->m_sandboxes.empty()) { client.info("(no sandbox was found)"); client.tutorial( "Please hit the sandbox from browser at least once. Then run " "'[m]achine [l]ist' again." ); } else { for (int i = 0; i < (int)res->m_sandboxes.size(); i++) { client.print(" %d\t%s", i + 1, res->m_sandboxes[i]->desc().c_str()); } client.tutorial( "Use '[m]achine [a]ttach {index}' to attach to one sandbox. For " "example, 'm a 1'. If desired sandbox is not on the list, please " "hit the sandbox from browser once. Then run '[m]achine [l]ist' " "again." ); } return true; }
void CmdEval::setClientOutput(DebuggerClient &client) { client.setOutputType(DebuggerClient::OTValues); ArrayInit values(2); values.set(s_body, m_body); values.set(s_value, m_output); client.setOTValues(values.create()); }
void CmdMacro::list(DebuggerClient &client) { if (client.argCount() == 0) { static const char *keywords[] = { "start", "end", "replay", "list", "clear", nullptr}; client.addCompletion(keywords); } }
void CmdHeaptrace::printHeap(DebuggerClient &client) { for (const auto &pair : m_accum.typesMap) { size_t size = m_accum.sizeMap[pair.first]; std::string sizeStr = size ? folly::stringPrintf(" which consumes %lu bytes", size) : std::string(); client.print( folly::stringPrintf("Found TV at %p with type %s%s", (void *)pair.first, typeName(pair.second), sizeStr.c_str())); std::vector<int64_t> &adjList = m_accum.adjacencyList[pair.first]; if (!adjList.empty()) { std::string children = " -> found children: "; bool first = true; for (const int64_t &adjacent : adjList) { if (!first) { children += ", "; } children += folly::stringPrintf("%p", (void *)adjacent); first = false; } client.print(children); } } }
void CmdThread::list(DebuggerClient &client) { if (client.argCount() == 0) { static const char *keywords[] = { "list", "normal", "sticky", "exclusive", nullptr }; client.addCompletion(keywords); } }
// 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." ); }
void CmdHeaptrace::printGraphToFile(DebuggerClient &client, String filename, const GraphFormat &gf) { const char *name = filename->data(); FILE *graphFile = fopen(name, "w"); if (!graphFile) { client.print("Could not open file!"); return; } fprintf(graphFile, "%s", gf.prologue.c_str()); for (const auto &pair : m_accum.typesMap) { std::string n = gf.stringifyNode((TypedValue *)pair.first, typeName(pair.second)); fprintf(graphFile, "%s", n.c_str()); std::vector<int64_t> &adjList = m_accum.adjacencyList[pair.first]; for (const int64_t adjacent : adjList) { std::string e = gf.stringifyEdge((TypedValue *)pair.first, (TypedValue *)adjacent); fprintf(graphFile, "%s", e.c_str()); } } fprintf(graphFile, "%s", gf.epilogue.c_str()); fclose(graphFile); client.print(folly::stringPrintf("Wrote heap graph to %s.", name)); }
bool CmdMachine::AttachSandbox(DebuggerClient &client, DSandboxInfoPtr sandbox, bool force /* = false */) { if (client.isLocal()) { client.error("Local script doesn't have sandbox to attach to."); return false; } CmdMachine cmd; cmd.m_body = "attach"; cmd.m_sandboxes.push_back(sandbox); cmd.m_force = force; client.info("Attaching to %s and pre-loading, please wait...", sandbox->desc().c_str()); CmdMachinePtr cmdMachine = client.xend<CmdMachine>(&cmd); if (cmdMachine->m_succeed) { client.playMacro("startup"); } else { client.error("failed to attach to sandbox, maybe another client is " "debugging, \nattach to another sandbox, exit the " "attached hphpd client, or try \n" "[m]achine [a]ttach [f]orce [%s] [%s]", sandbox->m_user.c_str(), sandbox->m_name.c_str()); } return cmdMachine->m_succeed; }
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." ); }
void CmdMacro::processList(DebuggerClient &client) { const MacroPtrVec ¯os = client.getMacros(); for (unsigned int i = 0; i < macros.size(); i++) { MacroPtr macro = macros[i]; client.output("%4d %s", i + 1, macro->m_name.c_str()); client.print("%s", macro->desc(" > ").c_str()); } }
// If the first argument of the command is "help" or "?" // this displays help text for the command and returns true. // Otherwise it returns false. bool DebuggerCommand::displayedHelp(DebuggerClient &client) { TRACE(2, "DebuggerCommand::displayedHelp\n"); if (client.arg(1, "help") || client.arg(1, "?")) { help(client); return true; } return false; }
void CmdInstrument::clearInst(DebuggerClient &client) { m_type = ActionWrite; m_instPoints = client.getInstPoints(); m_instPoints->clear(); CmdInstrumentPtr instCmdPtr = client.xend<CmdInstrument>(this); client.setInstPoints(instCmdPtr->m_ips); PrintInstPoints(client); }
void CmdComplete::onClient(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; std::string text = client.lineRest(1); std::vector<std::string> res = client.getAllCompletions(text); for (size_t i = 0; i < res.size(); ++i) { client.print("%s", res[i].c_str()); } }
void CmdEval::handleReply(DebuggerClient &client) { if (this->failed() && client.unknownCmdReceived()) { client.help( "Notice: Attempted to interpret unknown debugger command as PHP!\n"); } if (!m_output.empty()) client.print(m_output); }
void CmdEval::onClient(DebuggerClient &client) { m_body = client.getCode(); m_frame = client.getFrame(); m_bypassAccessCheck = client.getDebuggerClientBypassCheck(); auto res = client.xendWithNestedExecution<CmdEval>(this); res->handleReply(client); m_failed = res->m_failed; }
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." ); }
void CmdFrame::onClient(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; if (client.argCount() != 1) { help(client); } else { CmdWhere().fetchStackTrace(client); client.moveToFrame(CmdUp::ParseNumber(client)); } }
void CmdRun::onClientImpl(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; m_args = StringVecPtr(client.args(), null_deleter()); m_smallStep = client.getDebuggerSmallStep(); client.sendToServer(this); client.clearCachedLocal(); client.setFrame(0); throw DebuggerConsoleExitException(); }
// If there is no current file, print the desired range of eval code // or give an error message if the debugger is not currently performing // an eval command. void CmdList::listEvalCode(DebuggerClient &client) { assert(m_file.empty()); std::string evalCode = client.getCode(); if (evalCode.empty()) { client.error("There is no current source file."); } else { client.print(highlight_php(evalCode)); } }
void CmdExtension::onClient(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; m_args = *client.args(); auto cmd = client.xend<CmdExtension>(this); if (cmd->m_out.empty()) { client.error(cmd->m_err); } else { client.print(cmd->m_out); } }
Array CmdWhere::fetchStackTrace(DebuggerClient &client) { Array st = client.getStackTrace(); if (st.isNull()) { m_stackArgs = client.getDebuggerStackArgs(); CmdWherePtr cmd = client.xend<CmdWhere>(this); st = cmd->m_stacktrace; client.setStackTrace(st); } return st; }
void CmdEval::onClient(DebuggerClient &client) { m_body = client.getCode(); m_frame = client.getFrame(); m_bypassAccessCheck = client.getDebuggerClientBypassCheck(); auto res = client.xendWithNestedExecution<CmdEval>(this); assertx(res->is(DebuggerCommand::KindOfEval)); auto eval = std::static_pointer_cast<CmdEval>(res); eval->handleReply(client); m_failed = eval->m_failed; }
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." ); }
void CmdShell::onClientImpl(DebuggerClient &client) { if (DebuggerCommand::displayedHelp(client)) return; if (client.argCount() == 0) { help(client); return; } m_args = *client.args(); CmdShellPtr cmd = client.xend<CmdShell>(this); client.print(cmd->m_out); }
void CmdRun::onClient(DebuggerClient &client) { TRACE(2, "CmdRun::onClient\n"); if (DebuggerCommand::displayedHelp(client)) return; m_args = StringVecPtr(client.args(), null_deleter()); client.sendToServer(this); client.clearCachedLocal(); client.setFrame(0); throw DebuggerConsoleExitException(); }