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;
}