Linux Perf
trace-event-read.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 #include <dirent.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/wait.h>
29 #include <sys/mman.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33 
34 #include "../perf.h"
35 #include "util.h"
36 #include "trace-event.h"
37 #include "debug.h"
38 
39 static int input_fd;
40 
41 static ssize_t trace_data_size;
42 static bool repipe;
43 
44 static int __do_read(int fd, void *buf, int size)
45 {
46  int rsize = size;
47 
48  while (size) {
49  int ret = read(fd, buf, size);
50 
51  if (ret <= 0)
52  return -1;
53 
54  if (repipe) {
55  int retw = write(STDOUT_FILENO, buf, ret);
56 
57  if (retw <= 0 || retw != ret) {
58  pr_debug("repiping input file");
59  return -1;
60  }
61  }
62 
63  size -= ret;
64  buf += ret;
65  }
66 
67  return rsize;
68 }
69 
70 static int do_read(void *data, int size)
71 {
72  int r;
73 
74  r = __do_read(input_fd, data, size);
75  if (r <= 0) {
76  pr_debug("reading input file (size expected=%d received=%d)",
77  size, r);
78  return -1;
79  }
80 
81  trace_data_size += r;
82 
83  return r;
84 }
85 
86 /* If it fails, the next read will report it */
87 static void skip(int size)
88 {
89  char buf[BUFSIZ];
90  int r;
91 
92  while (size) {
93  r = size > BUFSIZ ? BUFSIZ : size;
94  do_read(buf, r);
95  size -= r;
96  };
97 }
98 
99 static unsigned int read4(struct pevent *pevent)
100 {
101  unsigned int data;
102 
103  if (do_read(&data, 4) < 0)
104  return 0;
105  return __data2host4(pevent, data);
106 }
107 
108 static unsigned long long read8(struct pevent *pevent)
109 {
110  unsigned long long data;
111 
112  if (do_read(&data, 8) < 0)
113  return 0;
114  return __data2host8(pevent, data);
115 }
116 
117 static char *read_string(void)
118 {
119  char buf[BUFSIZ];
120  char *str = NULL;
121  int size = 0;
122  off_t r;
123  char c;
124 
125  for (;;) {
126  r = read(input_fd, &c, 1);
127  if (r < 0) {
128  pr_debug("reading input file");
129  goto out;
130  }
131 
132  if (!r) {
133  pr_debug("no data");
134  goto out;
135  }
136 
137  if (repipe) {
138  int retw = write(STDOUT_FILENO, &c, 1);
139 
140  if (retw <= 0 || retw != r) {
141  pr_debug("repiping input file string");
142  goto out;
143  }
144  }
145 
146  buf[size++] = c;
147 
148  if (!c)
149  break;
150  }
151 
153 
154  str = malloc(size);
155  if (str)
156  memcpy(str, buf, size);
157 out:
158  return str;
159 }
160 
161 static int read_proc_kallsyms(struct pevent *pevent)
162 {
163  unsigned int size;
164 
165  size = read4(pevent);
166  if (!size)
167  return 0;
168  /*
169  * Just skip it, now that we configure libtraceevent to use the
170  * tools/perf/ symbol resolver.
171  *
172  * We need to skip it so that we can continue parsing old perf.data
173  * files, that contains this /proc/kallsyms payload.
174  *
175  * Newer perf.data files will have just the 4-bytes zeros "kallsyms
176  * payload", so that older tools can continue reading it and interpret
177  * it as "no kallsyms payload is present".
178  */
179  lseek(input_fd, size, SEEK_CUR);
181  return 0;
182 }
183 
184 static int read_ftrace_printk(struct pevent *pevent)
185 {
186  unsigned int size;
187  char *buf;
188 
189  /* it can have 0 size */
190  size = read4(pevent);
191  if (!size)
192  return 0;
193 
194  buf = malloc(size + 1);
195  if (buf == NULL)
196  return -1;
197 
198  if (do_read(buf, size) < 0) {
199  free(buf);
200  return -1;
201  }
202 
203  buf[size] = '\0';
204 
205  parse_ftrace_printk(pevent, buf, size);
206 
207  free(buf);
208  return 0;
209 }
210 
211 static int read_header_files(struct pevent *pevent)
212 {
213  unsigned long long size;
214  char *header_page;
215  char buf[BUFSIZ];
216  int ret = 0;
217 
218  if (do_read(buf, 12) < 0)
219  return -1;
220 
221  if (memcmp(buf, "header_page", 12) != 0) {
222  pr_debug("did not read header page");
223  return -1;
224  }
225 
226  size = read8(pevent);
227 
228  header_page = malloc(size);
229  if (header_page == NULL)
230  return -1;
231 
232  if (do_read(header_page, size) < 0) {
233  pr_debug("did not read header page");
234  free(header_page);
235  return -1;
236  }
237 
238  if (!pevent_parse_header_page(pevent, header_page, size,
239  pevent_get_long_size(pevent))) {
240  /*
241  * The commit field in the page is of type long,
242  * use that instead, since it represents the kernel.
243  */
244  pevent_set_long_size(pevent, pevent->header_page_size_size);
245  }
246  free(header_page);
247 
248  if (do_read(buf, 13) < 0)
249  return -1;
250 
251  if (memcmp(buf, "header_event", 13) != 0) {
252  pr_debug("did not read header event");
253  return -1;
254  }
255 
256  size = read8(pevent);
257  skip(size);
258 
259  return ret;
260 }
261 
262 static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
263 {
264  int ret;
265  char *buf;
266 
267  buf = malloc(size);
268  if (buf == NULL) {
269  pr_debug("memory allocation failure\n");
270  return -1;
271  }
272 
273  ret = do_read(buf, size);
274  if (ret < 0) {
275  pr_debug("error reading ftrace file.\n");
276  goto out;
277  }
278 
279  ret = parse_ftrace_file(pevent, buf, size);
280  if (ret < 0)
281  pr_debug("error parsing ftrace file.\n");
282 out:
283  free(buf);
284  return ret;
285 }
286 
287 static int read_event_file(struct pevent *pevent, char *sys,
288  unsigned long long size)
289 {
290  int ret;
291  char *buf;
292 
293  buf = malloc(size);
294  if (buf == NULL) {
295  pr_debug("memory allocation failure\n");
296  return -1;
297  }
298 
299  ret = do_read(buf, size);
300  if (ret < 0) {
301  free(buf);
302  goto out;
303  }
304 
305  ret = parse_event_file(pevent, buf, size, sys);
306  if (ret < 0)
307  pr_debug("error parsing event file.\n");
308 out:
309  free(buf);
310  return ret;
311 }
312 
313 static int read_ftrace_files(struct pevent *pevent)
314 {
315  unsigned long long size;
316  int count;
317  int i;
318  int ret;
319 
320  count = read4(pevent);
321 
322  for (i = 0; i < count; i++) {
323  size = read8(pevent);
324  ret = read_ftrace_file(pevent, size);
325  if (ret)
326  return ret;
327  }
328  return 0;
329 }
330 
331 static int read_event_files(struct pevent *pevent)
332 {
333  unsigned long long size;
334  char *sys;
335  int systems;
336  int count;
337  int i,x;
338  int ret;
339 
340  systems = read4(pevent);
341 
342  for (i = 0; i < systems; i++) {
343  sys = read_string();
344  if (sys == NULL)
345  return -1;
346 
347  count = read4(pevent);
348 
349  for (x=0; x < count; x++) {
350  size = read8(pevent);
351  ret = read_event_file(pevent, sys, size);
352  if (ret)
353  return ret;
354  }
355  }
356  return 0;
357 }
358 
359 static int read_saved_cmdline(struct pevent *pevent)
360 {
361  unsigned long long size;
362  char *buf;
363  int ret;
364 
365  /* it can have 0 size */
366  size = read8(pevent);
367  if (!size)
368  return 0;
369 
370  buf = malloc(size + 1);
371  if (buf == NULL) {
372  pr_debug("memory allocation failure\n");
373  return -1;
374  }
375 
376  ret = do_read(buf, size);
377  if (ret < 0) {
378  pr_debug("error reading saved cmdlines\n");
379  goto out;
380  }
381 
382  parse_saved_cmdline(pevent, buf, size);
383  ret = 0;
384 out:
385  free(buf);
386  return ret;
387 }
388 
389 ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
390 {
391  char buf[BUFSIZ];
392  char test[] = { 23, 8, 68 };
393  char *version;
394  int show_version = 0;
395  int show_funcs = 0;
396  int show_printk = 0;
397  ssize_t size = -1;
398  int file_bigendian;
399  int host_bigendian;
400  int file_long_size;
401  int file_page_size;
402  struct pevent *pevent = NULL;
403  int err;
404 
405  repipe = __repipe;
406  input_fd = fd;
407 
408  if (do_read(buf, 3) < 0)
409  return -1;
410  if (memcmp(buf, test, 3) != 0) {
411  pr_debug("no trace data in the file");
412  return -1;
413  }
414 
415  if (do_read(buf, 7) < 0)
416  return -1;
417  if (memcmp(buf, "tracing", 7) != 0) {
418  pr_debug("not a trace file (missing 'tracing' tag)");
419  return -1;
420  }
421 
422  version = read_string();
423  if (version == NULL)
424  return -1;
425  if (show_version)
426  printf("version = %s\n", version);
427 
428  if (do_read(buf, 1) < 0) {
429  free(version);
430  return -1;
431  }
432  file_bigendian = buf[0];
433  host_bigendian = bigendian();
434 
435  if (trace_event__init(tevent)) {
436  pr_debug("trace_event__init failed");
437  goto out;
438  }
439 
440  pevent = tevent->pevent;
441 
442  pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
443  pevent_set_file_bigendian(pevent, file_bigendian);
444  pevent_set_host_bigendian(pevent, host_bigendian);
445 
446  if (do_read(buf, 1) < 0)
447  goto out;
448  file_long_size = buf[0];
449 
450  file_page_size = read4(pevent);
451  if (!file_page_size)
452  goto out;
453 
454  pevent_set_long_size(pevent, file_long_size);
455  pevent_set_page_size(pevent, file_page_size);
456 
457  err = read_header_files(pevent);
458  if (err)
459  goto out;
460  err = read_ftrace_files(pevent);
461  if (err)
462  goto out;
463  err = read_event_files(pevent);
464  if (err)
465  goto out;
466  err = read_proc_kallsyms(pevent);
467  if (err)
468  goto out;
469  err = read_ftrace_printk(pevent);
470  if (err)
471  goto out;
472  if (atof(version) >= 0.6) {
473  err = read_saved_cmdline(pevent);
474  if (err)
475  goto out;
476  }
477 
478  size = trace_data_size;
479  repipe = false;
480 
481  if (show_funcs) {
482  pevent_print_funcs(pevent);
483  } else if (show_printk) {
484  pevent_print_printk(pevent);
485  }
486 
487  pevent = NULL;
488 
489 out:
490  if (pevent)
491  trace_event__cleanup(tevent);
492  free(version);
493  return size;
494 }
size_t size
Definition: evsel.c:60
int parse_event_file(struct pevent *pevent, char *buf, unsigned long size, char *sys)
static void skip(int size)
static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
static struct version version
dictionary data
Definition: stat-cpi.py:4
int int err
Definition: 5sec.c:44
int bigendian(void)
ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size __maybe_unused)
static struct trace_event tevent
Definition: trace-event.c:26
static int read_ftrace_files(struct pevent *pevent)
static int read_ftrace_printk(struct pevent *pevent)
void * malloc(YYSIZE_T)
int trace_event__init(struct trace_event *t)
Definition: trace-event.c:29
#define pr_debug(fmt,...)
Definition: json.h:27
static unsigned int read4(struct pevent *pevent)
void trace_event__cleanup(struct trace_event *t)
Definition: trace-event.c:66
static int __do_read(int fd, void *buf, int size)
static int input_fd
static bool repipe
static int str(yyscan_t scanner, int token)
x86 movsq based memcpy() in arch/x86/lib/memcpy_64.S") MEMCPY_FN(memcpy_erms
int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
static int do_read(void *data, int size)
static ssize_t trace_data_size
void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size __maybe_unused)
static int read_event_files(struct pevent *pevent)
static char * read_string(void)
Definition: tests.h:30
static int read_saved_cmdline(struct pevent *pevent)
void free(void *)
struct pevent * pevent
Definition: trace-event.h:16
static int read_event_file(struct pevent *pevent, char *sys, unsigned long long size)
static unsigned long long read8(struct pevent *pevent)
static int read_proc_kallsyms(struct pevent *pevent)
static int read_header_files(struct pevent *pevent)