Arquivos
hhvm/hphp/runtime/debugger/debugger_command.cpp
T
Owen Yamauchi 739450013f Move runtime/eval/debugger to runtime/debugger
runtime/eval is now gone. Woooo

This is just a git mv + `codemod runtime/eval/debugger runtime/debugger`
2013-06-03 23:54:35 -07:00

212 linhas
8.2 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/debugger/debugger_command.h"
#include "hphp/runtime/debugger/debugger.h"
#include "hphp/runtime/debugger/cmd/all.h"
#include "hphp/util/logger.h"
#define POLLING_SECONDS 1
namespace HPHP { namespace Eval {
///////////////////////////////////////////////////////////////////////////////
TRACE_SET_MOD(debugger);
// Resets the buffer, serializes this command into the buffer and then
// flushes the buffer.
// Returns false if an exception occurs during these steps.
bool DebuggerCommand::send(DebuggerThriftBuffer &thrift) {
TRACE(5, "DebuggerCommand::send\n");
try {
thrift.reset(false);
sendImpl(thrift);
thrift.flush();
} catch (...) {
Logger::Error("DebuggerCommand::send(): a socket error has happened");
return false;
}
return true;
}
bool DebuggerCommand::recv(DebuggerThriftBuffer &thrift) {
TRACE(5, "DebuggerCommand::recv\n");
try {
recvImpl(thrift);
} catch (...) {
Logger::Error("DebuggerCommand::recv(): a socket error has happened");
return false;
}
return true;
}
// Always called from send and must implement the subclass specific
// logic for serializing a command to send via Thrift.
void DebuggerCommand::sendImpl(DebuggerThriftBuffer &thrift) {
TRACE(5, "DebuggerCommand::sendImpl\n");
thrift.write((int32_t)m_type);
thrift.write(m_class);
thrift.write(m_body);
thrift.write(m_version);
}
// Always called from recv and must implement the subclass specific
// logic for deserializing a command received via Thrift.
void DebuggerCommand::recvImpl(DebuggerThriftBuffer &thrift) {
TRACE(5, "DebuggerCommand::recvImpl\n");
thrift.read(m_body);
thrift.read(m_version);
}
bool DebuggerCommand::Receive(DebuggerThriftBuffer &thrift,
DebuggerCommandPtr &cmd, const char *caller) {
TRACE(5, "DebuggerCommand::Receive\n");
cmd.reset();
struct pollfd fds[1];
fds[0].fd = thrift.getSocket()->fd();
fds[0].events = POLLIN|POLLERR|POLLHUP;
int ret = poll(fds, 1, POLLING_SECONDS * 1000);
if (ret == 0) {
return false;
}
// Any error bits set indicate that we have nothing to read, so bail early.
if ((ret == -1) || (fds[0].revents != POLLIN)) {
return errno != EINTR; // treat signals as timeouts
}
int32_t type;
string clsname;
try {
thrift.reset(true);
thrift.read(type);
thrift.read(clsname);
} catch (...) {
Logger::Error("%s => DebuggerCommand::Receive(): socket error", caller);
return true;
}
TRACE(1, "DebuggerCommand::Receive: got cmd of type %d\n", type);
// not all commands are here, as not all commands need to be sent over wire
switch (type) {
case KindOfBreak : cmd = DebuggerCommandPtr(new CmdBreak ()); break;
case KindOfContinue : cmd = DebuggerCommandPtr(new CmdContinue ()); break;
case KindOfDown : cmd = DebuggerCommandPtr(new CmdDown ()); break;
case KindOfException: cmd = DebuggerCommandPtr(new CmdException()); break;
case KindOfFrame : cmd = DebuggerCommandPtr(new CmdFrame ()); break;
case KindOfGlobal : cmd = DebuggerCommandPtr(new CmdGlobal ()); break;
case KindOfInfo : cmd = DebuggerCommandPtr(new CmdInfo ()); break;
case KindOfConstant : cmd = DebuggerCommandPtr(new CmdConstant ()); break;
case KindOfList : cmd = DebuggerCommandPtr(new CmdList ()); break;
case KindOfMachine : cmd = DebuggerCommandPtr(new CmdMachine ()); break;
case KindOfNext : cmd = DebuggerCommandPtr(new CmdNext ()); break;
case KindOfOut : cmd = DebuggerCommandPtr(new CmdOut ()); break;
case KindOfPrint : cmd = DebuggerCommandPtr(new CmdPrint ()); break;
case KindOfQuit : cmd = DebuggerCommandPtr(new CmdQuit ()); break;
case KindOfRun : cmd = DebuggerCommandPtr(new CmdRun ()); break;
case KindOfStep : cmd = DebuggerCommandPtr(new CmdStep ()); break;
case KindOfThread : cmd = DebuggerCommandPtr(new CmdThread ()); break;
case KindOfUp : cmd = DebuggerCommandPtr(new CmdUp ()); break;
case KindOfVariable : cmd = DebuggerCommandPtr(new CmdVariable ()); break;
case KindOfWhere : cmd = DebuggerCommandPtr(new CmdWhere ()); break;
case KindOfUser : cmd = DebuggerCommandPtr(new CmdUser ()); break;
case KindOfEval : cmd = DebuggerCommandPtr(new CmdEval ()); break;
case KindOfInterrupt: cmd = DebuggerCommandPtr(new CmdInterrupt()); break;
case KindOfSignal : cmd = DebuggerCommandPtr(new CmdSignal ()); break;
case KindOfShell : cmd = DebuggerCommandPtr(new CmdShell ()); break;
case KindOfExtended: {
assert(!clsname.empty());
cmd = CmdExtended::CreateExtendedCommand(clsname);
assert(cmd);
break;
}
default:
assert(false);
Logger::Error("%s => DebuggerCommand::Receive(): bad cmd type: %d",
caller, type);
return true;
}
if (!cmd->recv(thrift)) {
Logger::Error("%s => DebuggerCommand::Receive(): socket error", caller);
cmd.reset();
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// default handlers
// Informs the client of all argument strings that may follow this command
// name. Used for auto completion. The client uses the prefix of the argument
// following the command name to narrow down the list displayed to the user.
void DebuggerCommand::list(DebuggerClient &client) {
TRACE(2, "DebuggerCommand::list\n");
}
// The text to display when the debugger client
// processes "help <this command name>".
void DebuggerCommand::help(DebuggerClient &client) {
TRACE(2, "DebuggerCommand::help\n");
assert(false);
}
// 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;
}
// Carries out the command, possibly by sending it to the server.
// If the client is controlled via the API, the setClientOuput method
// is invoked to update the client with the command output for access
// via the API.
void DebuggerCommand::onClient(DebuggerClient &client) {
TRACE(2, "DebuggerCommand::onClient\n");
onClientImpl(client);
if (client.isApiMode() && !m_incomplete) {
setClientOutput(client);
}
}
// Updates the client with information about the execution of this command.
// This information is not used by the command line client, but can
// be accessed via the debugger client API exposed to PHP programs.
void DebuggerCommand::setClientOutput(DebuggerClient &client) {
TRACE(2, "DebuggerCommand::setClientOutput\n");
// Just default to text
client.setOutputType(DebuggerClient::OTText);
}
// Server-side work for a command. Returning false indicates a failure to
// communicate with the client (for commands that do so).
bool DebuggerCommand::onServer(DebuggerProxy &proxy) {
TRACE(2, "DebuggerCommand::onServer\n");
assert(false);
Logger::Error("DebuggerCommand::onServer(): bad cmd type: %d", m_type);
return false;
}
///////////////////////////////////////////////////////////////////////////////
}}