From a279673974e0d0ab9f1b70c29eef351aa83f6131 Mon Sep 17 00:00:00 2001 From: Scott Graham Date: Tue, 1 May 2018 13:41:06 -0700 Subject: [PATCH] fuchsia: Implement execvp() equivalent for run_with_crashpad There's no implementation of execvp() on Fuchsia, so attempt to emulate it in `run_with_crashpad` by using launchpad. Failures are mapped to exit codes similar to what the execvp() path would return for missing binary, and other non-subprocess errors. Bug: crashpad:196 Change-Id: I042cbcf82bfd4560442a9d7f301e97bbfea54042 Reviewed-on: https://chromium-review.googlesource.com/1038055 Commit-Queue: Scott Graham Reviewed-by: Joshua Peraza --- tools/BUILD.gn | 8 ++++++ tools/run_with_crashpad.cc | 54 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/tools/BUILD.gn b/tools/BUILD.gn index cd1e95f4..eb76a240 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -104,6 +104,14 @@ if (crashpad_is_mac || crashpad_is_fuchsia) { "../third_party/mini_chromium:base", "../util", ] + + if (crashpad_is_fuchsia) { + if (crashpad_is_in_fuchsia) { + deps += [ "//zircon/public/lib/launchpad" ] + } else { + libs = [ "launchpad" ] + } + } } } diff --git a/tools/run_with_crashpad.cc b/tools/run_with_crashpad.cc index 39095145..a65f5256 100644 --- a/tools/run_with_crashpad.cc +++ b/tools/run_with_crashpad.cc @@ -25,11 +25,20 @@ #include "base/files/file_path.h" #include "base/logging.h" +#include "build/build_config.h" #include "client/crashpad_client.h" #include "tools/tool_support.h" #include "util/stdlib/map_insert.h" #include "util/string/split_string.h" +#if defined(OS_FUCHSIA) +#include +#include +#include + +#include "base/fuchsia/fuchsia_logging.h" +#endif + namespace crashpad { namespace { @@ -38,6 +47,13 @@ void Usage(const std::string& me) { "Usage: %s [OPTION]... COMMAND [ARG]...\n" "Start a Crashpad handler and have it handle crashes from COMMAND.\n" "\n" +#if defined(OS_FUCHSIA) +"COMMAND is run via launchpad, so must be a qualified path to the subprocess to\n" +"be executed.\n" +#else +"COMMAND is run via execvp() so the PATH will be searched.\n" +#endif +"\n" " -h, --handler=HANDLER invoke HANDLER instead of crashpad_handler\n" " --annotation=KEY=VALUE passed to the handler as an --annotation argument\n" " --database=PATH passed to the handler as its --database argument\n" @@ -173,11 +189,49 @@ int RunWithCrashpadMain(int argc, char* argv[]) { return kExitFailure; } +#if defined(OS_FUCHSIA) + // Fuchsia doesn't implement execvp(), launch with launchpad here. + launchpad_t* lp; + launchpad_create(zx_job_default(), argv[0], &lp); + launchpad_load_from_file(lp, argv[0]); + launchpad_set_args(lp, argc, argv); + launchpad_clone(lp, LP_CLONE_ALL); + const char* error_message; + zx_handle_t child; + zx_status_t status = launchpad_go(lp, &child, &error_message); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "launchpad_go: " << error_message; + return status == ZX_ERR_IO ? kExitExecENOENT : kExitExecFailure; + } + + zx_signals_t observed; + status = zx_object_wait_one( + child, ZX_TASK_TERMINATED, ZX_TIME_INFINITE, &observed); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_object_wait_one"; + return kExitExecFailure; + } + if (!(observed & ZX_TASK_TERMINATED)) { + LOG(ERROR) << "did not observe ZX_TASK_TERMINATED"; + return kExitExecFailure; + } + + zx_info_process_t proc_info; + status = zx_object_get_info( + child, ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_object_get_info"; + return kExitExecFailure; + } + + return proc_info.return_code; +#else // Using the remaining arguments, start a new program with the new exception // port in effect. execvp(argv[0], argv); PLOG(ERROR) << "execvp " << argv[0]; return errno == ENOENT ? kExitExecENOENT : kExitExecFailure; +#endif } } // namespace