blob: 276256439b784804ea86d0c28873487d8a475fb8 [file] [log] [blame]
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001#include "util/util.h"
Ingo Molnar16f762a2009-05-27 09:10:38 +02002#include "builtin.h"
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02003
4#include <libelf.h>
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -03005#include <gelf.h>
6#include <elf.h>
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03007
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -03008#include "util/list.h"
Ingo Molnara930d2c2009-05-27 09:50:13 +02009#include "util/cache.h"
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030010#include "util/rbtree.h"
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030011
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020012#include "perf.h"
13
14#include "util/parse-options.h"
15#include "util/parse-events.h"
16
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030017#define SHOW_KERNEL 1
18#define SHOW_USER 2
19#define SHOW_HV 4
20
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020021static char const *input_name = "perf.data";
Peter Zijlstra450aaa22009-05-27 20:20:23 +020022static char *vmlinux = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030023static int input;
24static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
25
Ingo Molnar97b07b62009-05-26 18:48:58 +020026static int dump_trace = 0;
Ingo Molnar16f762a2009-05-27 09:10:38 +020027static int verbose;
Ingo Molnar97b07b62009-05-26 18:48:58 +020028
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030029static unsigned long page_size;
30static unsigned long mmap_window = 32;
31
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020032const char *perf_event_names[] = {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030033 [PERF_EVENT_MMAP] = " PERF_EVENT_MMAP",
34 [PERF_EVENT_MUNMAP] = " PERF_EVENT_MUNMAP",
35 [PERF_EVENT_COMM] = " PERF_EVENT_COMM",
36};
37
38struct ip_event {
39 struct perf_event_header header;
40 __u64 ip;
41 __u32 pid, tid;
42};
43struct mmap_event {
44 struct perf_event_header header;
45 __u32 pid, tid;
46 __u64 start;
47 __u64 len;
48 __u64 pgoff;
49 char filename[PATH_MAX];
50};
51struct comm_event {
52 struct perf_event_header header;
53 __u32 pid,tid;
54 char comm[16];
55};
56
57typedef union event_union {
58 struct perf_event_header header;
59 struct ip_event ip;
60 struct mmap_event mmap;
61 struct comm_event comm;
62} event_t;
63
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030064struct symbol {
Ingo Molnar16f762a2009-05-27 09:10:38 +020065 struct rb_node rb_node;
66 __u64 start;
67 __u64 end;
68 char name[0];
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030069};
70
71static struct symbol *symbol__new(uint64_t start, uint64_t len, const char *name)
72{
73 struct symbol *self = malloc(sizeof(*self) + strlen(name) + 1);
74
75 if (self != NULL) {
76 self->start = start;
77 self->end = start + len;
78 strcpy(self->name, name);
79 }
80
81 return self;
82}
83
84static void symbol__delete(struct symbol *self)
85{
86 free(self);
87}
88
89static size_t symbol__fprintf(struct symbol *self, FILE *fp)
90{
Ingo Molnar16f762a2009-05-27 09:10:38 +020091 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030092 self->start, self->end, self->name);
93}
94
95struct dso {
96 struct list_head node;
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030097 struct rb_root syms;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030098 char name[0];
99};
100
101static struct dso *dso__new(const char *name)
102{
103 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
104
105 if (self != NULL) {
106 strcpy(self->name, name);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300107 self->syms = RB_ROOT;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300108 }
109
110 return self;
111}
112
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300113static void dso__delete_symbols(struct dso *self)
114{
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300115 struct symbol *pos;
116 struct rb_node *next = rb_first(&self->syms);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300117
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300118 while (next) {
119 pos = rb_entry(next, struct symbol, rb_node);
120 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300121 symbol__delete(pos);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300122 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300123}
124
125static void dso__delete(struct dso *self)
126{
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300127 dso__delete_symbols(self);
128 free(self);
129}
130
131static void dso__insert_symbol(struct dso *self, struct symbol *sym)
132{
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300133 struct rb_node **p = &self->syms.rb_node;
134 struct rb_node *parent = NULL;
135 const uint64_t ip = sym->start;
136 struct symbol *s;
137
138 while (*p != NULL) {
139 parent = *p;
140 s = rb_entry(parent, struct symbol, rb_node);
141 if (ip < s->start)
142 p = &(*p)->rb_left;
143 else
144 p = &(*p)->rb_right;
145 }
146 rb_link_node(&sym->rb_node, parent, p);
147 rb_insert_color(&sym->rb_node, &self->syms);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300148}
149
150static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
151{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200152 struct rb_node *n;
153
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300154 if (self == NULL)
155 return NULL;
156
Ingo Molnar16f762a2009-05-27 09:10:38 +0200157 n = self->syms.rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300158
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300159 while (n) {
160 struct symbol *s = rb_entry(n, struct symbol, rb_node);
161
162 if (ip < s->start)
163 n = n->rb_left;
164 else if (ip > s->end)
165 n = n->rb_right;
166 else
167 return s;
168 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300169
170 return NULL;
171}
172
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300173/**
174 * elf_symtab__for_each_symbol - iterate thru all the symbols
175 *
176 * @self: struct elf_symtab instance to iterate
177 * @index: uint32_t index
178 * @sym: GElf_Sym iterator
179 */
180#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
181 for (index = 0, gelf_getsym(syms, index, &sym);\
182 index < nr_syms; \
183 index++, gelf_getsym(syms, index, &sym))
184
185static inline uint8_t elf_sym__type(const GElf_Sym *sym)
186{
187 return GELF_ST_TYPE(sym->st_info);
188}
189
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200190static inline int elf_sym__is_function(const GElf_Sym *sym)
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300191{
192 return elf_sym__type(sym) == STT_FUNC &&
193 sym->st_name != 0 &&
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200194 sym->st_shndx != SHN_UNDEF &&
195 sym->st_size != 0;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300196}
197
198static inline const char *elf_sym__name(const GElf_Sym *sym,
199 const Elf_Data *symstrs)
200{
201 return symstrs->d_buf + sym->st_name;
202}
203
204static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
205 GElf_Shdr *shp, const char *name,
206 size_t *index)
207{
208 Elf_Scn *sec = NULL;
209 size_t cnt = 1;
210
211 while ((sec = elf_nextscn(elf, sec)) != NULL) {
212 char *str;
213
214 gelf_getshdr(sec, shp);
215 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
216 if (!strcmp(name, str)) {
217 if (index)
218 *index = cnt;
219 break;
220 }
221 ++cnt;
222 }
223
224 return sec;
225}
226
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200227static int dso__load_sym(struct dso *self, int fd, char *name)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300228{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200229 Elf_Data *symstrs;
230 uint32_t nr_syms;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200231 int err = -1;
Ingo Molnar16f762a2009-05-27 09:10:38 +0200232 uint32_t index;
233 GElf_Ehdr ehdr;
234 GElf_Shdr shdr;
235 Elf_Data *syms;
236 GElf_Sym sym;
237 Elf_Scn *sec;
238 Elf *elf;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200239 int nr = 0;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300240
Ingo Molnar16f762a2009-05-27 09:10:38 +0200241 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300242 if (elf == NULL) {
243 fprintf(stderr, "%s: cannot read %s ELF file.\n",
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200244 __func__, name);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300245 goto out_close;
246 }
247
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300248 if (gelf_getehdr(elf, &ehdr) == NULL) {
249 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
250 goto out_elf_end;
251 }
252
Ingo Molnar16f762a2009-05-27 09:10:38 +0200253 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300254 if (sec == NULL)
255 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
256
257 if (sec == NULL)
258 goto out_elf_end;
259
Ingo Molnar16f762a2009-05-27 09:10:38 +0200260 syms = elf_getdata(sec, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300261 if (syms == NULL)
262 goto out_elf_end;
263
264 sec = elf_getscn(elf, shdr.sh_link);
265 if (sec == NULL)
266 goto out_elf_end;
267
Ingo Molnar16f762a2009-05-27 09:10:38 +0200268 symstrs = elf_getdata(sec, NULL);
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300269 if (symstrs == NULL)
270 goto out_elf_end;
271
Ingo Molnar16f762a2009-05-27 09:10:38 +0200272 nr_syms = shdr.sh_size / shdr.sh_entsize;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300273
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300274 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200275 struct symbol *f;
276
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300277 if (!elf_sym__is_function(&sym))
278 continue;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200279
280 sec = elf_getscn(elf, sym.st_shndx);
281 if (!sec)
282 goto out_elf_end;
283
284 gelf_getshdr(sec, &shdr);
285 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
286
287 f = symbol__new(sym.st_value, sym.st_size,
288 elf_sym__name(&sym, symstrs));
289 if (!f)
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300290 goto out_elf_end;
291
292 dso__insert_symbol(self, f);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200293
294 nr++;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300295 }
296
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200297 err = nr;
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300298out_elf_end:
299 elf_end(elf);
300out_close:
Arnaldo Carvalho de Melo62eb9392009-05-18 14:28:47 -0300301 return err;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300302}
303
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200304static int dso__load(struct dso *self)
305{
306 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
307 char *name = malloc(size);
308 int variant = 0;
309 int ret = -1;
310 int fd;
311
312 if (!name)
313 return -1;
314
315more:
316 do {
317 switch (variant) {
318 case 0: /* Fedora */
319 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
320 break;
321 case 1: /* Ubuntu */
322 snprintf(name, size, "/usr/lib/debug%s", self->name);
323 break;
324 case 2: /* Sane people */
325 snprintf(name, size, "%s", self->name);
326 break;
327
328 default:
329 goto out;
330 }
331 variant++;
332
333 fd = open(name, O_RDONLY);
334 } while (fd < 0);
335
336 ret = dso__load_sym(self, fd, name);
337 close(fd);
338
339 /*
340 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
341 */
342 if (!ret)
343 goto more;
344
345out:
346 free(name);
347 return ret;
348}
349
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300350static size_t dso__fprintf(struct dso *self, FILE *fp)
351{
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300352 size_t ret = fprintf(fp, "dso: %s\n", self->name);
353
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300354 struct rb_node *nd;
355 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
356 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300357 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -0300358 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300359
360 return ret;
361}
362
363static LIST_HEAD(dsos);
364static struct dso *kernel_dso;
365
366static void dsos__add(struct dso *dso)
367{
368 list_add_tail(&dso->node, &dsos);
369}
370
371static struct dso *dsos__find(const char *name)
372{
373 struct dso *pos;
374
375 list_for_each_entry(pos, &dsos, node)
376 if (strcmp(pos->name, name) == 0)
377 return pos;
378 return NULL;
379}
380
381static struct dso *dsos__findnew(const char *name)
382{
383 struct dso *dso = dsos__find(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200384 int nr;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300385
386 if (dso == NULL) {
387 dso = dso__new(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200388 if (!dso)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300389 goto out_delete_dso;
390
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200391 nr = dso__load(dso);
392 if (nr < 0) {
393 fprintf(stderr, "Failed to open: %s\n", name);
394 goto out_delete_dso;
395 }
396 if (!nr) {
397 fprintf(stderr,
398 "Failed to find debug symbols for: %s, maybe install a debug package?\n",
399 name);
400 }
401
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300402 dsos__add(dso);
403 }
404
405 return dso;
406
407out_delete_dso:
408 dso__delete(dso);
409 return NULL;
410}
411
Ingo Molnar16f762a2009-05-27 09:10:38 +0200412static void dsos__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300413{
414 struct dso *pos;
415
416 list_for_each_entry(pos, &dsos, node)
417 dso__fprintf(pos, fp);
418}
419
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300420static int hex(char ch)
421{
422 if ((ch >= '0') && (ch <= '9'))
423 return ch - '0';
424 if ((ch >= 'a') && (ch <= 'f'))
425 return ch - 'a' + 10;
426 if ((ch >= 'A') && (ch <= 'F'))
427 return ch - 'A' + 10;
428 return -1;
429}
430
431/*
432 * While we find nice hex chars, build a long_val.
433 * Return number of chars processed.
434 */
Ingo Molnar16f762a2009-05-27 09:10:38 +0200435static int hex2long(char *ptr, unsigned long *long_val)
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300436{
437 const char *p = ptr;
438 *long_val = 0;
439
440 while (*p) {
441 const int hex_val = hex(*p);
442
443 if (hex_val < 0)
444 break;
445
446 *long_val = (*long_val << 4) | hex_val;
447 p++;
448 }
449
450 return p - ptr;
451}
452
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300453static int load_kallsyms(void)
454{
Ingo Molnaraf836322009-05-27 08:38:48 +0200455 struct rb_node *nd, *prevnd;
456 char *line = NULL;
457 FILE *file;
458 size_t n;
459
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300460 kernel_dso = dso__new("[kernel]");
461 if (kernel_dso == NULL)
462 return -1;
463
Ingo Molnaraf836322009-05-27 08:38:48 +0200464 file = fopen("/proc/kallsyms", "r");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300465 if (file == NULL)
466 goto out_delete_dso;
467
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300468 while (!feof(file)) {
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300469 unsigned long start;
Ingo Molnaraf836322009-05-27 08:38:48 +0200470 struct symbol *sym;
471 int line_len, len;
472 char symbol_type;
473
474 line_len = getline(&line, &n, file);
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300475 if (line_len < 0)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300476 break;
477
478 if (!line)
479 goto out_delete_dso;
480
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300481 line[--line_len] = '\0'; /* \n */
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300482
Ingo Molnaraf836322009-05-27 08:38:48 +0200483 len = hex2long(line, &start);
484
Arnaldo Carvalho de Melo03f63162009-05-26 19:21:55 -0300485 len++;
486 if (len + 2 >= line_len)
487 continue;
488
Ingo Molnaraf836322009-05-27 08:38:48 +0200489 symbol_type = toupper(line[len]);
Arnaldo Carvalho de Melo03f63162009-05-26 19:21:55 -0300490 /*
491 * We're interested only in code ('T'ext)
492 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200493 if (symbol_type != 'T' && symbol_type != 'W')
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300494 continue;
495 /*
496 * Well fix up the end later, when we have all sorted.
497 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200498 sym = symbol__new(start, 0xdead, line + len + 2);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300499
Arnaldo Carvalho de Melod8d16562009-05-26 19:20:57 -0300500 if (sym == NULL)
501 goto out_delete_dso;
502
503 dso__insert_symbol(kernel_dso, sym);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300504 }
505
Arnaldo Carvalho de Meloabd54f62009-05-26 12:21:34 -0300506 /*
507 * Now that we have all sorted out, just set the ->end of all
508 * symbols
509 */
Ingo Molnaraf836322009-05-27 08:38:48 +0200510 prevnd = rb_first(&kernel_dso->syms);
Arnaldo Carvalho de Meloabd54f62009-05-26 12:21:34 -0300511
512 if (prevnd == NULL)
513 goto out_delete_line;
514
515 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
516 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
517 *curr = rb_entry(nd, struct symbol, rb_node);
518
519 prev->end = curr->start - 1;
520 prevnd = nd;
521 }
522
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300523 dsos__add(kernel_dso);
524 free(line);
525 fclose(file);
Ingo Molnaraf836322009-05-27 08:38:48 +0200526
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300527 return 0;
528
Arnaldo Carvalho de Melo59d81022009-05-26 11:14:27 -0300529out_delete_line:
530 free(line);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300531out_delete_dso:
532 dso__delete(kernel_dso);
533 return -1;
534}
535
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200536static int load_kernel(void)
537{
538 int fd, nr;
539
540 if (!vmlinux)
541 goto kallsyms;
542
543 fd = open(vmlinux, O_RDONLY);
544 if (fd < 0)
545 goto kallsyms;
546
547 kernel_dso = dso__new("[kernel]");
548 if (!kernel_dso)
549 goto fail_open;
550
551 nr = dso__load_sym(kernel_dso, fd, vmlinux);
552
553 if (nr <= 0)
554 goto fail_load;
555
556 dsos__add(kernel_dso);
557 close(fd);
558
559 return 0;
560
561fail_load:
562 dso__delete(kernel_dso);
563fail_open:
564 close(fd);
565kallsyms:
566 return load_kallsyms();
567}
568
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300569struct map {
570 struct list_head node;
571 uint64_t start;
572 uint64_t end;
573 uint64_t pgoff;
574 struct dso *dso;
575};
576
577static struct map *map__new(struct mmap_event *event)
578{
579 struct map *self = malloc(sizeof(*self));
580
581 if (self != NULL) {
582 self->start = event->start;
583 self->end = event->start + event->len;
584 self->pgoff = event->pgoff;
585
586 self->dso = dsos__findnew(event->filename);
587 if (self->dso == NULL)
588 goto out_delete;
589 }
590 return self;
591out_delete:
592 free(self);
593 return NULL;
594}
595
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300596struct thread;
597
598static const char *thread__name(struct thread *self, char *bf, size_t size);
599
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300600struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300601 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300602 struct list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300603 pid_t pid;
604 char *comm;
605};
606
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300607static const char *thread__name(struct thread *self, char *bf, size_t size)
608{
609 if (self->comm)
610 return self->comm;
611
612 snprintf(bf, sizeof(bf), ":%u", self->pid);
613 return bf;
614}
615
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300616static struct thread *thread__new(pid_t pid)
617{
618 struct thread *self = malloc(sizeof(*self));
619
620 if (self != NULL) {
621 self->pid = pid;
622 self->comm = NULL;
623 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300624 }
625
626 return self;
627}
628
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300629static int thread__set_comm(struct thread *self, const char *comm)
630{
631 self->comm = strdup(comm);
632 return self->comm ? 0 : -ENOMEM;
633}
634
Ingo Molnar16f762a2009-05-27 09:10:38 +0200635static struct rb_root threads;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300636
637static struct thread *threads__findnew(pid_t pid)
638{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300639 struct rb_node **p = &threads.rb_node;
640 struct rb_node *parent = NULL;
641 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300642
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300643 while (*p != NULL) {
644 parent = *p;
645 th = rb_entry(parent, struct thread, rb_node);
646
647 if (th->pid == pid)
648 return th;
649
650 if (pid < th->pid)
651 p = &(*p)->rb_left;
652 else
653 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300654 }
655
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300656 th = thread__new(pid);
657 if (th != NULL) {
658 rb_link_node(&th->rb_node, parent, p);
659 rb_insert_color(&th->rb_node, &threads);
660 }
661 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300662}
663
664static void thread__insert_map(struct thread *self, struct map *map)
665{
666 list_add_tail(&map->node, &self->maps);
667}
668
669static struct map *thread__find_map(struct thread *self, uint64_t ip)
670{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200671 struct map *pos;
672
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300673 if (self == NULL)
674 return NULL;
675
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300676 list_for_each_entry(pos, &self->maps, node)
677 if (ip >= pos->start && ip <= pos->end)
678 return pos;
679
680 return NULL;
681}
682
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200683/*
684 * histogram, sorted on item, collects counts
685 */
686
687static struct rb_root hist;
688
689struct hist_entry {
690 struct rb_node rb_node;
691
692 struct thread *thread;
693 struct map *map;
694 struct dso *dso;
695 struct symbol *sym;
696 uint64_t ip;
697 char level;
698
699 uint32_t count;
700};
701
702static int64_t
703hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300704{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200705 uint64_t ip_l, ip_r;
706 int cmp = right->thread->pid - left->thread->pid;
707
708 if (cmp)
709 return cmp;
710
711 if (left->sym == right->sym)
712 return 0;
713
714 ip_l = left->sym ? left->sym->start : left->ip;
715 ip_r = right->sym ? right->sym->start : right->ip;
716
717 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300718}
719
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200720static int
721hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
722 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300723{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200724 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300725 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200726 struct hist_entry *he;
727 struct hist_entry entry = {
728 .thread = thread,
729 .map = map,
730 .dso = dso,
731 .sym = sym,
732 .ip = ip,
733 .level = level,
734 .count = 1,
735 };
736 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300737
738 while (*p != NULL) {
739 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200740 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300741
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200742 cmp = hist_entry__cmp(&entry, he);
743
744 if (!cmp) {
745 he->count++;
746 return 0;
747 }
748
749 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300750 p = &(*p)->rb_left;
751 else
752 p = &(*p)->rb_right;
753 }
754
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200755 he = malloc(sizeof(*he));
756 if (!he)
757 return -ENOMEM;
758 *he = entry;
759 rb_link_node(&he->rb_node, parent, p);
760 rb_insert_color(&he->rb_node, &hist);
761
762 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300763}
764
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200765static size_t
766hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300767{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200768 char bf[32];
769 size_t ret;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300770
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200771 if (total_samples) {
772 ret = fprintf(fp, "%5.2f%% ",
773 (self->count * 100.0) / total_samples);
774 } else
775 ret = fprintf(fp, "%12d ", self->count);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300776
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200777 ret += fprintf(fp, "%14s [%c] ",
778 thread__name(self->thread, bf, sizeof(bf)),
779 self->level);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300780
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200781 if (verbose)
782 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
783
784 if (self->level != '.')
785 ret += fprintf(fp, "%s\n",
786 self->sym ? self->sym->name : "<unknown>");
787 else
788 ret += fprintf(fp, "%s: %s\n",
789 self->dso ? self->dso->name : "<unknown>",
790 self->sym ? self->sym->name : "<unknown>");
791 return ret;
792}
793
794/*
795 * reverse the map, sort on count.
796 */
797
798static struct rb_root output_hists;
799
800static void output__insert_entry(struct hist_entry *he)
801{
802 struct rb_node **p = &output_hists.rb_node;
803 struct rb_node *parent = NULL;
804 struct hist_entry *iter;
805
806 while (*p != NULL) {
807 parent = *p;
808 iter = rb_entry(parent, struct hist_entry, rb_node);
809
810 if (he->count > iter->count)
811 p = &(*p)->rb_left;
812 else
813 p = &(*p)->rb_right;
814 }
815
816 rb_link_node(&he->rb_node, parent, p);
817 rb_insert_color(&he->rb_node, &output_hists);
818}
819
820static void output__resort(void)
821{
822 struct rb_node *next = rb_first(&hist);
823 struct hist_entry *n;
824
825 while (next) {
826 n = rb_entry(next, struct hist_entry, rb_node);
827 next = rb_next(&n->rb_node);
828
829 rb_erase(&n->rb_node, &hist);
830 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300831 }
832}
833
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200834static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300835{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200836 struct hist_entry *pos;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300837 struct rb_node *nd;
838 size_t ret = 0;
839
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200840 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
841 pos = rb_entry(nd, struct hist_entry, rb_node);
842 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300843 }
844
845 return ret;
846}
847
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200848
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200849static int __cmd_report(void)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300850{
851 unsigned long offset = 0;
852 unsigned long head = 0;
853 struct stat stat;
854 char *buf;
855 event_t *event;
856 int ret, rc = EXIT_FAILURE;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200857 uint32_t size;
Ingo Molnarf49515b2009-05-26 19:03:36 +0200858 unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300859
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300860 input = open(input_name, O_RDONLY);
861 if (input < 0) {
862 perror("failed to open file");
863 exit(-1);
864 }
865
866 ret = fstat(input, &stat);
867 if (ret < 0) {
868 perror("failed to stat file");
869 exit(-1);
870 }
871
872 if (!stat.st_size) {
873 fprintf(stderr, "zero-sized file, nothing to do!\n");
874 exit(0);
875 }
876
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200877 if (load_kernel() < 0) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300878 perror("failed to open kallsyms");
879 return EXIT_FAILURE;
880 }
881
882remap:
883 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
884 MAP_SHARED, input, offset);
885 if (buf == MAP_FAILED) {
886 perror("failed to mmap file");
887 exit(-1);
888 }
889
890more:
891 event = (event_t *)(buf + head);
892
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200893 size = event->header.size;
894 if (!size)
895 size = 8;
896
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300897 if (head + event->header.size >= page_size * mmap_window) {
898 unsigned long shift = page_size * (head / page_size);
899 int ret;
900
901 ret = munmap(buf, page_size * mmap_window);
902 assert(ret == 0);
903
904 offset += shift;
905 head -= shift;
906 goto remap;
907 }
908
Peter Zijlstra6142f9e2009-05-26 20:51:47 +0200909 size = event->header.size;
910 if (!size)
911 goto broken_event;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300912
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300913 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
914 char level;
915 int show = 0;
916 struct dso *dso = NULL;
917 struct thread *thread = threads__findnew(event->ip.pid);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200918 uint64_t ip = event->ip.ip;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200919 struct map *map = NULL;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300920
Ingo Molnar97b07b62009-05-26 18:48:58 +0200921 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200922 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
923 (void *)(offset + head),
924 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200925 event->header.misc,
926 event->ip.pid,
Ingo Molnar16f762a2009-05-27 09:10:38 +0200927 (void *)(long)ip);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200928 }
929
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300930 if (thread == NULL) {
931 fprintf(stderr, "problem processing %d event, bailing out\n",
932 event->header.type);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300933 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300934 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300935
936 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
937 show = SHOW_KERNEL;
938 level = 'k';
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200939
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300940 dso = kernel_dso;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200941
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300942 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
Ingo Molnar16f762a2009-05-27 09:10:38 +0200943
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300944 show = SHOW_USER;
945 level = '.';
Ingo Molnar16f762a2009-05-27 09:10:38 +0200946
947 map = thread__find_map(thread, ip);
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200948 if (map != NULL) {
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300949 dso = map->dso;
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200950 ip -= map->start + map->pgoff;
951 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200952
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300953 } else {
954 show = SHOW_HV;
955 level = 'H';
956 }
957
958 if (show & show_mask) {
Peter Zijlstraf17e04a2009-05-26 15:30:22 +0200959 struct symbol *sym = dso__find_symbol(dso, ip);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300960
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200961 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
962 fprintf(stderr,
963 "problem incrementing symbol count, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300964 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300965 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300966 }
967 total++;
968 } else switch (event->header.type) {
969 case PERF_EVENT_MMAP: {
970 struct thread *thread = threads__findnew(event->mmap.pid);
971 struct map *map = map__new(&event->mmap);
972
Ingo Molnar97b07b62009-05-26 18:48:58 +0200973 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200974 fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
975 (void *)(offset + head),
976 (void *)(long)(event->header.size),
Ingo Molnar16f762a2009-05-27 09:10:38 +0200977 (void *)(long)event->mmap.start,
978 (void *)(long)event->mmap.len,
979 (void *)(long)event->mmap.pgoff,
Ingo Molnar97b07b62009-05-26 18:48:58 +0200980 event->mmap.filename);
981 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300982 if (thread == NULL || map == NULL) {
983 fprintf(stderr, "problem processing PERF_EVENT_MMAP, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300984 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300985 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300986 thread__insert_map(thread, map);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200987 total_mmap++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300988 break;
989 }
990 case PERF_EVENT_COMM: {
991 struct thread *thread = threads__findnew(event->comm.pid);
992
Ingo Molnar97b07b62009-05-26 18:48:58 +0200993 if (dump_trace) {
Ingo Molnarf49515b2009-05-26 19:03:36 +0200994 fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
995 (void *)(offset + head),
996 (void *)(long)(event->header.size),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200997 event->comm.comm, event->comm.pid);
998 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300999 if (thread == NULL ||
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001000 thread__set_comm(thread, event->comm.comm)) {
1001 fprintf(stderr, "problem processing PERF_EVENT_COMM, bailing out\n");
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001002 goto done;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -03001003 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001004 total_comm++;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001005 break;
1006 }
Ingo Molnar97b07b62009-05-26 18:48:58 +02001007 default: {
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001008broken_event:
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001009 if (dump_trace)
1010 fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
1011 (void *)(offset + head),
1012 (void *)(long)(event->header.size),
1013 event->header.type);
1014
Ingo Molnar3e706112009-05-26 18:53:17 +02001015 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001016
1017 /*
1018 * assume we lost track of the stream, check alignment, and
1019 * increment a single u64 in the hope to catch on again 'soon'.
1020 */
1021
1022 if (unlikely(head & 7))
1023 head &= ~7ULL;
1024
1025 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001026 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001027 }
1028
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001029 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001030
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001031 if (offset + head < stat.st_size)
1032 goto more;
1033
1034 rc = EXIT_SUCCESS;
1035done:
1036 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001037
1038 if (dump_trace) {
Ingo Molnar3e706112009-05-26 18:53:17 +02001039 fprintf(stderr, " IP events: %10ld\n", total);
1040 fprintf(stderr, " mmap events: %10ld\n", total_mmap);
1041 fprintf(stderr, " comm events: %10ld\n", total_comm);
1042 fprintf(stderr, " unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001043
1044 return 0;
1045 }
1046
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001047 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02001048 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02001049
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001050 output__resort();
1051 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001052
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001053 return rc;
1054}
1055
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001056static const char * const report_usage[] = {
1057 "perf report [<options>] <command>",
1058 NULL
1059};
1060
1061static const struct option options[] = {
1062 OPT_STRING('i', "input", &input_name, "file",
1063 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001064 OPT_BOOLEAN('v', "verbose", &verbose,
1065 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001066 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1067 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001068 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001069 OPT_END()
1070};
1071
1072int cmd_report(int argc, const char **argv, const char *prefix)
1073{
1074 elf_version(EV_CURRENT);
1075
1076 page_size = getpagesize();
1077
1078 parse_options(argc, argv, options, report_usage, 0);
1079
Ingo Molnara930d2c2009-05-27 09:50:13 +02001080 setup_pager();
1081
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001082 return __cmd_report();
1083}