b24d2f2016
There was a similar-but-different event loop used when receiving command results from the server which was close, but not quite right. Unified it with the main event loop to ensure that all error cases are handled properly when we put up a prompt at a nested interrupt, like when hitting a breakpoint during an eval. The event loop is now shared, with a few different "kinds" to control some of the special needs of the loop when executed from a command. Most commands don't cause the server to run more PHP, so they don't change the machine state or cause more interrupts. But some do (Eval and Print) and certainly the top-level loop does, too. Made sure to throw a protocol error if any command causes this to happen when we don't expect it.
82 linhas
2.9 KiB
C++
82 linhas
2.9 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/cmd/cmd_eval.h"
|
|
#include "hphp/runtime/vm/debugger_hook.h"
|
|
|
|
namespace HPHP { namespace Eval {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRACE_SET_MOD(debugger);
|
|
|
|
void CmdEval::sendImpl(DebuggerThriftBuffer &thrift) {
|
|
DebuggerCommand::sendImpl(thrift);
|
|
thrift.write(m_output);
|
|
thrift.write(m_frame);
|
|
thrift.write(m_bypassAccessCheck);
|
|
}
|
|
|
|
void CmdEval::recvImpl(DebuggerThriftBuffer &thrift) {
|
|
DebuggerCommand::recvImpl(thrift);
|
|
thrift.read(m_output);
|
|
thrift.read(m_frame);
|
|
thrift.read(m_bypassAccessCheck);
|
|
}
|
|
|
|
void CmdEval::onClientImpl(DebuggerClient &client) {
|
|
m_body = client.getCode();
|
|
m_frame = client.getFrame();
|
|
m_bypassAccessCheck = client.getDebuggerBypassCheck();
|
|
DebuggerCommandPtr res =
|
|
client.xendWithNestedExecution<DebuggerCommand>(this);
|
|
if (!res->is(m_type)) {
|
|
assert(client.isApiMode());
|
|
m_incomplete = true;
|
|
res->setClientOutput(client);
|
|
} else {
|
|
res->handleReply(client);
|
|
}
|
|
}
|
|
|
|
void CmdEval::handleReply(DebuggerClient &client) {
|
|
client.print(m_output);
|
|
}
|
|
|
|
static const StaticString s_body("body");
|
|
static const StaticString s_value("value");
|
|
|
|
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());
|
|
}
|
|
|
|
bool CmdEval::onServer(DebuggerProxy &proxy) {
|
|
PCFilter* locSave = g_vmContext->m_lastLocFilter;
|
|
g_vmContext->m_lastLocFilter = new PCFilter();
|
|
g_vmContext->setDebuggerBypassCheck(m_bypassAccessCheck);
|
|
DebuggerProxy::ExecutePHP(m_body, m_output, !proxy.isLocal(), m_frame);
|
|
g_vmContext->setDebuggerBypassCheck(false);
|
|
delete g_vmContext->m_lastLocFilter;
|
|
g_vmContext->m_lastLocFilter = locSave;
|
|
return proxy.sendToClient(this);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}}
|