]>
Commit | Line | Data |
---|---|---|
1 | // | |
2 | // main.cpp | |
3 | // msa | |
4 | // | |
5 | // Created by James McIlree on 1/30/14. | |
6 | // Copyright (c) 2014 Apple. All rights reserved. | |
7 | // | |
8 | ||
9 | #include <CPPUtil/CPPUtil.h> | |
10 | ||
11 | #include "global.h" | |
12 | ||
13 | bool isVerbose = true; | |
14 | bool shouldPrintVersion = true; | |
15 | std::vector<std::string> procsOfInterest; | |
16 | bool interestedInEverything = false; | |
17 | ||
18 | __attribute__((noreturn)) void usage(const char *errorMsg) { | |
19 | if (errorMsg) { | |
20 | printf("%s\n", errorMsg); | |
21 | exit(1); | |
22 | } | |
23 | ||
24 | // const char* BOLD = "\033[1m"; | |
25 | // const char* UNBOLD = "\033[0m"; | |
26 | ||
27 | // printf("01234567890123456789012345678901234567890123456789012345678901234567890123456789\n"); | |
28 | printf("msa [options]\n\n"); | |
29 | printf(" GLOBAL OPTIONS\n\n"); | |
30 | printf(" -h, --help Print this message\n"); | |
31 | printf(" --verbose Print additional information\n"); | |
32 | printf(" --version Print version info\n"); | |
33 | printf("\n"); | |
34 | printf(" TRACE COLLECTION OPTIONS\n\n"); | |
35 | printf(" -i, --initialize # Set the size of the kernel trace buffer\n"); | |
36 | printf(" --no-voucher-contents Disable collecting voucher contents\n"); | |
37 | printf(" -L path Capture and save trace output to path\n"); | |
38 | printf("\n"); | |
39 | printf(" OUTPUT OPTIONS\n\n"); | |
40 | printf(" --lifecycle all|user|none\n"); | |
41 | printf(" Set filter level for lifecycle events\n"); | |
42 | printf(" --mach-msg all|user|voucher|none\n"); | |
43 | printf(" Set filter level for mach msg events\n"); | |
44 | printf(" -o, --output path Print output to path\n"); | |
45 | printf(" --raw-timestamps Print timestamps as raw values, not deltas\n"); | |
46 | printf(" --mach-absolute-time Print timestamps in mach absolute time\n"); | |
47 | printf(" --event-index Print the index of each event\n"); | |
48 | printf("\n"); | |
49 | exit(1); | |
50 | } | |
51 | ||
52 | template <typename SIZE> | |
53 | static bool check_interest_name(const MachineProcess<SIZE>& process) { | |
54 | if (interestedInEverything) | |
55 | return true; | |
56 | ||
57 | const char* name = process.name(); | |
58 | for (auto& proc : procsOfInterest) { | |
59 | if (strcmp(name, proc.c_str()) == 0) | |
60 | return true; | |
61 | } | |
62 | ||
63 | return false; | |
64 | } | |
65 | ||
66 | static std::unique_ptr<Action> create_read_trace_file_action(const char* trace_file_path) { | |
67 | if (Path::is_file(trace_file_path, true)) { | |
68 | char resolved_path[PATH_MAX]; | |
69 | if (realpath(trace_file_path, resolved_path)) { | |
70 | return std::make_unique<ReadTraceFileAction>(resolved_path); | |
71 | } | |
72 | } | |
73 | char* errmsg = NULL; | |
74 | asprintf(&errmsg, "%s does not exist or is not a file", trace_file_path); | |
75 | usage(errmsg); | |
76 | } | |
77 | ||
78 | static std::vector<std::unique_ptr<Action>> parse_arguments(int argc, const char* argv[], Globals& globals) { | |
79 | int i = 1; | |
80 | ||
81 | std::vector<std::unique_ptr<Action>> actions; | |
82 | ||
83 | while (i < argc) { | |
84 | const char* arg = argv[i]; | |
85 | if ((strcmp(arg, "-h") == 0) || (strcasecmp(arg, "--help") == 0)) { | |
86 | usage(NULL); | |
87 | } else if ((strcmp(arg, "-v") == 0) || strcasecmp(arg, "--verbose") == 0) { | |
88 | globals.set_is_verbose(true); | |
89 | } else if (strcasecmp(arg, "--version") == 0) { | |
90 | shouldPrintVersion = true; | |
91 | } else if ((strcmp(arg, "-i") == 0) || strcasecmp(arg, "--initialize") == 0) { | |
92 | if (++i >= argc) | |
93 | usage("--initialize requires an argument"); | |
94 | ||
95 | arg = argv[i]; | |
96 | char* endptr; | |
97 | uint32_t temp = (uint32_t)strtoul(arg, &endptr, 0); | |
98 | if (*endptr == 0) { | |
99 | globals.set_trace_buffer_size(temp); | |
100 | } else { | |
101 | usage("Unable to parse --initialize argument"); | |
102 | } | |
103 | } else if (strcasecmp(arg, "--no-voucher-contents") == 0) { | |
104 | globals.set_should_trace_voucher_contents(false); | |
105 | } else if (strcasecmp(arg, "-L") == 0) { | |
106 | if (++i >= argc) | |
107 | usage("-L requires an argument"); | |
108 | ||
109 | arg = argv[i]; | |
110 | actions.push_back(std::make_unique<WriteTraceFileAction>(arg)); | |
111 | } else if (strcasecmp(arg, "--lifecycle") == 0) { | |
112 | if (++i >= argc) | |
113 | usage("--lifecycle requires an argument"); | |
114 | ||
115 | arg = argv[i]; | |
116 | if (strcasecmp(arg, "all") == 0) { | |
117 | globals.set_lifecycle_filter(kLifecycleFilter::All); | |
118 | } else if (strcasecmp(arg, "user") == 0) { | |
119 | globals.set_lifecycle_filter(kLifecycleFilter::User); | |
120 | } else if (strcasecmp(arg, "none") == 0) { | |
121 | globals.set_lifecycle_filter(kLifecycleFilter::None); | |
122 | } else { | |
123 | usage("Unrecognized --lifecycle value"); | |
124 | } | |
125 | } else if (strcasecmp(arg, "--mach-msg") == 0) { | |
126 | if (++i >= argc) | |
127 | usage("--mach-msg requires an argument"); | |
128 | ||
129 | arg = argv[i]; | |
130 | if (strcasecmp(arg, "all") == 0) { | |
131 | globals.set_mach_msg_filter(kMachMsgFilter::All); | |
132 | } else if (strcasecmp(arg, "user") == 0) { | |
133 | globals.set_mach_msg_filter(kMachMsgFilter::User); | |
134 | } else if (strcasecmp(arg, "voucher") == 0) { | |
135 | globals.set_mach_msg_filter(kMachMsgFilter::Voucher); | |
136 | } else if (strcasecmp(arg, "none") == 0) { | |
137 | globals.set_mach_msg_filter(kMachMsgFilter::None); | |
138 | } else { | |
139 | usage("Unrecognized --mach-msg value"); | |
140 | } | |
141 | } else if ((strcmp(arg, "-o") == 0) || strcasecmp(arg, "--output") == 0) { | |
142 | if (++i >= argc) | |
143 | usage("--output requires an argument"); | |
144 | ||
145 | FileDescriptor desc(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0644); | |
146 | if (!desc.is_open()) { | |
147 | char* errmsg = NULL; | |
148 | asprintf(&errmsg, "Unable to create output file at %s", argv[i]); | |
149 | usage(errmsg); | |
150 | } | |
151 | globals.set_output_fd(std::move(desc)); | |
152 | } else if (strcasecmp(arg, "--raw-timestamps") == 0) { | |
153 | globals.set_should_zero_base_timestamps(false); | |
154 | } else if (strcasecmp(arg, "--mach-absolute-time") == 0) { | |
155 | globals.set_should_print_mach_absolute_timestamps(true); | |
156 | } else if (strcasecmp(arg, "--event-index") == 0) { | |
157 | globals.set_should_print_event_index(true); | |
158 | } else { | |
159 | // | |
160 | // Last attempts to divine argument type/intent. | |
161 | // | |
162 | std::string temp(arg); | |
163 | ||
164 | if (ends_with(temp, ".trace")) { | |
165 | actions.push_back(create_read_trace_file_action(argv[i])); | |
166 | goto no_error; | |
167 | } | |
168 | ||
169 | // | |
170 | // ERROR! | |
171 | // | |
172 | char error_buffer[PATH_MAX]; | |
173 | snprintf(error_buffer, sizeof(error_buffer), "Unhandled argument: %s", arg); | |
174 | usage(error_buffer); | |
175 | } | |
176 | ||
177 | no_error: | |
178 | ||
179 | i++; | |
180 | } | |
181 | ||
182 | if (actions.empty()) { | |
183 | actions.push_back(std::make_unique<LiveTraceAction>()); | |
184 | } | |
185 | ||
186 | return actions; | |
187 | } | |
188 | ||
189 | int main(int argc, const char * argv[]) | |
190 | { | |
191 | // | |
192 | // Use host values as defaults. | |
193 | // User overrides as needed via flags. | |
194 | // | |
195 | Globals globals; | |
196 | auto actions = parse_arguments(argc, argv, globals); | |
197 | ||
198 | interestedInEverything = procsOfInterest.empty(); | |
199 | ||
200 | // globals.set_should_print_mach_absolute_timestamps(true); | |
201 | ||
202 | for (auto& action : actions) { | |
203 | action->execute(globals); | |
204 | } | |
205 | ||
206 | return 0; | |
207 | } | |
208 |