Variant f_hphpd_client_ctrl(CStrRef name, CStrRef op) { TRACE(5, "in f_hphpd_client_ctrl()\n"); DebuggerClient *client = NULL; std::string nameStr = name->toCPPString(); { DbgCltMap::const_accessor acc; if (!s_dbgCltMap.find(acc, nameStr)) { if (op.equal("getstate")) { return q_DebuggerClient$$STATE_INVALID; } else { raise_warning("client %s does not exist", name.data()); return uninit_null(); } } client = acc->second; } if (op.equal("interrupt")) { if (client->getClientState() < DebuggerClient::StateReadyForCommand) { raise_warning("client is not initialized"); return uninit_null(); } if (client->getClientState() != DebuggerClient::StateBusy) { raise_warning("client is not in a busy state"); return uninit_null(); } client->onSignal(SIGINT); return uninit_null(); } else if (op.equal("getstate")) { return client->getClientState(); } else if (op.equal("reset")) { // To handle the case when client is in a bad state, e.g. the grabbing // request encountered error and did not get chance to destruct or call // sweep. It will remove the client from the map. Here we'd rather take // the risk of leaking the client than the risk of chasing dangling // pointers. // // FIXME: it's unclear why it should be possible that we would not // get a chance to destruct or call sweep. return s_dbgCltMap.erase(nameStr); } raise_warning("unknown op %s", op.data()); return uninit_null(); }
Variant c_DebuggerClient::t_processcmd(CVarRef cmdName, CVarRef args) { INSTANCE_METHOD_INJECTION_BUILTIN(DebuggerClient, DebuggerClient::processcmd); if (!m_client || m_client->getClientState() < DebuggerClient::StateReadyForCommand) { raise_warning("client is not initialized"); return null; } if (m_client->getClientState() != DebuggerClient::StateReadyForCommand) { raise_warning("client is not ready to take command"); return null; } if (!cmdName.isString()) { raise_warning("cmdName must be string"); return null; } if (!args.isNull() && !args.isArray()) { raise_warning("args must be null or array"); return null; } static const char *s_allowedCmds[] = { "break", "continue", "down", "exception", "frame", "global", "help", "info", "konstant", "next", "out", "print", "quit", "step", "up", "variable", "where", "bt", "set", "inst", "=", "@", NULL }; bool allowed = false; for (int i = 0; ; i++) { const char *cmd = s_allowedCmds[i]; if (cmd == NULL) { break; } if (cmdName.same(cmd)) { allowed = true; break; } } if (!allowed) { raise_warning("unsupported command %s", cmdName.toString().data()); return null; } m_client->setCommand(cmdName.toString().data()); StringVec *clientArgs = m_client->args(); clientArgs->clear(); if (!args.isNull()) { for (ArrayIter iter(args.toArray()); iter; ++iter) { CStrRef arg = iter.second().toString(); clientArgs->push_back(std::string(arg.data(), arg.size())); } } try { if (!m_client->process()) { raise_warning("command \"%s\" not found", cmdName.toString().data()); } } catch (DebuggerConsoleExitException &e) { // Flow-control command goes here Logger::Info("wait for debugger client to stop"); m_client->setTakingInterrupt(); m_client->setClientState(DebuggerClient::StateBusy); DebuggerCommandPtr cmd = m_client->waitForNextInterrupt(); if (!cmd) { raise_warning("not getting a command"); } else if (cmd->is(DebuggerCommand::KindOfInterrupt)) { CmdInterruptPtr cmdInterrupt = dynamic_pointer_cast<CmdInterrupt>(cmd); cmdInterrupt->onClientD(m_client); } else { // Previous pending commands cmd->handleReply(m_client); cmd->setClientOutput(m_client); } Logger::Info("debugger client ready for command"); } catch (DebuggerClientExitException &e) { const std::string& nameStr = m_client->getNameApi(); Logger::Info("client %s disconnected", nameStr.c_str()); s_dbgCltMap.erase(nameStr); delete m_client; m_client = NULL; return true; } catch (DebuggerProtocolException &e) { raise_warning("DebuggerProtocolException"); return null; } return m_client->getOutputArray(); }