static int execute_program_impl()

in hphp/runtime/base/program-functions.cpp [1511:2313]


static int execute_program_impl(int argc, char** argv) {
  std::string usage = "Usage:\n\n   ";
  usage += argv[0];
  usage += " [-m <mode>] [<options>] [<arg1>] [<arg2>] ...\n\nOptions";

  ProgramOptions po;
  options_description desc(usage.c_str());
  desc.add_options()
    ("help", "display this message")
    ("version", "display version number")
    ("modules", "display modules")
    ("info", "PHP information")
    ("php", "emulate the standard php command line")
    ("compiler-id", "display the git hash for the compiler")
    ("repo-schema", "display the repository schema id")
    ("mode,m", value<std::string>(&po.mode)->default_value("run"),
     "run | debug (d) | vsdebug | server (s) | daemon | replay | "
     "translate (t) | verify | getoption | eval")
    ("interactive,a", "Shortcut for --mode debug") // -a is from PHP5
    ("config,c", value<std::vector<std::string>>(&po.config)->composing(),
     "load specified config file")
    ("config-value,v",
     value<std::vector<std::string>>(&po.confStrings)->composing(),
     "individual configuration string in a format of name=value, where "
     "name can be any valid configuration for a config file")
    ("define,d", value<std::vector<std::string>>(&po.iniStrings)->composing(),
     "define an ini setting in the same format ( foo[=bar] ) as provided in a "
     ".ini file")
    ("no-config", "don't use the default php.ini")
    ("port,p", value<int>(&po.port)->default_value(-1),
     "start an HTTP server at specified port")
    ("port-fd", value<int>(&po.portfd)->default_value(-1),
     "use specified fd instead of creating a socket")
    ("ssl-port-fd", value<int>(&po.sslportfd)->default_value(-1),
     "use specified fd for SSL instead of creating a socket")
    ("admin-port", value<int>(&po.admin_port)->default_value(-1),
     "start admin listener at specified port")
    ("debug-config", value<std::string>(&po.debugger_options.configFName),
      "load specified debugger config file")
    ("debug-host,h",
     value<std::string>(&po.debugger_options.host)->implicit_value("localhost"),
     "connect to debugger server at specified address")
    ("debug-port", value<int>(&po.debugger_options.port)->default_value(-1),
     "connect to debugger server at specified port")
    ("debug-extension", value<std::string>(&po.debugger_options.extension),
     "PHP file that extends command 'arg'")
    ("debug-cmd", value<std::vector<std::string>>(
     &po.debugger_options.cmds)->composing(),
     "executes this debugger command and returns its output in stdout")
    ("debug-sandbox",
     value<std::string>(&po.debugger_options.sandbox)->default_value("default"),
     "initial sandbox to attach to when debugger is started")
    ("user,u", value<std::string>(&po.user),
     "run server under this user account")
    ("file,f", value<std::string>(&po.file),
     "execute specified file")
    ("lint,l", value<std::string>(&po.lint),
     "lint specified file")
    ("show,w", value<std::string>(&po.show),
     "output specified file and do nothing else")
    ("check-repo", "attempt to load repo and then exit")
    ("temp-file",
     "file specified is temporary and removed after execution")
    ("count", value<int>(&po.count)->default_value(1),
     "how many times to repeat execution")
    ("no-safe-access-check",
      value<bool>(&po.noSafeAccessCheck)->default_value(false),
     "whether to ignore safe file access check")
    ("arg", value<std::vector<std::string>>(&po.args)->composing(),
     "arguments")
    ("extra-header", value<std::string>(&Logger::ExtraHeader),
     "extra-header to add to log lines")
    ("build-id", value<std::string>(&po.buildId),
     "unique identifier of compiled server code")
    ("instance-id", value<std::string>(&po.instanceId),
     "unique identifier of server instance")
    ("xhprof-flags", value<int>(&po.xhprofFlags)->default_value(0),
     "Set XHProf flags")
    ("vsDebugPort", value<int>(&po.vsDebugPort)->default_value(-1),
      "Debugger TCP port to listen on for the VS Code debugger extension")
    ("vsDebugDomainSocketPath",
      value<std::string>(&po.vsDebugDomainSocket)->default_value(""),
      "Debugger port to listen on for the VS Code debugger extension")
    ("vsDebugNoWait", value<bool>(&po.vsDebugNoWait)->default_value(false),
      "Indicates the debugger should not block script startup waiting for "
      "a debugger client to attach. Only applies if vsDebugPort or "
        "vsDebugDomainSocketPath is specified.")
    ;

  positional_options_description p;
  p.add("arg", -1);
  variables_map vm;

  // Before invoking the boost command line parser, we do a manual pass
  // to find the first occurrence of either "--" or a non-option argument
  // in order to determine which arguments should be consumed by HHVM and
  // which arguments should be passed along to the PHP application. This
  // is necessary so that the boost command line parser doesn't choke on
  // args intended for the PHP application.
  int hhvm_argc = compute_hhvm_argc(desc, argc, argv);
  // Need to have a parent try for opts so I can use opts in the catch of
  // one of the sub-tries below.
  try {
    // Invoke the boost command line parser to parse the args for HHVM.
    auto opts = command_line_parser(hhvm_argc, argv)
      .options(desc)
      .positional(p)
      // If these style options are changed, compute_hhvm_argc() will
      // need to be updated appropriately
      .style(command_line_style::default_style &
             ~command_line_style::allow_guessing &
             ~command_line_style::allow_sticky &
             ~command_line_style::long_allow_adjacent)
      .run();
    try {
      // Manually append the args for the PHP application.
      int pos = 0;
      for (unsigned m = 0; m < opts.options.size(); ++m) {
        const auto& bo = opts.options[m];
        if (bo.string_key == "arg") {
          ++pos;
        }
      }
      for (unsigned m = hhvm_argc; m < argc; ++m) {
        std::string str = argv[m];
        basic_option<char> bo;
        bo.string_key = "arg";
        bo.position_key = pos++;
        bo.value.push_back(str);
        bo.original_tokens.push_back(str);
        bo.unregistered = false;
        bo.case_insensitive = false;
        opts.options.push_back(bo);
      }
      // Process the options
      store(opts, vm);
      notify(vm);
      if (vm.count("interactive") /* or -a */) po.mode = "debug";
      else if (po.mode.empty()) po.mode = "run";
      else if (po.mode == "d") po.mode = "debug";
      else if (po.mode == "s") po.mode = "server";
      else if (po.mode == "t") po.mode = "translate";

      if (!set_execution_mode(po.mode)) {
        Logger::Error("Error in command line: invalid mode: %s",
                      po.mode.c_str());
        cout << desc << "\n";
        return -1;
      }
      if (po.config.empty() && !vm.count("no-config")
          && ::getenv("HHVM_NO_DEFAULT_CONFIGS") == nullptr) {
        auto file_callback = [&po] (const char *filename) {
          Logger::Verbose("Using default config file: %s", filename);
          po.config.push_back(filename);
        };
        add_default_config_files_globbed(DEFAULT_CONFIG_DIR "/php*.ini",
                                         file_callback);
        add_default_config_files_globbed(DEFAULT_CONFIG_DIR "/config*.hdf",
                                         file_callback);
      }
      const auto env_config = ::getenv("HHVM_CONFIG_FILE");
      if (env_config != nullptr) {
        add_default_config_files_globbed(
          env_config,
          [&po](const char* filename) {
            Logger::Verbose("Using config file from environment: %s", filename);
            po.config.push_back(filename);
          }
        );
      }
    } catch (const error &e) {
      Logger::Error("Error in command line: %s", e.what());
      cout << desc << "\n";
      return -1;
    } catch (...) {
      Logger::Error("Error in command line.");
      cout << desc << "\n";
      return -1;
    }
  } catch (const error &e) {
    Logger::Error("Error in command line: %s", e.what());
    cout << desc << "\n";
    return -1;
  } catch (...) {
    Logger::Error("Error in command line parsing.");
    cout << desc << "\n";
    return -1;
  }
  // reuse -h for help command if possible
  if (vm.count("help") || (vm.count("debug-host") && po.mode != "debug")) {
    cout << desc << "\n";
    return 0;
  }
  if (vm.count("version")) {
    cout << "HipHop VM";
    cout << " " << HHVM_VERSION;
    cout << " (" << (debug ? "dbg" : "rel") << ")";
    cout << " (" << (use_lowptr ? "lowptr" : "non-lowptr") << ")\n";
    cout << "Compiler: " << compilerId() << "\n";
    cout << "Repo schema: " << repoSchemaId() << "\n";
    return 0;
  }
  if (vm.count("modules")) {
    tl_heap.getCheck();
    Array exts = ExtensionRegistry::getLoaded();
    cout << "[PHP Modules]" << "\n";
    for (ArrayIter iter(exts); iter; ++iter) {
      cout << iter.second().toString().toCppString() << "\n";
    }
    return 0;
  }
  if (vm.count("compiler-id")) {
    cout << compilerId() << "\n";
    return 0;
  }

  if (vm.count("repo-schema")) {
    cout << repoSchemaId() << "\n";
    return 0;
  }

  if (!po.show.empty()) {
    hphp_thread_init();
    g_context.getCheck();
    SCOPE_EXIT { hphp_thread_exit(); };

    auto f = req::make<PlainFile>();
    f->open(po.show, "r");
    if (!f->valid()) {
      Logger::Error("Unable to open file %s", po.show.c_str());
      return 1;
    }
    f->print();
    f->close();
    return 0;
  }

  po.isTempFile = vm.count("temp-file");

  // forget the source for systemlib.php unless we are debugging
  if (po.mode != "debug" && po.mode != "vsdebug") SystemLib::s_source = "";
  if (po.mode == "vsdebug") {
    RuntimeOption::EnableVSDebugger = true;
    RuntimeOption::VSDebuggerListenPort = po.vsDebugPort;
    RuntimeOption::VSDebuggerDomainSocketPath = po.vsDebugDomainSocket;
    RuntimeOption::VSDebuggerNoWait = po.vsDebugNoWait;
  }

  // we need to to initialize these very early
  pcre_init();
  // this is needed for libevent2 to be thread-safe, which backs Hack ASIO.
  #ifndef FACEBOOK
  // FB uses a custom libevent 1
  evthread_use_pthreads();
  #endif

  rds::local::init();
  SCOPE_EXIT { rds::local::fini(); };
  tl_heap.getCheck();
  if (RuntimeOption::ServerExecutionMode()) {
    // Create the hardware counter before reading options,
    // so that the main thread never has inherit set in server
    // mode
    HardwareCounter::s_counter.getCheck();
  }
  std::vector<std::string> messages;
  // We want the ini map to be freed after processing and loading the options
  // So put this in its own block
  {
    IniSettingMap ini = IniSettingMap();
    Hdf config;
    s_config_files = po.config;
    // Start with .hdf and .ini files
    for (auto& filename : s_config_files) {
      if (boost::filesystem::exists(filename)) {
        Config::ParseConfigFile(filename, ini, config);
      } else {
        Logger::Warning(
          "The configuration file %s does not exist",
          filename.c_str()
        );
      }
    }

    auto const scriptFilePath =
      !po.file.empty() ? po.file :
      !po.args.empty() ? po.args[0] :
      std::string("");

    // Now, take care of CLI options and then officially load and bind things
    s_ini_strings = po.iniStrings;
    RuntimeOption::Load(
      ini,
      config,
      po.iniStrings,
      po.confStrings,
      &messages,
      scriptFilePath
    );
    if (RuntimeOption::WhitelistExec ||
        RuntimeOption::WhitelistExecWarningOnly ||
        !RuntimeOption::AllowedExecCmds.empty()) {
      fprintf(stderr, "Configurations Server.WhitelistExec, "
             "Server.WhitelistExecWarningOnly, Server.AllowedExecCmds "
             "are not supported.\n");
      return 1;
    }
    std::vector<std::string> badnodes;
    config.lint(badnodes);
    for (const auto& badnode : badnodes) {
      const auto msg = "Possible bad config node: " + badnode;
      fprintf(stderr, "%s\n", msg.c_str());
      messages.push_back(msg);
    }

    if (po.mode == "getoption") {
      if (po.args.size() < 1) {
        fprintf(stderr, "Must specify an option to load\n");
        return 1;
      }
      Variant value;
      bool ret = IniSetting::Get(po.args[0], value);
      if (!ret) {
        fprintf(stderr, "No such option: %s\n", po.args[0].data());
        return 1;
      }
      if (!value.isString()) {
        VariableSerializer vs{VariableSerializer::Type::JSON};
        value = vs.serializeValue(value, false);
      }
      printf("%s\n", value.toString().data());
      return 0;
    }
  }

  std::vector<int> inherited_fds;
  RuntimeOption::BuildId = po.buildId;
  RuntimeOption::InstanceId = po.instanceId;

  // Do this as early as possible to avoid creating temp files and spawing
  // light processes. Correct compilation still requires loading all of the
  // ini/hdf/cli options.
  if (po.mode == "dumphhas" || po.mode == "verify" ||
      po.mode == "dumpcoverage") {
    if (po.file.empty() && po.args.empty()) {
      std::cerr << "Nothing to do. Pass a hack file to compile.\n";
      return 1;
    }

    auto const file = [] (std::string file) -> std::string {
      if (!FileUtil::isAbsolutePath(file)) {
        return SourceRootInfo::GetCurrentSourceRoot() + std::move(file);
      }
      return file;
    }(po.file.empty() ? po.args[0] : po.file);

    std::fstream fs(file, std::ios::in);
    if (!fs) {
      std::cerr << "Unable to open \"" << file << "\"\n";
      return 1;
    }
    std::stringstream contents;
    contents << fs.rdbuf();

    auto const str = contents.str();
    auto const sha1 = SHA1{
      mangleUnitSha1(string_sha1(str), file, RepoOptions::defaults().flags())
    };

    if (!registrationComplete) {
      folly::SingletonVault::singleton()->registrationComplete();
      registrationComplete = true;
    }

    compilers_start();
    hphp_thread_init();
    g_context.getCheck();
    SCOPE_EXIT { hphp_thread_exit(); };

    if (po.mode == "dumphhas")  RuntimeOption::EvalDumpHhas = true;
    else if (po.mode != "dumpcoverage") RuntimeOption::EvalVerifyOnly = true;
    SystemLib::s_inited = true;

    // Ensure write to SystemLib::s_inited is visible by other threads.
    std::atomic_thread_fence(std::memory_order_release);

    LazyUnitContentsLoader loader{sha1, str, RepoOptions::defaults().flags()};
    auto compiled =
      compile_file(loader, file.c_str(), Native::s_noNativeFuncs, nullptr);

    if (po.mode == "verify") {
      return 0;
    }

    // This will dump the hhas for file as EvalDumpHhas was set
    if (!compiled) {
      std::cerr << "Unable to compile \"" << file << "\"\n";
      return 1;
    }

    if (po.mode == "dumpcoverage") {
      std::cout << "[" << folly::join(", ", get_executable_lines(compiled))
                << "]" << std::endl;
      return 0;
    }

    return 0;
  }

  if (po.port != -1) {
    RuntimeOption::ServerPort = po.port;
  }
  if (po.portfd != -1) {
    RuntimeOption::ServerPortFd = po.portfd;
    inherited_fds.push_back(po.portfd);
  }
  if (po.sslportfd != -1) {
    RuntimeOption::SSLPortFd = po.sslportfd;
    inherited_fds.push_back(po.sslportfd);
  }
  if (po.admin_port != -1) {
    RuntimeOption::AdminServerPort = po.admin_port;
  }
  if (po.noSafeAccessCheck) {
    RuntimeOption::SafeFileAccess = false;
  }
  IniSetting::s_system_settings_are_set = true;
  if (debug) tl_heap->checkHeap("resetRuntimeOptions");
  tl_heap.destroy();
  rds::local::fini();
  // From this point on there is no tl_heap until hphp_process_init is called.

  auto opened_logs = open_server_log_files();
  if (po.mode == "daemon") {
    if (!opened_logs) {
      Logger::Error("Log file not specified under daemon mode.\n\n");
    }
    proc::daemonize();
  }

  if (RuntimeOption::ServerExecutionMode()) {
    for (auto const& m : messages) {
      Logger::Info(m);
    }
  }

#ifndef _MSC_VER
  // Defer the initialization of light processes until the log file handle is
  // created, so that light processes can log to the right place. If we ever
  // lose a light process, stop the server instead of proceeding in an
  // uncertain state. Don't start them in DumpHhas mode because
  // it _Exit()s after loading the first non-systemlib unit.
  if (!RuntimeOption::EvalDumpHhas) {
    LightProcess::SetLostChildHandler([](pid_t /*child*/) {
      if (!HttpServer::Server) return;
      if (!HttpServer::Server->isStopped()) {
        HttpServer::Server->stopOnSignal(SIGCHLD);
      }
    });
    LightProcess::Initialize(RuntimeOption::LightProcessFilePrefix,
                             RuntimeOption::LightProcessCount,
                             RuntimeOption::EvalRecordSubprocessTimes,
                             inherited_fds);
  }
#endif
#if USE_JEMALLOC_EXTENT_HOOKS
  if (RuntimeOption::EvalEnableArenaMetadata1GPage) {
    // Set up extent hook so that we can place jemalloc metadata on 1G pages.
    // This needs to be done after initializing LightProcess (which forks),
    // because the child process does malloc which won't work with jemalloc
    // metadata on 1G huge pages.
    setup_jemalloc_metadata_extent_hook(
      RuntimeOption::EvalEnableArenaMetadata1GPage,
      RuntimeOption::EvalEnableNumaArenaMetadata1GPage,
      RuntimeOption::EvalArenaMetadataReservedSize
    );
  } else if (RuntimeOption::ServerExecutionMode()) {
    purge_all();
    setup_arena0({RuntimeOption::EvalNum1GPagesForA0,
                  RuntimeOption::EvalNum2MPagesForA0});
  }
  if (RuntimeOption::EvalFileBackedColdArena) {
    set_cold_file_dir(RuntimeOption::EvalColdArenaFileDir.c_str());
    enable_high_cold_file();
  }
#endif

  auto const addTypeToEmbeddedPath = [&](std::string path, const char* type) {
    auto const typePlaceholder = "%{type}";
    assertx(strstr(type, typePlaceholder) == nullptr);
    size_t idx;
    if ((idx = path.find(typePlaceholder)) != std::string::npos) {
      path.replace(idx, strlen(typePlaceholder), type);
    }
    return path;
  };

  // We want to initialize the type-scanners as early as possible
  // because any allocations before-hand will get a generic unknown
  // type type-index.
  SCOPE_EXIT {
    // this would be handled by hphp_process_exit, but some paths
    // short circuit before getting there.
    embedded_data_cleanup();
  };
  try {
    type_scan::init(
      addTypeToEmbeddedPath(
        RuntimeOption::EvalEmbeddedDataExtractPath,
        "type_scanners"
      ),
      addTypeToEmbeddedPath(
        RuntimeOption::EvalEmbeddedDataFallbackPath,
        "type_scanners"
      ),
      RuntimeOption::EvalEmbeddedDataTrustExtract
    );
  } catch (const type_scan::InitException& exn) {
    Logger::Error("Unable to initialize GC type-scanners: %s", exn.what());
    exit(HPHP_EXIT_FAILURE);
  }
  ThreadLocalManager::GetManager().initTypeIndices();

  // It's okay if this fails.
  init_member_reflection(
    addTypeToEmbeddedPath(
      RuntimeOption::EvalEmbeddedDataExtractPath,
      "member_reflection"
    ),
    addTypeToEmbeddedPath(
      RuntimeOption::EvalEmbeddedDataFallbackPath,
      "member_reflection"
    ),
    RuntimeOption::EvalEmbeddedDataTrustExtract
  );

  if (!ShmCounters::initialize(true, Logger::Error)) {
    exit(HPHP_EXIT_FAILURE);
  }

  if (vm.count("check-repo")) {
    hphp_thread_init();
    always_assert(RO::RepoAuthoritative);
    init_repo_file();
    LitstrTable::init();
    LitarrayTable::init();
    RepoFile::loadGlobalTables(RO::RepoLitstrLazyLoad);
    RepoFile::globalData().load();
    return 0;
  }

  if (!po.lint.empty()) {
    Logger::LogHeader = false;
    Logger::LogLevel = Logger::LogInfo;
    Logger::UseCronolog = false;
    Logger::UseLogFile = true;
    // we're linting, reset whatever logger settings and write once to stdout
    Logger::ClearThreadLog();
    for (auto& el : RuntimeOption::ErrorLogs) {
      const auto& name = el.first;
      Logger::SetTheLogger(name, nullptr);
    }
    Logger::SetTheLogger(Logger::DEFAULT, new Logger());

    if (po.isTempFile) {
      tempFile = po.lint;
    }

    if (!registrationComplete) {
      folly::SingletonVault::singleton()->registrationComplete();
      registrationComplete = true;
    }

    compilers_start();
    hphp_thread_init();
    g_context.getCheck();
    SCOPE_EXIT { hphp_thread_exit(); };

    SystemLib::s_inited = true;

    // Ensure write to SystemLib::s_inited is visible by other threads.
    std::atomic_thread_fence(std::memory_order_release);

    try {
      auto const file = [&] {
        if (!FileUtil::isAbsolutePath(po.lint)) {
          return SourceRootInfo::GetCurrentSourceRoot() + po.lint;
        }
        return po.lint;
      }();

      std::fstream fs{file, std::ios::in};
      if (!fs) throw FileOpenException(po.lint);
      std::stringstream contents;
      contents << fs.rdbuf();

      auto const repoOptions = RepoOptions::forFile(file.c_str());

      auto const str = contents.str();
      auto const sha1 =
        SHA1{mangleUnitSha1(string_sha1(str), file, repoOptions.flags())};

      // Disable any cache hooks because they're generally not useful
      // if we're just going to lint (and they might be expensive).
      g_unit_emitter_cache_hook = nullptr;

      LazyUnitContentsLoader loader{sha1, str, repoOptions.flags()};
      auto const unit =
        compile_file(loader, file.c_str(), Native::s_noNativeFuncs, nullptr);
      if (!unit) {
        std::cerr << "Unable to compile \"" << file << "\"\n";
        return 1;
      }
      if (auto const info = unit->getFatalInfo()) {
        raise_parse_error(unit->filepath(), info->m_fatalMsg.c_str(),
                          info->m_fatalLoc);
      }
    } catch (const FatalErrorException& e) {
      RuntimeOption::CallUserHandlerOnFatals = false;
      RuntimeOption::AlwaysLogUnhandledExceptions = false;
      g_context->onFatalError(e);
      return 1;
    }
    Logger::Info("No syntax errors detected in %s", po.lint.c_str());
    return 0;
  }

  if (argc <= 1 || po.mode == "run" || po.mode == "debug" ||
      po.mode == "vsdebug" || po.mode == "eval") {
    set_stack_size();

    if (po.isTempFile) {
      tempFile = po.file;
    }

    set_execution_mode("run");
    /* recreate the hardware counters for the main thread now that we know
     * whether to include subprocess times */
    HardwareCounter::s_counter.destroy();
    HardwareCounter::s_counter.getCheck();

    int new_argc;
    char **new_argv;
    prepare_args(new_argc, new_argv, po.args, po.file.c_str());

    std::string const cliFile = !po.file.empty() ? po.file :
                                 new_argv[0] ? new_argv[0] : "";
    if (po.mode != "debug" && po.mode != "eval" && cliFile.empty()) {
      std::cerr << "Nothing to do. Either pass a hack file to run, or "
        "use -m server\n";
      return 1;
    }

    if (po.mode == "eval" && po.args.empty()) {
      std::cerr << "Nothing to do. Pass a command to run with mode eval\n";
      return 1;
    }

    if (RuntimeOption::EvalUseRemoteUnixServer != "no" &&
        !RuntimeOption::EvalUnixServerPath.empty() &&
        (!po.file.empty() || !po.args.empty()) && po.mode != "eval") {
      // CLI server clients use a wacky delayed initialization scheme for
      // RDS, and therefore requires RDS_LOCALS be outside RDS.
      rds::local::init();
      SCOPE_EXIT { rds::local::fini(); };
      std::vector<std::string> args;
      if (!po.file.empty()) {
        args.emplace_back(po.file);
      }
      args.insert(args.end(), po.args.begin(), po.args.end());
      run_command_on_cli_server(
        RuntimeOption::EvalUnixServerPath.c_str(), args, po.count
      );
      if (RuntimeOption::EvalUseRemoteUnixServer == "only") {
        Logger::Error("Failed to connect to unix server.");
        exit(255);
      }
    }

    int ret = 0;
    init_repo_file();
    hphp_process_init();
    SCOPE_EXIT { hphp_process_exit(); };

    block_sync_signals_and_start_handler_thread();

    std::string file;
    if (new_argc > 0) {
      file = new_argv[0];
    }

    if (po.mode == "debug") {
      StackTraceNoHeap::AddExtraLogging("IsDebugger", "True");
      RuntimeOption::EnableHphpdDebugger = true;
      po.debugger_options.fileName = file;
      po.debugger_options.user = po.user;
      Eval::DebuggerProxyPtr localProxy =
        Eval::Debugger::StartClient(po.debugger_options);
      if (!localProxy) {
        Logger::Error("Failed to start debugger client\n\n");
        return 1;
      }
      Eval::Debugger::RegisterSandbox(localProxy->getDummyInfo());
      std::shared_ptr<std::vector<std::string>> client_args;
      bool restart = false;
      ret = 0;
      while (true) {
        try {
          assertx(po.debugger_options.fileName == file);
          execute_command_line_begin(new_argc, new_argv, po.xhprofFlags);
          // Set the proxy for this thread to be the localProxy we just
          // created. If we're script debugging, this will be the proxy that
          // does all of our work. If we're remote debugging, this proxy will
          // go unused until we finally stop it when the user quits the
          // debugger.
          g_context->setSandboxId(localProxy->getDummyInfo().id());
          if (restart) {
            // Systemlib.php is not loaded again, so we need this if we
            // are to hit any breakpoints in systemlib.
            proxySetBreakPoints(localProxy.get());
          }
          Eval::Debugger::DebuggerSession(po.debugger_options, restart);
          restart = false;
          execute_command_line_end(po.xhprofFlags, true, file.c_str());
        } catch (const Eval::DebuggerRestartException& e) {
          execute_command_line_end(0, false, nullptr);

          if (!e.m_args->empty()) {
            file = e.m_args->at(0);
            po.debugger_options.fileName = file;
            client_args = e.m_args;
            free(new_argv);
            prepare_args(new_argc, new_argv, *client_args, nullptr);
          }
          restart = true;
        } catch (const Eval::DebuggerClientExitException& e) {
          execute_command_line_end(0, false, nullptr);
          break; // end user quitting debugger
        }
      }

    } else {
      tracing::Request _{
        "cli-request",
        file,
        [&] { return tracing::Props{}.add("file", file); }
      };

      ret = 0;

      for (int i = 0; i < po.count; i++) {
        execute_command_line_begin(new_argc, new_argv, po.xhprofFlags);
        ret = 255;
        if (po.mode == "eval") {
          String code{"<?hh " + file};
          auto const r = g_context->evalPHPDebugger(code.get(), 0);
          if (!r.failed) ret = 0;
        } else if (hphp_invoke_simple(file, false /* warmup only */)) {
          ret = *rl_exit_code;
        }
        const bool last = i == po.count - 1;
        if (last && jit::tc::dumpEnabled()) {
          jit::mcgen::joinWorkerThreads();
          jit::tc::dump();
        }
        execute_command_line_end(po.xhprofFlags, true, file.c_str());
      }
    }

    free(new_argv);

    return ret;
  }

  if (po.mode == "daemon" || po.mode == "server") {
    if (!po.user.empty()) RuntimeOption::ServerUser = po.user;
    return start_server(RuntimeOption::ServerUser, po.xhprofFlags);
  }

  if (po.mode == "replay" && !po.args.empty()) {
    RuntimeOption::RecordInput = false;
    set_execution_mode("server");
    HttpServer server; // so we initialize runtime properly
    HttpRequestHandler handler(0);
    for (int i = 0; i < po.count; i++) {
      for (unsigned int j = 0; j < po.args.size(); j++) {
        ReplayTransport rt;
        rt.replayInput(po.args[j].c_str());
        handler.run(&rt);
        printf("%s\n", rt.getResponse().c_str());
      }
    }
    return 0;
  }

  if (po.mode == "translate" && !po.args.empty()) {
    printf("%s", translate_stack(po.args[0].c_str()).c_str());
    return 0;
  }

  cout << desc << "\n";
  return -1;
}