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(); }
Variant c_DebuggerClient::t_init(CVarRef options) { INSTANCE_METHOD_INJECTION_BUILTIN(DebuggerClient, DebuggerClient::init); if (!m_client) { raise_warning("invalid client"); return false; } if (m_client->getClientState() != DebuggerClient::StateUninit) { return m_client->getClientState() == DebuggerClient::StateReadyForCommand; } if (!options.isArray()) { raise_warning("options must be an array"); return false; } m_client->setClientState(DebuggerClient::StateInitializing); DebuggerClientOptions ops; ops.apiMode = true; Array opsArr = options.toArray(); if (opsArr.exists("user")) { ops.user = opsArr.rvalAtRef("user").toString().data(); } else { raise_warning("must specify user in options"); return false; } if (opsArr.exists("configFName")) { ops.configFName = opsArr.rvalAtRef("configFName").toString().data(); FILE *f = fopen(ops.configFName.c_str(), "r"); if (!f) { raise_warning("cannot access config file %s", ops.configFName.c_str()); return false; } fclose(f); } if (opsArr.exists("host")) { ops.host = opsArr.rvalAtRef("host").toString().data(); } if (opsArr.exists("port")) { ops.port = opsArr.rvalAtRef("port").toInt32(); } if (opsArr.exists("sandbox")) { ops.sandbox = opsArr.rvalAtRef("sandbox").toString().data(); } m_client->init(ops); if (ops.host.empty()) { ops.host = "localhost"; } if (ops.port < 0) { ops.port = RuntimeOption::DebuggerServerPort; } bool ret = m_client->connect(ops.host, ops.port); if (!ret) { raise_warning("failed to connect to hhvm %s:%d", ops.host.c_str(), ops.port); return false; } // To wait for the session start interrupt DebuggerCommandPtr cmd = m_client->waitForNextInterrupt(); if (!cmd->is(DebuggerCommand::KindOfInterrupt) || dynamic_pointer_cast<CmdInterrupt>(cmd)->getInterruptType() != SessionStarted) { raise_warning("failed to load sandbox"); return false; } ret = m_client->initializeMachine(); if (!ret) { raise_warning("failed to initialize machine info"); return false; } // To wait for the machine loading sandbox cmd = m_client->waitForNextInterrupt(); if (!cmd->is(DebuggerCommand::KindOfInterrupt) || dynamic_pointer_cast<CmdInterrupt>(cmd)->getInterruptType() != SessionStarted) { raise_warning("failed to load sandbox"); return false; } m_client->setClientState(DebuggerClient::StateReadyForCommand); return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar) { if (Loaded) return true; Loaded = true; if (g_context.isNull()) init_thread_locals(); ClassInfo::Load(); // load extension functions first, so system/php may call them ImportExtFunctions(ar, ClassInfo::GetSystem()); ConstantTablePtr cns = ar->getConstants(); // load extension constants, classes and dynamics ImportNativeConstants(ar, cns); ImportExtConstants(ar, cns, ClassInfo::GetSystem()); ImportExtClasses(ar); Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (cns->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar, ar, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; cns->add(key.toCStrRef().data(), t, e, ar, e); } for (int i = 0, n = NumGlobalNames(); i < n; ++i) { ar->getVariables()->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } cns->setDynamic(ar, "PHP_BINARY", true); cns->setDynamic(ar, "PHP_BINDIR", true); cns->setDynamic(ar, "PHP_OS", true); cns->setDynamic(ar, "PHP_SAPI", true); cns->setDynamic(ar, "SID", true); // Systemlib files were all parsed by hphp_process_init const StringToFileScopePtrMap &files = ar->getAllFiles(); for (const auto& file : files) { file.second->setSystem(); const auto& classes = file.second->getClasses(); for (const auto& clsVec : classes) { assert(clsVec.second.size() == 1); auto cls = clsVec.second[0]; cls->setSystem(); ar->addSystemClass(cls); for (const auto& func : cls->getFunctions()) { FunctionScope::RecordFunctionInfo(func.first, func.second); } } const auto& functions = file.second->getFunctions(); for (const auto& func : functions) { func.second->setSystem(); ar->addSystemFunction(func.second); FunctionScope::RecordFunctionInfo(func.first, func.second); } } return true; }
bool TestMessage::fromJson(CVarRef json) { if (!json.isArray()) { printf("Invalid format of a message\n"); return false; } Array arr = json.toArray(); if (!arr.exists(String("command"))) { printf("Key 'command' missing from the message\n"); return false; } if (!arr[String("command")].isString()) { printf("Invalid command in message\n"); return false; } String command = arr[String("command")].toString(); if (command == String("send") || command == String("recv")) { if (command == String("send")) { m_command = Command::SEND; } else { CHECK(command == String("recv")); m_command = Command::RECV; } if (arr.exists(String("message"))) { if (!arr[String("message")].isString()) { printf("Invalid value for key 'message'\n"); return false; } String message = arr[String("message")].toString(); bodyFromStr(message); } else if (arr.exists(String("length"))) { if (!arr[String("length")].isInteger()) { printf("Invalid value for key 'length'\n"); return false; } int length = arr[String("length")].toInt32(); m_body.resize(length); m_mask.clear(); m_mask.resize(length); } else { printf("Keys 'message' or 'length' missing from a message\n"); return false; } } else if (command == String("close")) { m_command = Command::CLOSE; } else if (command == String("recv_close")) { m_command = Command::RECV_CLOSE; } else if (command == String("call")) { m_command = Command::CALL; if (!arr.exists(String("args"))) { printf("Key 'args' missing from a CALL message\n"); return false; } if (!arr[String("args")].isArray()) { printf("Invalid key 'args' in a CALL message\n"); return false; } m_args.clear(); Array args = arr[String("args")].toArray(); for (ArrayIter it(args); it; ++it) { if (!it.first().isString()) { printf("Invalid element of 'args'\n"); return false; } m_args[it.first().toString().data()] = it.second(); } } else { printf("Invalid commmand: %s\n", command.data()); return false; } return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) { if (Loaded) return true; Loaded = true; // load extension functions first, so system/classes may call them ParseExtFunctions(ar, ExtensionFunctions, false); AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult()); s_variables = VariableTablePtr(new VariableTable(*ar2.get())); s_constants = ConstantTablePtr(new ConstantTable(*ar2.get())); // parse all PHP files under system/classes if (!extOnly) { ar = AnalysisResultPtr(new AnalysisResult()); ar->loadBuiltinFunctions(); string slib = systemlib_path(); if (slib.empty()) { for (const char **cls = SystemClasses; *cls; cls++) { string phpBaseName = "/system/classes/"; phpBaseName += *cls; phpBaseName += ".php"; Parse(ar, phpBaseName, Option::GetSystemRoot() + phpBaseName); } } else { Parse(ar, slib, slib); } ar->analyzeProgram(true); ar->inferTypes(); const StringToFileScopePtrMap &files = ar->getAllFiles(); for (StringToFileScopePtrMap::const_iterator iterFile = files.begin(); iterFile != files.end(); iterFile++) { const StringToClassScopePtrVecMap &classes = iterFile->second->getClasses(); for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(); iter != classes.end(); ++iter) { assert(iter->second.size() == 1); iter->second[0]->setSystem(); assert(!s_classes[iter->first]); s_classes[iter->first] = iter->second[0]; } } } else { NoSuperGlobals = true; } // load extension constants, classes and dynamics ParseExtConsts(ar, ExtensionConsts, false); ParseExtClasses(ar, ExtensionClasses, false); for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) { Option::SepExtensionOptions &options = Option::SepExtensions[i]; string soname = options.soname; if (soname.empty()) { soname = string("lib") + options.name + ".so"; } if (!options.lib_path.empty()) { soname = options.lib_path + "/" + soname; } if (!LoadSepExtensionSymbols(ar, options.name, soname)) { return false; } } if (!extOnly) { Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (s_constants->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; s_constants->add(key.toCStrRef().data(), t, e, ar2, e); } s_variables = ar2->getVariables(); for (int i = 0, n = NumGlobalNames(); i < n; ++i) { s_variables->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } } s_constants->setDynamic(ar, "SID", true); return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) { if (Loaded) return true; Loaded = true; if (g_context.isNull()) init_thread_locals(); ClassInfo::Load(); // load extension functions first, so system/classes may call them ImportExtFunctions(ar, s_functions, ClassInfo::GetSystem()); AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult()); s_variables = VariableTablePtr(new VariableTable(*ar2.get())); s_constants = ConstantTablePtr(new ConstantTable(*ar2.get())); // parse all PHP files under system/classes if (!extOnly) { ar = AnalysisResultPtr(new AnalysisResult()); ar->loadBuiltinFunctions(); string slib = get_systemlib(); Scanner scanner(slib.c_str(), slib.size(), Option::ScannerType, "systemlib.php"); Compiler::Parser parser(scanner, "systemlib.php", ar); if (!parser.parse()) { Logger::Error("Unable to parse systemlib.php: %s", parser.getMessage().c_str()); assert(false); } ar->analyzeProgram(true); ar->inferTypes(); const StringToFileScopePtrMap &files = ar->getAllFiles(); for (StringToFileScopePtrMap::const_iterator iterFile = files.begin(); iterFile != files.end(); iterFile++) { const StringToClassScopePtrVecMap &classes = iterFile->second->getClasses(); for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(); iter != classes.end(); ++iter) { assert(iter->second.size() == 1); iter->second[0]->setSystem(); assert(!s_classes[iter->first]); s_classes[iter->first] = iter->second[0]; } } } else { NoSuperGlobals = true; } // load extension constants, classes and dynamics ImportExtConstants(ar, s_constants, ClassInfo::GetSystem()); ImportExtClasses(ar); if (!extOnly) { Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (s_constants->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; s_constants->add(key.toCStrRef().data(), t, e, ar2, e); } s_variables = ar2->getVariables(); for (int i = 0, n = NumGlobalNames(); i < n; ++i) { s_variables->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } } s_constants->setDynamic(ar, "SID", true); return true; }