| Index: tools/exception_port_tool.cc
 | 
| diff --git a/tools/exception_port_tool.cc b/tools/exception_port_tool.cc
 | 
| deleted file mode 100644
 | 
| index bc6b637fbc2493a39e5ee4ad4f524d8a27efbe84..0000000000000000000000000000000000000000
 | 
| --- a/tools/exception_port_tool.cc
 | 
| +++ /dev/null
 | 
| @@ -1,594 +0,0 @@
 | 
| -// Copyright 2014 The Crashpad Authors. All rights reserved.
 | 
| -//
 | 
| -// Licensed under the Apache License, Version 2.0 (the "License");
 | 
| -// you may not use this file except in compliance with the License.
 | 
| -// You may obtain a copy of the License at
 | 
| -//
 | 
| -//     http://www.apache.org/licenses/LICENSE-2.0
 | 
| -//
 | 
| -// Unless required by applicable law or agreed to in writing, software
 | 
| -// distributed under the License is distributed on an "AS IS" BASIS,
 | 
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
| -// See the License for the specific language governing permissions and
 | 
| -// limitations under the License.
 | 
| -
 | 
| -#include <errno.h>
 | 
| -#include <getopt.h>
 | 
| -#include <libgen.h>
 | 
| -#include <mach/mach.h>
 | 
| -#include <servers/bootstrap.h>
 | 
| -#include <stdio.h>
 | 
| -#include <stdlib.h>
 | 
| -#include <string.h>
 | 
| -#include <unistd.h>
 | 
| -
 | 
| -#include <string>
 | 
| -#include <vector>
 | 
| -
 | 
| -#include "base/basictypes.h"
 | 
| -#include "base/mac/mach_logging.h"
 | 
| -#include "base/mac/scoped_mach_port.h"
 | 
| -#include "base/strings/stringprintf.h"
 | 
| -#include "tools/tool_support.h"
 | 
| -#include "util/mach/exception_ports.h"
 | 
| -#include "util/mach/mach_extensions.h"
 | 
| -#include "util/mach/symbolic_constants_mach.h"
 | 
| -#include "util/mach/task_for_pid.h"
 | 
| -#include "util/posix/drop_privileges.h"
 | 
| -#include "util/stdlib/string_number_conversion.h"
 | 
| -
 | 
| -namespace crashpad {
 | 
| -namespace {
 | 
| -
 | 
| -//! \brief Manages a pool of Mach send rights, deallocating all send rights upon
 | 
| -//!     destruction.
 | 
| -//!
 | 
| -//! This class effectively implements what a vector of
 | 
| -//! base::mac::ScopedMachSendRight objects would be.
 | 
| -//!
 | 
| -//! The various “show” operations performed by this program display Mach ports
 | 
| -//! by their names as they are known in this task. For this to be useful, rights
 | 
| -//! to the same ports must have consistent names across successive calls. This
 | 
| -//! cannot be guaranteed if the rights are deallocated as soon as they are used,
 | 
| -//! because if that deallocation causes the task to lose its last right to a
 | 
| -//! port, subsequently regaining a right to the same port would cause it to be
 | 
| -//! known by a new name in this task.
 | 
| -//!
 | 
| -//! Instead of immediately deallocating send rights that are used for display,
 | 
| -//! they can be added to this pool. The pool collects send rights, ensuring that
 | 
| -//! they remain alive in this task, and that subsequent calls that obtain the
 | 
| -//! same rights cause them to be known by the same name. All rights are
 | 
| -//! deallocated upon destruction.
 | 
| -class MachSendRightPool {
 | 
| - public:
 | 
| -  MachSendRightPool()
 | 
| -      : send_rights_() {
 | 
| -  }
 | 
| -
 | 
| -  ~MachSendRightPool() {
 | 
| -    for (mach_port_t send_right : send_rights_) {
 | 
| -      kern_return_t kr = mach_port_deallocate(mach_task_self(), send_right);
 | 
| -      MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  //! \brief Adds a send right to the pool.
 | 
| -  //!
 | 
| -  //! \param[in] send_right The send right to be added. The pool object takes
 | 
| -  //!     ownership of the send right, which remains valid until the pool object
 | 
| -  //!     is destroyed.
 | 
| -  //!
 | 
| -  //! It is possible and in fact likely that one pool will wind up owning the
 | 
| -  //! same send right multiple times. This is acceptable, because send rights
 | 
| -  //! are reference-counted.
 | 
| -  void AddSendRight(mach_port_t send_right) {
 | 
| -    send_rights_.push_back(send_right);
 | 
| -  }
 | 
| -
 | 
| - private:
 | 
| -  std::vector<mach_port_t> send_rights_;
 | 
| -
 | 
| -  DISALLOW_COPY_AND_ASSIGN(MachSendRightPool);
 | 
| -};
 | 
| -
 | 
| -struct ExceptionHandlerDescription {
 | 
| -  ExceptionPorts::TargetType target_type;
 | 
| -  exception_mask_t mask;
 | 
| -  exception_behavior_t behavior;
 | 
| -  thread_state_flavor_t flavor;
 | 
| -  std::string handler;
 | 
| -};
 | 
| -
 | 
| -const char kHandlerNull[] = "NULL";
 | 
| -const char kHandlerBootstrapColon[] = "bootstrap:";
 | 
| -
 | 
| -// Populates |description| based on a textual representation in
 | 
| -// |handler_string_ro|, returning true on success and false on failure (parse
 | 
| -// error). The --help string describes the format of |handler_string_ro|.
 | 
| -// Briefly, it is a comma-separated string that allows the members of
 | 
| -// |description| to be specified as "field=value". Values for "target" can be
 | 
| -// "host", "task", or "thread"; values for "handler" are of the form
 | 
| -// "bootstrap:service_name" where service_name will be looked up with the
 | 
| -// bootstrap server; and values for the other fields are interpreted by
 | 
| -// SymbolicConstantsMach.
 | 
| -bool ParseHandlerString(const char* handler_string_ro,
 | 
| -                        ExceptionHandlerDescription* description) {
 | 
| -  const char kTargetEquals[] = "target=";
 | 
| -  const char kMaskEquals[] = "mask=";
 | 
| -  const char kBehaviorEquals[] = "behavior=";
 | 
| -  const char kFlavorEquals[] = "flavor=";
 | 
| -  const char kHandlerEquals[] = "handler=";
 | 
| -
 | 
| -  std::string handler_string(handler_string_ro);
 | 
| -  char* handler_string_c = &handler_string[0];
 | 
| -
 | 
| -  char* token;
 | 
| -  while ((token = strsep(&handler_string_c, ",")) != nullptr) {
 | 
| -    if (strncmp(token, kTargetEquals, strlen(kTargetEquals)) == 0) {
 | 
| -      const char* value = token + strlen(kTargetEquals);
 | 
| -      if (strcmp(value, "host") == 0) {
 | 
| -        description->target_type = ExceptionPorts::kTargetTypeHost;
 | 
| -      } else if (strcmp(value, "task") == 0) {
 | 
| -        description->target_type = ExceptionPorts::kTargetTypeTask;
 | 
| -      } else if (strcmp(value, "thread") == 0) {
 | 
| -        description->target_type = ExceptionPorts::kTargetTypeThread;
 | 
| -      } else {
 | 
| -        return false;
 | 
| -      }
 | 
| -    } else if (strncmp(token, kMaskEquals, strlen(kMaskEquals)) == 0) {
 | 
| -      const char* value = token + strlen(kMaskEquals);
 | 
| -      if (!StringToExceptionMask(
 | 
| -              value,
 | 
| -              kAllowFullName | kAllowShortName | kAllowNumber | kAllowOr,
 | 
| -              &description->mask)) {
 | 
| -        return false;
 | 
| -      }
 | 
| -    } else if (strncmp(token, kBehaviorEquals, strlen(kBehaviorEquals)) == 0) {
 | 
| -      const char* value = token + strlen(kBehaviorEquals);
 | 
| -      if (!StringToExceptionBehavior(
 | 
| -              value,
 | 
| -              kAllowFullName | kAllowShortName | kAllowNumber,
 | 
| -              &description->behavior)) {
 | 
| -        return false;
 | 
| -      }
 | 
| -    } else if (strncmp(token, kFlavorEquals, strlen(kFlavorEquals)) == 0) {
 | 
| -      const char* value = token + strlen(kFlavorEquals);
 | 
| -      if (!StringToThreadStateFlavor(
 | 
| -              value,
 | 
| -              kAllowFullName | kAllowShortName | kAllowNumber,
 | 
| -              &description->flavor)) {
 | 
| -        return false;
 | 
| -      }
 | 
| -    } else if (strncmp(token, kHandlerEquals, strlen(kHandlerEquals)) == 0) {
 | 
| -      const char* value = token + strlen(kHandlerEquals);
 | 
| -      if (strcmp(value, kHandlerNull) != 0 &&
 | 
| -          strncmp(value,
 | 
| -                  kHandlerBootstrapColon,
 | 
| -                  strlen(kHandlerBootstrapColon)) != 0) {
 | 
| -        return false;
 | 
| -      }
 | 
| -      description->handler = std::string(value);
 | 
| -    } else {
 | 
| -      return false;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -// ShowExceptionPorts() shows handlers as numeric mach_port_t values, which are
 | 
| -// opaque and meaningless on their own. ShowBootstrapService() can be used to
 | 
| -// look up a service with the bootstrap server by name and show its mach_port_t
 | 
| -// value, which can then be associated with handlers shown by
 | 
| -// ShowExceptionPorts(). Any send rights obtained by this function are added to
 | 
| -// |mach_send_right_pool|.
 | 
| -void ShowBootstrapService(const std::string& service_name,
 | 
| -                          MachSendRightPool* mach_send_right_pool) {
 | 
| -  mach_port_t service_port;
 | 
| -  kern_return_t kr = bootstrap_look_up(
 | 
| -      bootstrap_port, const_cast<char*>(service_name.c_str()), &service_port);
 | 
| -  if (kr != BOOTSTRAP_SUCCESS) {
 | 
| -    BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up " << service_name;
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  mach_send_right_pool->AddSendRight(service_port);
 | 
| -
 | 
| -  printf("service %s %#x\n", service_name.c_str(), service_port);
 | 
| -}
 | 
| -
 | 
| -// Prints information about all exception ports known for |exception_ports|. If
 | 
| -// |numeric| is true, all information is printed in numeric form, otherwise, it
 | 
| -// will be converted to symbolic constants where possible by
 | 
| -// SymbolicConstantsMach. If |is_new| is true, information will be presented as
 | 
| -// “new exception ports”, indicating that they show the state of the exception
 | 
| -// ports after SetExceptionPort() has been called. Any send rights obtained by
 | 
| -// this function are added to |mach_send_right_pool|.
 | 
| -void ShowExceptionPorts(const ExceptionPorts& exception_ports,
 | 
| -                        bool numeric,
 | 
| -                        bool is_new,
 | 
| -                        MachSendRightPool* mach_send_right_pool) {
 | 
| -  const char* target_name = exception_ports.TargetTypeName();
 | 
| -
 | 
| -  std::vector<ExceptionPorts::ExceptionHandler> handlers;
 | 
| -  if (!exception_ports.GetExceptionPorts(ExcMaskAll() | EXC_MASK_CRASH,
 | 
| -                                         &handlers)) {
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  const char* age_name = is_new ? "new " : "";
 | 
| -
 | 
| -  if (handlers.size() == 0) {
 | 
| -    printf("no %s%s exception ports\n", age_name, target_name);
 | 
| -  }
 | 
| -
 | 
| -  for (size_t port_index = 0; port_index < handlers.size(); ++port_index) {
 | 
| -    mach_send_right_pool->AddSendRight(handlers[port_index].port);
 | 
| -
 | 
| -    if (numeric) {
 | 
| -      printf(
 | 
| -          "%s%s exception port %zu, mask %#x, port %#x, "
 | 
| -          "behavior %#x, flavor %u\n",
 | 
| -          age_name,
 | 
| -          target_name,
 | 
| -          port_index,
 | 
| -          handlers[port_index].mask,
 | 
| -          handlers[port_index].port,
 | 
| -          handlers[port_index].behavior,
 | 
| -          handlers[port_index].flavor);
 | 
| -    } else {
 | 
| -      std::string mask_string = ExceptionMaskToString(
 | 
| -          handlers[port_index].mask, kUseShortName | kUnknownIsEmpty | kUseOr);
 | 
| -      if (mask_string.empty()) {
 | 
| -        mask_string.assign("?");
 | 
| -      }
 | 
| -
 | 
| -      std::string behavior_string = ExceptionBehaviorToString(
 | 
| -          handlers[port_index].behavior, kUseShortName | kUnknownIsEmpty);
 | 
| -      if (behavior_string.empty()) {
 | 
| -        behavior_string.assign("?");
 | 
| -      }
 | 
| -
 | 
| -      std::string flavor_string = ThreadStateFlavorToString(
 | 
| -          handlers[port_index].flavor, kUseShortName | kUnknownIsEmpty);
 | 
| -      if (flavor_string.empty()) {
 | 
| -        flavor_string.assign("?");
 | 
| -      }
 | 
| -
 | 
| -      printf(
 | 
| -          "%s%s exception port %zu, mask %#x (%s), port %#x, "
 | 
| -          "behavior %#x (%s), flavor %u (%s)\n",
 | 
| -          age_name,
 | 
| -          target_name,
 | 
| -          port_index,
 | 
| -          handlers[port_index].mask,
 | 
| -          mask_string.c_str(),
 | 
| -          handlers[port_index].port,
 | 
| -          handlers[port_index].behavior,
 | 
| -          behavior_string.c_str(),
 | 
| -          handlers[port_index].flavor,
 | 
| -          flavor_string.c_str());
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -// Sets the exception port for |target_port|, a send right to a thread, task, or
 | 
| -// host port, to |description|, which identifies what type of port |target_port|
 | 
| -// is and describes an exception port to be set. Returns true on success.
 | 
| -//
 | 
| -// This function may be called more than once if setting different handlers is
 | 
| -// desired.
 | 
| -bool SetExceptionPort(const ExceptionHandlerDescription* description,
 | 
| -                      mach_port_t target_port) {
 | 
| -  base::mac::ScopedMachSendRight service_port_owner;
 | 
| -  exception_handler_t service_port = MACH_PORT_NULL;
 | 
| -  kern_return_t kr;
 | 
| -  if (description->handler.compare(
 | 
| -          0, strlen(kHandlerBootstrapColon), kHandlerBootstrapColon) == 0) {
 | 
| -    const char* service_name =
 | 
| -        description->handler.c_str() + strlen(kHandlerBootstrapColon);
 | 
| -    kr = bootstrap_look_up(
 | 
| -        bootstrap_port, const_cast<char*>(service_name), &service_port);
 | 
| -    if (kr != BOOTSTRAP_SUCCESS) {
 | 
| -      BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up " << service_name;
 | 
| -      return false;
 | 
| -    }
 | 
| -
 | 
| -    // The service port doesn’t need to be added to a MachSendRightPool because
 | 
| -    // it’s not used for display at all. ScopedMachSendRight is sufficient.
 | 
| -    service_port_owner.reset(service_port);
 | 
| -  } else if (description->handler != kHandlerNull) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  ExceptionPorts exception_ports(description->target_type, target_port);
 | 
| -  if (!exception_ports.SetExceptionPort(description->mask,
 | 
| -                                        service_port,
 | 
| -                                        description->behavior,
 | 
| -                                        description->flavor)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -void Usage(const std::string& me) {
 | 
| -  fprintf(stderr,
 | 
| -"Usage: %s [OPTION]... [COMMAND [ARG]...]\n"
 | 
| -"View and change Mach exception ports, and run COMMAND if supplied.\n"
 | 
| -"\n"
 | 
| -"  -s, --set-handler=DESCRIPTION  set an exception port to DESCRIPTION, see below\n"
 | 
| -"      --show-bootstrap=SERVICE   look up and display a service registered with\n"
 | 
| -"                                 the bootstrap server\n"
 | 
| -"  -p, --pid=PID                  operate on PID instead of the current task\n"
 | 
| -"  -h, --show-host                display original host exception ports\n"
 | 
| -"  -t, --show-task                display original task exception ports\n"
 | 
| -"      --show-thread              display original thread exception ports\n"
 | 
| -"  -H, --show-new-host            display modified host exception ports\n"
 | 
| -"  -T, --show-new-task            display modified task exception ports\n"
 | 
| -"      --show-new-thread          display modified thread exception ports\n"
 | 
| -"  -n, --numeric                  display values numerically, not symbolically\n"
 | 
| -"      --help                     display this help and exit\n"
 | 
| -"      --version                  output version information and exit\n"
 | 
| -"\n"
 | 
| -"Any operations on host exception ports require superuser permissions.\n"
 | 
| -"\n"
 | 
| -"DESCRIPTION is formatted as a comma-separated sequence of tokens, where each\n"
 | 
| -"token consists of a key and value separated by an equals sign. Available keys:\n"
 | 
| -"  target    which target's exception ports to set: host, task, or thread\n"
 | 
| -"  mask      the mask of exception types to handle: CRASH, ALL, or others\n"
 | 
| -"  behavior  the specific exception handler routine to call: DEFAULT, STATE,\n"
 | 
| -"            or STATE_IDENTITY, possibly with MACH_EXCEPTION_CODES.\n"
 | 
| -"  flavor    the thread state flavor passed to the handler: architecture-specific\n"
 | 
| -"  handler   the exception handler: NULL or bootstrap:SERVICE, indicating that\n"
 | 
| -"            the handler should be looked up with the bootstrap server\n"
 | 
| -"The default DESCRIPTION is\n"
 | 
| -"  target=task,mask=CRASH,behavior=DEFAULT|MACH,flavor=NONE,handler=NULL\n",
 | 
| -          me.c_str());
 | 
| -  ToolSupport::UsageTail(me);
 | 
| -}
 | 
| -
 | 
| -int ExceptionPortToolMain(int argc, char* argv[]) {
 | 
| -  const std::string me(basename(argv[0]));
 | 
| -
 | 
| -  enum ExitCode {
 | 
| -    kExitSuccess = EXIT_SUCCESS,
 | 
| -
 | 
| -    // To differentiate this tool’s errors from errors in the programs it execs,
 | 
| -    // use a high exit code for ordinary failures instead of EXIT_FAILURE. This
 | 
| -    // is the same rationale for using the distinct exit codes for exec
 | 
| -    // failures.
 | 
| -    kExitFailure = 125,
 | 
| -
 | 
| -    // Like env, use exit code 126 if the program was found but could not be
 | 
| -    // invoked, and 127 if it could not be found.
 | 
| -    // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/env.html
 | 
| -    kExitExecFailure = 126,
 | 
| -    kExitExecENOENT = 127,
 | 
| -  };
 | 
| -
 | 
| -  enum OptionFlags {
 | 
| -    // “Short” (single-character) options.
 | 
| -    kOptionSetPort = 's',
 | 
| -    kOptionPid = 'p',
 | 
| -    kOptionShowHost = 'h',
 | 
| -    kOptionShowTask = 't',
 | 
| -    kOptionShowNewHost = 'H',
 | 
| -    kOptionShowNewTask = 'T',
 | 
| -    kOptionNumeric = 'n',
 | 
| -
 | 
| -    // Long options without short equivalents.
 | 
| -    kOptionLastChar = 255,
 | 
| -    kOptionShowBootstrap,
 | 
| -    kOptionShowThread,
 | 
| -    kOptionShowNewThread,
 | 
| -
 | 
| -    // Standard options.
 | 
| -    kOptionHelp = -2,
 | 
| -    kOptionVersion = -3,
 | 
| -  };
 | 
| -
 | 
| -  struct {
 | 
| -    std::vector<const char*> show_bootstrap;
 | 
| -    std::vector<ExceptionHandlerDescription> set_handler;
 | 
| -    pid_t pid;
 | 
| -    task_t alternate_task;
 | 
| -    bool show_host;
 | 
| -    bool show_task;
 | 
| -    bool show_thread;
 | 
| -    bool show_new_host;
 | 
| -    bool show_new_task;
 | 
| -    bool show_new_thread;
 | 
| -    bool numeric;
 | 
| -  } options = {};
 | 
| -
 | 
| -  const struct option long_options[] = {
 | 
| -      {"set-handler", required_argument, nullptr, kOptionSetPort},
 | 
| -      {"show-bootstrap", required_argument, nullptr, kOptionShowBootstrap},
 | 
| -      {"pid", required_argument, nullptr, kOptionPid},
 | 
| -      {"show-host", no_argument, nullptr, kOptionShowHost},
 | 
| -      {"show-task", no_argument, nullptr, kOptionShowTask},
 | 
| -      {"show-thread", no_argument, nullptr, kOptionShowThread},
 | 
| -      {"show-new-host", no_argument, nullptr, kOptionShowNewHost},
 | 
| -      {"show-new-task", no_argument, nullptr, kOptionShowNewTask},
 | 
| -      {"show-new-thread", no_argument, nullptr, kOptionShowNewThread},
 | 
| -      {"numeric", no_argument, nullptr, kOptionNumeric},
 | 
| -      {"help", no_argument, nullptr, kOptionHelp},
 | 
| -      {"version", no_argument, nullptr, kOptionVersion},
 | 
| -      {nullptr, 0, nullptr, 0},
 | 
| -  };
 | 
| -
 | 
| -  int opt;
 | 
| -  while ((opt = getopt_long(argc, argv, "+s:p:htHTn", long_options, nullptr)) !=
 | 
| -         -1) {
 | 
| -    switch (opt) {
 | 
| -      case kOptionSetPort: {
 | 
| -        options.set_handler.push_back({});
 | 
| -        ExceptionHandlerDescription* description = &options.set_handler.back();
 | 
| -        description->target_type = ExceptionPorts::kTargetTypeTask;
 | 
| -        description->mask = EXC_MASK_CRASH;
 | 
| -        description->behavior = EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES;
 | 
| -        description->flavor = THREAD_STATE_NONE;
 | 
| -        description->handler = "NULL";
 | 
| -        if (!ParseHandlerString(optarg, description)) {
 | 
| -          fprintf(stderr,
 | 
| -                  "%s: invalid exception handler: %s\n",
 | 
| -                  me.c_str(),
 | 
| -                  optarg);
 | 
| -          return kExitFailure;
 | 
| -        }
 | 
| -        break;
 | 
| -      }
 | 
| -      case kOptionShowBootstrap:
 | 
| -        options.show_bootstrap.push_back(optarg);
 | 
| -        break;
 | 
| -      case kOptionPid:
 | 
| -        if (!StringToNumber(optarg, &options.pid)) {
 | 
| -          fprintf(stderr, "%s: invalid pid: %s\n", me.c_str(), optarg);
 | 
| -          return kExitFailure;
 | 
| -        }
 | 
| -        break;
 | 
| -      case kOptionShowHost:
 | 
| -        options.show_host = true;
 | 
| -        break;
 | 
| -      case kOptionShowTask:
 | 
| -        options.show_task = true;
 | 
| -        break;
 | 
| -      case kOptionShowThread:
 | 
| -        options.show_thread = true;
 | 
| -        break;
 | 
| -      case kOptionShowNewHost:
 | 
| -        options.show_new_host = true;
 | 
| -        break;
 | 
| -      case kOptionShowNewTask:
 | 
| -        options.show_new_task = true;
 | 
| -        break;
 | 
| -      case kOptionShowNewThread:
 | 
| -        options.show_new_thread = true;
 | 
| -        break;
 | 
| -      case kOptionNumeric:
 | 
| -        options.numeric = true;
 | 
| -        break;
 | 
| -      case kOptionHelp:
 | 
| -        Usage(me);
 | 
| -        return kExitSuccess;
 | 
| -      case kOptionVersion:
 | 
| -        ToolSupport::Version(me);
 | 
| -        return kExitSuccess;
 | 
| -      default:
 | 
| -        ToolSupport::UsageHint(me, nullptr);
 | 
| -        return kExitFailure;
 | 
| -    }
 | 
| -  }
 | 
| -  argc -= optind;
 | 
| -  argv += optind;
 | 
| -
 | 
| -  if (options.show_bootstrap.empty() && !options.show_host &&
 | 
| -      !options.show_task && !options.show_thread &&
 | 
| -      options.set_handler.empty() && argc == 0) {
 | 
| -    ToolSupport::UsageHint(me, "nothing to do");
 | 
| -    return kExitFailure;
 | 
| -  }
 | 
| -
 | 
| -  base::mac::ScopedMachSendRight alternate_task_owner;
 | 
| -  if (options.pid) {
 | 
| -    if (argc) {
 | 
| -      ToolSupport::UsageHint(me, "cannot combine -p with COMMAND");
 | 
| -      return kExitFailure;
 | 
| -    }
 | 
| -
 | 
| -    options.alternate_task = TaskForPID(options.pid);
 | 
| -    if (options.alternate_task == TASK_NULL) {
 | 
| -      return kExitFailure;
 | 
| -    }
 | 
| -    alternate_task_owner.reset(options.alternate_task);
 | 
| -  }
 | 
| -
 | 
| -  // This tool may have been installed as a setuid binary so that TaskForPID()
 | 
| -  // could succeed. Drop any privileges now that they’re no longer necessary.
 | 
| -  DropPrivileges();
 | 
| -
 | 
| -  MachSendRightPool mach_send_right_pool;
 | 
| -
 | 
| -  // Show bootstrap services requested.
 | 
| -  for (const char* service : options.show_bootstrap) {
 | 
| -    ShowBootstrapService(service, &mach_send_right_pool);
 | 
| -  }
 | 
| -
 | 
| -  // Show the original exception ports.
 | 
| -  if (options.show_host) {
 | 
| -    ShowExceptionPorts(
 | 
| -        ExceptionPorts(ExceptionPorts::kTargetTypeHost, HOST_NULL),
 | 
| -        options.numeric,
 | 
| -        false,
 | 
| -        &mach_send_right_pool);
 | 
| -  }
 | 
| -  if (options.show_task) {
 | 
| -    ShowExceptionPorts(
 | 
| -        ExceptionPorts(ExceptionPorts::kTargetTypeTask, options.alternate_task),
 | 
| -        options.numeric,
 | 
| -        false,
 | 
| -        &mach_send_right_pool);
 | 
| -  }
 | 
| -  if (options.show_thread) {
 | 
| -    ShowExceptionPorts(
 | 
| -        ExceptionPorts(ExceptionPorts::kTargetTypeThread, THREAD_NULL),
 | 
| -        options.numeric,
 | 
| -        false,
 | 
| -        &mach_send_right_pool);
 | 
| -  }
 | 
| -
 | 
| -  if (!options.set_handler.empty()) {
 | 
| -    // Set new exception handlers.
 | 
| -    for (ExceptionHandlerDescription description : options.set_handler) {
 | 
| -      if (!SetExceptionPort(
 | 
| -              &description,
 | 
| -              description.target_type == ExceptionPorts::kTargetTypeTask
 | 
| -                  ? options.alternate_task
 | 
| -                  : TASK_NULL)) {
 | 
| -        return kExitFailure;
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    // Show changed exception ports.
 | 
| -    if (options.show_new_host) {
 | 
| -      ShowExceptionPorts(
 | 
| -          ExceptionPorts(ExceptionPorts::kTargetTypeHost, HOST_NULL),
 | 
| -          options.numeric,
 | 
| -          true,
 | 
| -          &mach_send_right_pool);
 | 
| -    }
 | 
| -    if (options.show_new_task) {
 | 
| -      ShowExceptionPorts(
 | 
| -          ExceptionPorts(ExceptionPorts::kTargetTypeTask,
 | 
| -                         options.alternate_task),
 | 
| -          options.numeric,
 | 
| -          true,
 | 
| -          &mach_send_right_pool);
 | 
| -    }
 | 
| -    if (options.show_new_thread) {
 | 
| -      ShowExceptionPorts(
 | 
| -          ExceptionPorts(ExceptionPorts::kTargetTypeThread, THREAD_NULL),
 | 
| -          options.numeric,
 | 
| -          true,
 | 
| -          &mach_send_right_pool);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  if (argc) {
 | 
| -    // Using the remaining arguments, start a new program with the new set of
 | 
| -    // exception ports in effect.
 | 
| -    execvp(argv[0], argv);
 | 
| -    PLOG(ERROR) << "execvp " << argv[0];
 | 
| -    return errno == ENOENT ? kExitExecENOENT : kExitExecFailure;
 | 
| -  }
 | 
| -
 | 
| -  return kExitSuccess;
 | 
| -}
 | 
| -
 | 
| -}  // namespace
 | 
| -}  // namespace crashpad
 | 
| -
 | 
| -int main(int argc, char* argv[]) {
 | 
| -  return crashpad::ExceptionPortToolMain(argc, argv);
 | 
| -}
 | 
| 
 |