--- /dev/null
+//
+// main.cpp
+// msa
+//
+// Created by James McIlree on 1/30/14.
+// Copyright (c) 2014 Apple. All rights reserved.
+//
+
+#include <CPPUtil/CPPUtil.h>
+
+#include "global.h"
+
+bool isVerbose = true;
+bool shouldPrintVersion = true;
+std::vector<std::string> procsOfInterest;
+bool interestedInEverything = false;
+
+__attribute__((noreturn)) void usage(const char *errorMsg) {
+ if (errorMsg) {
+ printf("%s\n", errorMsg);
+ exit(1);
+ }
+
+ // const char* BOLD = "\033[1m";
+ // const char* UNBOLD = "\033[0m";
+
+ // printf("01234567890123456789012345678901234567890123456789012345678901234567890123456789\n");
+ printf("msa [options]\n\n");
+ printf(" GLOBAL OPTIONS\n\n");
+ printf(" -h, --help Print this message\n");
+ printf(" --verbose Print additional information\n");
+ printf(" --version Print version info\n");
+ printf("\n");
+ printf(" TRACE COLLECTION OPTIONS\n\n");
+ printf(" -i, --initialize # Set the size of the kernel trace buffer\n");
+ printf(" --no-voucher-contents Disable collecting voucher contents\n");
+ printf(" -L path Capture and save trace output to path\n");
+ printf("\n");
+ printf(" OUTPUT OPTIONS\n\n");
+ printf(" --lifecycle all|user|none\n");
+ printf(" Set filter level for lifecycle events\n");
+ printf(" --mach-msg all|user|voucher|none\n");
+ printf(" Set filter level for mach msg events\n");
+ printf(" -o, --output path Print output to path\n");
+ printf(" --raw-timestamps Print timestamps as raw values, not deltas\n");
+ printf(" --mach-absolute-time Print timestamps in mach absolute time\n");
+ printf(" --event-index Print the index of each event\n");
+ printf("\n");
+ exit(1);
+}
+
+template <typename SIZE>
+static bool check_interest_name(const MachineProcess<SIZE>& process) {
+ if (interestedInEverything)
+ return true;
+
+ const char* name = process.name();
+ for (auto& proc : procsOfInterest) {
+ if (strcmp(name, proc.c_str()) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static std::unique_ptr<Action> create_read_trace_file_action(const char* trace_file_path) {
+ if (Path::is_file(trace_file_path, true)) {
+ char resolved_path[PATH_MAX];
+ if (realpath(trace_file_path, resolved_path)) {
+ return std::make_unique<ReadTraceFileAction>(resolved_path);
+ }
+ }
+ char* errmsg = NULL;
+ asprintf(&errmsg, "%s does not exist or is not a file", trace_file_path);
+ usage(errmsg);
+}
+
+static std::vector<std::unique_ptr<Action>> parse_arguments(int argc, const char* argv[], Globals& globals) {
+ int i = 1;
+
+ std::vector<std::unique_ptr<Action>> actions;
+
+ while (i < argc) {
+ const char* arg = argv[i];
+ if ((strcmp(arg, "-h") == 0) || (strcasecmp(arg, "--help") == 0)) {
+ usage(NULL);
+ } else if ((strcmp(arg, "-v") == 0) || strcasecmp(arg, "--verbose") == 0) {
+ globals.set_is_verbose(true);
+ } else if (strcasecmp(arg, "--version") == 0) {
+ shouldPrintVersion = true;
+ } else if ((strcmp(arg, "-i") == 0) || strcasecmp(arg, "--initialize") == 0) {
+ if (++i >= argc)
+ usage("--initialize requires an argument");
+
+ arg = argv[i];
+ char* endptr;
+ uint32_t temp = (uint32_t)strtoul(arg, &endptr, 0);
+ if (*endptr == 0) {
+ globals.set_trace_buffer_size(temp);
+ } else {
+ usage("Unable to parse --initialize argument");
+ }
+ } else if (strcasecmp(arg, "--no-voucher-contents") == 0) {
+ globals.set_should_trace_voucher_contents(false);
+ } else if (strcasecmp(arg, "-L") == 0) {
+ if (++i >= argc)
+ usage("-L requires an argument");
+
+ arg = argv[i];
+ actions.push_back(std::make_unique<WriteTraceFileAction>(arg));
+ } else if (strcasecmp(arg, "--lifecycle") == 0) {
+ if (++i >= argc)
+ usage("--lifecycle requires an argument");
+
+ arg = argv[i];
+ if (strcasecmp(arg, "all") == 0) {
+ globals.set_lifecycle_filter(kLifecycleFilter::All);
+ } else if (strcasecmp(arg, "user") == 0) {
+ globals.set_lifecycle_filter(kLifecycleFilter::User);
+ } else if (strcasecmp(arg, "none") == 0) {
+ globals.set_lifecycle_filter(kLifecycleFilter::None);
+ } else {
+ usage("Unrecognized --lifecycle value");
+ }
+ } else if (strcasecmp(arg, "--mach-msg") == 0) {
+ if (++i >= argc)
+ usage("--mach-msg requires an argument");
+
+ arg = argv[i];
+ if (strcasecmp(arg, "all") == 0) {
+ globals.set_mach_msg_filter(kMachMsgFilter::All);
+ } else if (strcasecmp(arg, "user") == 0) {
+ globals.set_mach_msg_filter(kMachMsgFilter::User);
+ } else if (strcasecmp(arg, "voucher") == 0) {
+ globals.set_mach_msg_filter(kMachMsgFilter::Voucher);
+ } else if (strcasecmp(arg, "none") == 0) {
+ globals.set_mach_msg_filter(kMachMsgFilter::None);
+ } else {
+ usage("Unrecognized --mach-msg value");
+ }
+ } else if ((strcmp(arg, "-o") == 0) || strcasecmp(arg, "--output") == 0) {
+ if (++i >= argc)
+ usage("--output requires an argument");
+
+ FileDescriptor desc(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (!desc.is_open()) {
+ char* errmsg = NULL;
+ asprintf(&errmsg, "Unable to create output file at %s", argv[i]);
+ usage(errmsg);
+ }
+ globals.set_output_fd(std::move(desc));
+ } else if (strcasecmp(arg, "--raw-timestamps") == 0) {
+ globals.set_should_zero_base_timestamps(false);
+ } else if (strcasecmp(arg, "--mach-absolute-time") == 0) {
+ globals.set_should_print_mach_absolute_timestamps(true);
+ } else if (strcasecmp(arg, "--event-index") == 0) {
+ globals.set_should_print_event_index(true);
+ } else {
+ //
+ // Last attempts to divine argument type/intent.
+ //
+ std::string temp(arg);
+
+ if (ends_with(temp, ".trace")) {
+ actions.push_back(create_read_trace_file_action(argv[i]));
+ goto no_error;
+ }
+
+ //
+ // ERROR!
+ //
+ char error_buffer[PATH_MAX];
+ snprintf(error_buffer, sizeof(error_buffer), "Unhandled argument: %s", arg);
+ usage(error_buffer);
+ }
+
+ no_error:
+
+ i++;
+ }
+
+ if (actions.empty()) {
+ actions.push_back(std::make_unique<LiveTraceAction>());
+ }
+
+ return actions;
+}
+
+int main(int argc, const char * argv[])
+{
+ //
+ // Use host values as defaults.
+ // User overrides as needed via flags.
+ //
+ Globals globals;
+ auto actions = parse_arguments(argc, argv, globals);
+
+ interestedInEverything = procsOfInterest.empty();
+
+ // globals.set_should_print_mach_absolute_timestamps(true);
+
+ for (auto& action : actions) {
+ action->execute(globals);
+ }
+
+ return 0;
+}
+