Commit | Line | Data |
---|---|---|
5a8e0ff9 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
538bafb5 SR |
2 | /* |
3 | * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> | |
538bafb5 | 4 | */ |
538bafb5 SR |
5 | #include <dirent.h> |
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <string.h> | |
538bafb5 SR |
9 | #include <stdarg.h> |
10 | #include <sys/types.h> | |
11 | #include <sys/stat.h> | |
12 | #include <sys/wait.h> | |
13 | #include <sys/mman.h> | |
378ef0f5 | 14 | #include <traceevent/event-parse.h> |
538bafb5 SR |
15 | #include <fcntl.h> |
16 | #include <unistd.h> | |
538bafb5 SR |
17 | #include <errno.h> |
18 | ||
538bafb5 | 19 | #include "trace-event.h" |
84f5d36f | 20 | #include "debug.h" |
5b7a29fb | 21 | #include "util.h" |
538bafb5 SR |
22 | |
23 | static int input_fd; | |
24 | ||
ebf3c675 | 25 | static ssize_t trace_data_size; |
454c407e | 26 | static bool repipe; |
9215545e | 27 | |
4a31e565 | 28 | static int __do_read(int fd, void *buf, int size) |
9215545e TZ |
29 | { |
30 | int rsize = size; | |
31 | ||
32 | while (size) { | |
33 | int ret = read(fd, buf, size); | |
34 | ||
35 | if (ret <= 0) | |
36 | return -1; | |
37 | ||
454c407e TZ |
38 | if (repipe) { |
39 | int retw = write(STDOUT_FILENO, buf, ret); | |
40 | ||
4a31e565 NK |
41 | if (retw <= 0 || retw != ret) { |
42 | pr_debug("repiping input file"); | |
43 | return -1; | |
44 | } | |
454c407e TZ |
45 | } |
46 | ||
9215545e TZ |
47 | size -= ret; |
48 | buf += ret; | |
49 | } | |
50 | ||
51 | return rsize; | |
52 | } | |
53 | ||
4a31e565 | 54 | static int do_read(void *data, int size) |
538bafb5 SR |
55 | { |
56 | int r; | |
57 | ||
4a31e565 NK |
58 | r = __do_read(input_fd, data, size); |
59 | if (r <= 0) { | |
60 | pr_debug("reading input file (size expected=%d received=%d)", | |
61 | size, r); | |
62 | return -1; | |
63 | } | |
9215545e | 64 | |
ebf3c675 | 65 | trace_data_size += r; |
9215545e | 66 | |
538bafb5 SR |
67 | return r; |
68 | } | |
69 | ||
cbb5cf7f TZ |
70 | /* If it fails, the next read will report it */ |
71 | static void skip(int size) | |
72 | { | |
73 | char buf[BUFSIZ]; | |
74 | int r; | |
75 | ||
76 | while (size) { | |
77 | r = size > BUFSIZ ? BUFSIZ : size; | |
4a31e565 | 78 | do_read(buf, r); |
cbb5cf7f | 79 | size -= r; |
8284bbea | 80 | } |
cbb5cf7f TZ |
81 | } |
82 | ||
096177a8 | 83 | static unsigned int read4(struct tep_handle *pevent) |
538bafb5 SR |
84 | { |
85 | unsigned int data; | |
86 | ||
4a31e565 NK |
87 | if (do_read(&data, 4) < 0) |
88 | return 0; | |
f0bba09c | 89 | return tep_read_number(pevent, &data, 4); |
538bafb5 SR |
90 | } |
91 | ||
096177a8 | 92 | static unsigned long long read8(struct tep_handle *pevent) |
538bafb5 SR |
93 | { |
94 | unsigned long long data; | |
95 | ||
4a31e565 NK |
96 | if (do_read(&data, 8) < 0) |
97 | return 0; | |
f0bba09c | 98 | return tep_read_number(pevent, &data, 8); |
538bafb5 SR |
99 | } |
100 | ||
101 | static char *read_string(void) | |
102 | { | |
103 | char buf[BUFSIZ]; | |
104 | char *str = NULL; | |
105 | int size = 0; | |
f887f301 | 106 | off_t r; |
9215545e | 107 | char c; |
538bafb5 SR |
108 | |
109 | for (;;) { | |
9215545e | 110 | r = read(input_fd, &c, 1); |
452958fd NK |
111 | if (r < 0) { |
112 | pr_debug("reading input file"); | |
113 | goto out; | |
114 | } | |
538bafb5 | 115 | |
452958fd NK |
116 | if (!r) { |
117 | pr_debug("no data"); | |
118 | goto out; | |
119 | } | |
538bafb5 | 120 | |
454c407e TZ |
121 | if (repipe) { |
122 | int retw = write(STDOUT_FILENO, &c, 1); | |
123 | ||
452958fd NK |
124 | if (retw <= 0 || retw != r) { |
125 | pr_debug("repiping input file string"); | |
126 | goto out; | |
127 | } | |
454c407e TZ |
128 | } |
129 | ||
9215545e | 130 | buf[size++] = c; |
538bafb5 | 131 | |
9215545e TZ |
132 | if (!c) |
133 | break; | |
538bafb5 SR |
134 | } |
135 | ||
ebf3c675 | 136 | trace_data_size += size; |
9215545e | 137 | |
a4c98367 NK |
138 | str = malloc(size); |
139 | if (str) | |
140 | memcpy(str, buf, size); | |
452958fd | 141 | out: |
538bafb5 SR |
142 | return str; |
143 | } | |
144 | ||
096177a8 | 145 | static int read_proc_kallsyms(struct tep_handle *pevent) |
538bafb5 SR |
146 | { |
147 | unsigned int size; | |
538bafb5 | 148 | |
da378962 | 149 | size = read4(pevent); |
538bafb5 | 150 | if (!size) |
a4c98367 | 151 | return 0; |
4263cece ACM |
152 | /* |
153 | * Just skip it, now that we configure libtraceevent to use the | |
154 | * tools/perf/ symbol resolver. | |
155 | * | |
156 | * We need to skip it so that we can continue parsing old perf.data | |
157 | * files, that contains this /proc/kallsyms payload. | |
158 | * | |
159 | * Newer perf.data files will have just the 4-bytes zeros "kallsyms | |
160 | * payload", so that older tools can continue reading it and interpret | |
161 | * it as "no kallsyms payload is present". | |
162 | */ | |
163 | lseek(input_fd, size, SEEK_CUR); | |
164 | trace_data_size += size; | |
a4c98367 | 165 | return 0; |
538bafb5 SR |
166 | } |
167 | ||
096177a8 | 168 | static int read_ftrace_printk(struct tep_handle *pevent) |
538bafb5 SR |
169 | { |
170 | unsigned int size; | |
171 | char *buf; | |
172 | ||
4a31e565 | 173 | /* it can have 0 size */ |
da378962 | 174 | size = read4(pevent); |
538bafb5 | 175 | if (!size) |
a4c98367 NK |
176 | return 0; |
177 | ||
d4b364df | 178 | buf = malloc(size + 1); |
a4c98367 NK |
179 | if (buf == NULL) |
180 | return -1; | |
538bafb5 | 181 | |
4a31e565 NK |
182 | if (do_read(buf, size) < 0) { |
183 | free(buf); | |
184 | return -1; | |
185 | } | |
538bafb5 | 186 | |
d4b364df TR |
187 | buf[size] = '\0'; |
188 | ||
da378962 | 189 | parse_ftrace_printk(pevent, buf, size); |
538bafb5 SR |
190 | |
191 | free(buf); | |
a4c98367 | 192 | return 0; |
538bafb5 SR |
193 | } |
194 | ||
096177a8 | 195 | static int read_header_files(struct tep_handle *pevent) |
538bafb5 SR |
196 | { |
197 | unsigned long long size; | |
94b4d89e | 198 | char *header_page; |
538bafb5 | 199 | char buf[BUFSIZ]; |
4a31e565 | 200 | int ret = 0; |
538bafb5 | 201 | |
4a31e565 NK |
202 | if (do_read(buf, 12) < 0) |
203 | return -1; | |
538bafb5 | 204 | |
452958fd NK |
205 | if (memcmp(buf, "header_page", 12) != 0) { |
206 | pr_debug("did not read header page"); | |
207 | return -1; | |
208 | } | |
538bafb5 | 209 | |
da378962 | 210 | size = read8(pevent); |
94b4d89e NK |
211 | |
212 | header_page = malloc(size); | |
213 | if (header_page == NULL) | |
214 | return -1; | |
215 | ||
216 | if (do_read(header_page, size) < 0) { | |
217 | pr_debug("did not read header page"); | |
218 | free(header_page); | |
219 | return -1; | |
220 | } | |
221 | ||
c60167c1 | 222 | if (!tep_parse_header_page(pevent, header_page, size, |
ece2a4f4 | 223 | tep_get_long_size(pevent))) { |
94b4d89e NK |
224 | /* |
225 | * The commit field in the page is of type long, | |
226 | * use that instead, since it represents the kernel. | |
227 | */ | |
bb3dd7e7 | 228 | tep_set_long_size(pevent, tep_get_header_page_size(pevent)); |
94b4d89e NK |
229 | } |
230 | free(header_page); | |
538bafb5 | 231 | |
4a31e565 NK |
232 | if (do_read(buf, 13) < 0) |
233 | return -1; | |
234 | ||
452958fd NK |
235 | if (memcmp(buf, "header_event", 13) != 0) { |
236 | pr_debug("did not read header event"); | |
237 | return -1; | |
238 | } | |
538bafb5 | 239 | |
da378962 | 240 | size = read8(pevent); |
2b2efc7f | 241 | skip(size); |
4a31e565 | 242 | |
4a31e565 | 243 | return ret; |
538bafb5 SR |
244 | } |
245 | ||
096177a8 | 246 | static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) |
538bafb5 | 247 | { |
a7619aef | 248 | int ret; |
538bafb5 SR |
249 | char *buf; |
250 | ||
a4c98367 | 251 | buf = malloc(size); |
a7619aef NK |
252 | if (buf == NULL) { |
253 | pr_debug("memory allocation failure\n"); | |
a4c98367 | 254 | return -1; |
a7619aef | 255 | } |
a4c98367 | 256 | |
a7619aef NK |
257 | ret = do_read(buf, size); |
258 | if (ret < 0) { | |
259 | pr_debug("error reading ftrace file.\n"); | |
260 | goto out; | |
4a31e565 NK |
261 | } |
262 | ||
a7619aef NK |
263 | ret = parse_ftrace_file(pevent, buf, size); |
264 | if (ret < 0) | |
265 | pr_debug("error parsing ftrace file.\n"); | |
266 | out: | |
538bafb5 | 267 | free(buf); |
a7619aef | 268 | return ret; |
538bafb5 SR |
269 | } |
270 | ||
096177a8 TSV |
271 | static int read_event_file(struct tep_handle *pevent, char *sys, |
272 | unsigned long long size) | |
538bafb5 | 273 | { |
a7619aef | 274 | int ret; |
538bafb5 SR |
275 | char *buf; |
276 | ||
a4c98367 | 277 | buf = malloc(size); |
a7619aef NK |
278 | if (buf == NULL) { |
279 | pr_debug("memory allocation failure\n"); | |
a4c98367 | 280 | return -1; |
a7619aef | 281 | } |
a4c98367 | 282 | |
a7619aef | 283 | ret = do_read(buf, size); |
470c8f7c | 284 | if (ret < 0) |
a7619aef | 285 | goto out; |
4a31e565 | 286 | |
a7619aef NK |
287 | ret = parse_event_file(pevent, buf, size, sys); |
288 | if (ret < 0) | |
289 | pr_debug("error parsing event file.\n"); | |
290 | out: | |
538bafb5 | 291 | free(buf); |
a7619aef | 292 | return ret; |
538bafb5 SR |
293 | } |
294 | ||
096177a8 | 295 | static int read_ftrace_files(struct tep_handle *pevent) |
538bafb5 SR |
296 | { |
297 | unsigned long long size; | |
298 | int count; | |
299 | int i; | |
a4c98367 | 300 | int ret; |
538bafb5 | 301 | |
da378962 | 302 | count = read4(pevent); |
538bafb5 SR |
303 | |
304 | for (i = 0; i < count; i++) { | |
da378962 | 305 | size = read8(pevent); |
a4c98367 NK |
306 | ret = read_ftrace_file(pevent, size); |
307 | if (ret) | |
308 | return ret; | |
538bafb5 | 309 | } |
a4c98367 | 310 | return 0; |
538bafb5 SR |
311 | } |
312 | ||
096177a8 | 313 | static int read_event_files(struct tep_handle *pevent) |
538bafb5 SR |
314 | { |
315 | unsigned long long size; | |
316 | char *sys; | |
317 | int systems; | |
318 | int count; | |
319 | int i,x; | |
a4c98367 | 320 | int ret; |
538bafb5 | 321 | |
da378962 | 322 | systems = read4(pevent); |
538bafb5 SR |
323 | |
324 | for (i = 0; i < systems; i++) { | |
325 | sys = read_string(); | |
a4c98367 NK |
326 | if (sys == NULL) |
327 | return -1; | |
538bafb5 | 328 | |
da378962 | 329 | count = read4(pevent); |
4a31e565 | 330 | |
538bafb5 | 331 | for (x=0; x < count; x++) { |
da378962 | 332 | size = read8(pevent); |
a4c98367 | 333 | ret = read_event_file(pevent, sys, size); |
1e44224f SS |
334 | if (ret) { |
335 | free(sys); | |
a4c98367 | 336 | return ret; |
1e44224f | 337 | } |
538bafb5 | 338 | } |
1e44224f | 339 | free(sys); |
538bafb5 | 340 | } |
a4c98367 | 341 | return 0; |
538bafb5 SR |
342 | } |
343 | ||
096177a8 | 344 | static int read_saved_cmdline(struct tep_handle *pevent) |
cd4ceb63 NK |
345 | { |
346 | unsigned long long size; | |
347 | char *buf; | |
a7619aef | 348 | int ret; |
cd4ceb63 NK |
349 | |
350 | /* it can have 0 size */ | |
351 | size = read8(pevent); | |
352 | if (!size) | |
353 | return 0; | |
354 | ||
355 | buf = malloc(size + 1); | |
a7619aef NK |
356 | if (buf == NULL) { |
357 | pr_debug("memory allocation failure\n"); | |
cd4ceb63 | 358 | return -1; |
a7619aef | 359 | } |
cd4ceb63 | 360 | |
a7619aef NK |
361 | ret = do_read(buf, size); |
362 | if (ret < 0) { | |
363 | pr_debug("error reading saved cmdlines\n"); | |
364 | goto out; | |
cd4ceb63 | 365 | } |
137a5258 | 366 | buf[ret] = '\0'; |
cd4ceb63 NK |
367 | |
368 | parse_saved_cmdline(pevent, buf, size); | |
a7619aef NK |
369 | ret = 0; |
370 | out: | |
cd4ceb63 | 371 | free(buf); |
a7619aef | 372 | return ret; |
cd4ceb63 NK |
373 | } |
374 | ||
29f5ffd3 | 375 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) |
538bafb5 | 376 | { |
538bafb5 SR |
377 | char buf[BUFSIZ]; |
378 | char test[] = { 23, 8, 68 }; | |
379 | char *version; | |
d9340c1d | 380 | int show_version = 0; |
538bafb5 SR |
381 | int show_funcs = 0; |
382 | int show_printk = 0; | |
3dce2ce3 | 383 | ssize_t size = -1; |
63af28fa NK |
384 | int file_bigendian; |
385 | int host_bigendian; | |
59657f9c | 386 | int file_long_size; |
30f36762 | 387 | int file_page_size; |
096177a8 | 388 | struct tep_handle *pevent = NULL; |
a4c98367 | 389 | int err; |
3dce2ce3 | 390 | |
454c407e | 391 | repipe = __repipe; |
03456a15 | 392 | input_fd = fd; |
538bafb5 | 393 | |
4a31e565 NK |
394 | if (do_read(buf, 3) < 0) |
395 | return -1; | |
452958fd NK |
396 | if (memcmp(buf, test, 3) != 0) { |
397 | pr_debug("no trace data in the file"); | |
398 | return -1; | |
399 | } | |
538bafb5 | 400 | |
4a31e565 NK |
401 | if (do_read(buf, 7) < 0) |
402 | return -1; | |
452958fd NK |
403 | if (memcmp(buf, "tracing", 7) != 0) { |
404 | pr_debug("not a trace file (missing 'tracing' tag)"); | |
405 | return -1; | |
406 | } | |
538bafb5 SR |
407 | |
408 | version = read_string(); | |
a4c98367 NK |
409 | if (version == NULL) |
410 | return -1; | |
d9340c1d IM |
411 | if (show_version) |
412 | printf("version = %s\n", version); | |
538bafb5 | 413 | |
cd4ceb63 NK |
414 | if (do_read(buf, 1) < 0) { |
415 | free(version); | |
4a31e565 | 416 | return -1; |
cd4ceb63 | 417 | } |
538bafb5 | 418 | file_bigendian = buf[0]; |
5b7a29fb | 419 | host_bigendian = host_is_bigendian() ? 1 : 0; |
538bafb5 | 420 | |
29f5ffd3 JO |
421 | if (trace_event__init(tevent)) { |
422 | pr_debug("trace_event__init failed"); | |
3dce2ce3 NK |
423 | goto out; |
424 | } | |
aaf045f7 | 425 | |
29f5ffd3 JO |
426 | pevent = tevent->pevent; |
427 | ||
6fed932e | 428 | tep_set_flag(pevent, TEP_NSEC_OUTPUT); |
ece2a4f4 | 429 | tep_set_file_bigendian(pevent, file_bigendian); |
55c34ae0 | 430 | tep_set_local_bigendian(pevent, host_bigendian); |
29f5ffd3 | 431 | |
4a31e565 NK |
432 | if (do_read(buf, 1) < 0) |
433 | goto out; | |
59657f9c | 434 | file_long_size = buf[0]; |
538bafb5 | 435 | |
30f36762 NK |
436 | file_page_size = read4(pevent); |
437 | if (!file_page_size) | |
4a31e565 | 438 | goto out; |
538bafb5 | 439 | |
ece2a4f4 TSV |
440 | tep_set_long_size(pevent, file_long_size); |
441 | tep_set_page_size(pevent, file_page_size); | |
30f36762 | 442 | |
a4c98367 NK |
443 | err = read_header_files(pevent); |
444 | if (err) | |
445 | goto out; | |
446 | err = read_ftrace_files(pevent); | |
447 | if (err) | |
448 | goto out; | |
449 | err = read_event_files(pevent); | |
450 | if (err) | |
451 | goto out; | |
452 | err = read_proc_kallsyms(pevent); | |
453 | if (err) | |
454 | goto out; | |
455 | err = read_ftrace_printk(pevent); | |
456 | if (err) | |
457 | goto out; | |
cd4ceb63 NK |
458 | if (atof(version) >= 0.6) { |
459 | err = read_saved_cmdline(pevent); | |
460 | if (err) | |
461 | goto out; | |
462 | } | |
538bafb5 | 463 | |
ebf3c675 | 464 | size = trace_data_size; |
454c407e | 465 | repipe = false; |
9215545e | 466 | |
538bafb5 | 467 | if (show_funcs) { |
6a48dc29 | 468 | tep_print_funcs(pevent); |
3dce2ce3 | 469 | } else if (show_printk) { |
6a48dc29 | 470 | tep_print_printk(pevent); |
538bafb5 SR |
471 | } |
472 | ||
3dce2ce3 NK |
473 | pevent = NULL; |
474 | ||
475 | out: | |
476 | if (pevent) | |
29f5ffd3 | 477 | trace_event__cleanup(tevent); |
cd4ceb63 | 478 | free(version); |
9215545e | 479 | return size; |
538bafb5 | 480 | } |