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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}