aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/build-id.c28
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/config.c64
-rw-r--r--tools/perf/util/cpumap.c57
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/debug.c10
-rw-r--r--tools/perf/util/event.c107
-rw-r--r--tools/perf/util/event.h6
-rw-r--r--tools/perf/util/header.c13
-rw-r--r--tools/perf/util/hist.c214
-rw-r--r--tools/perf/util/hist.h30
-rw-r--r--tools/perf/util/map.c116
-rw-r--r--tools/perf/util/map.h14
-rw-r--r--tools/perf/util/newt.c1164
-rw-r--r--tools/perf/util/parse-events.c11
-rw-r--r--tools/perf/util/probe-event.c271
-rw-r--r--tools/perf/util/probe-event.h29
-rw-r--r--tools/perf/util/probe-finder.c248
-rw-r--r--tools/perf/util/probe-finder.h10
-rw-r--r--tools/perf/util/session.c62
-rw-r--r--tools/perf/util/sort.c40
-rw-r--r--tools/perf/util/sort.h22
-rw-r--r--tools/perf/util/symbol.c299
-rw-r--r--tools/perf/util/symbol.h18
-rw-r--r--tools/perf/util/thread.c7
-rw-r--r--tools/perf/util/thread.h2
-rw-r--r--tools/perf/util/util.h3
29 files changed, 2001 insertions, 851 deletions
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 70c5cf87d020..e437edb72417 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -12,6 +12,7 @@
12#include "event.h" 12#include "event.h"
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h"
15 16
16static int build_id__mark_dso_hit(event_t *event, struct perf_session *session) 17static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
17{ 18{
@@ -34,28 +35,43 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
34 return 0; 35 return 0;
35} 36}
36 37
38static int event__exit_del_thread(event_t *self, struct perf_session *session)
39{
40 struct thread *thread = perf_session__findnew(session, self->fork.tid);
41
42 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
43 self->fork.ppid, self->fork.ptid);
44
45 if (thread) {
46 rb_erase(&thread->rb_node, &session->threads);
47 session->last_match = NULL;
48 thread__delete(thread);
49 }
50
51 return 0;
52}
53
37struct perf_event_ops build_id__mark_dso_hit_ops = { 54struct perf_event_ops build_id__mark_dso_hit_ops = {
38 .sample = build_id__mark_dso_hit, 55 .sample = build_id__mark_dso_hit,
39 .mmap = event__process_mmap, 56 .mmap = event__process_mmap,
40 .fork = event__process_task, 57 .fork = event__process_task,
58 .exit = event__exit_del_thread,
41}; 59};
42 60
43char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 61char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
44{ 62{
45 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 63 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
46 const char *home;
47 64
48 if (!self->has_build_id) 65 if (!self->has_build_id)
49 return NULL; 66 return NULL;
50 67
51 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); 68 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
52 home = getenv("HOME");
53 if (bf == NULL) { 69 if (bf == NULL) {
54 if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home, 70 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
55 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0) 71 build_id_hex, build_id_hex + 2) < 0)
56 return NULL; 72 return NULL;
57 } else 73 } else
58 snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home, 74 snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
59 DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2); 75 build_id_hex, build_id_hex + 2);
60 return bf; 76 return bf;
61} 77}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 65fe664fddf6..27e9ebe4076e 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *);
23extern int perf_config_int(const char *, const char *); 23extern int perf_config_int(const char *, const char *);
24extern int perf_config_bool(const char *, const char *); 24extern int perf_config_bool(const char *, const char *);
25extern int config_error_nonbool(const char *); 25extern int config_error_nonbool(const char *);
26extern const char *perf_config_dirname(const char *, const char *);
26 27
27/* pager.c */ 28/* pager.c */
28extern void setup_pager(void); 29extern void setup_pager(void);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 52c777e451ed..f231f43424d2 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,7 +18,7 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21bool ip_callchain__valid(struct ip_callchain *chain, event_t *event) 21bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
22{ 22{
23 unsigned int chain_size = event->header.size; 23 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index f2e9ee164bd8..624a96c636fd 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -63,5 +63,5 @@ int register_callchain_param(struct callchain_param *param);
63int append_chain(struct callchain_node *root, struct ip_callchain *chain, 63int append_chain(struct callchain_node *root, struct ip_callchain *chain,
64 struct map_symbol *syms, u64 period); 64 struct map_symbol *syms, u64 period);
65 65
66bool ip_callchain__valid(struct ip_callchain *chain, event_t *event); 66bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
67#endif /* __PERF_CALLCHAIN_H */ 67#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index dabe892d0e53..e02d78cae70f 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,11 @@
11 11
12#define MAXNAME (256) 12#define MAXNAME (256)
13 13
14#define DEBUG_CACHE_DIR ".debug"
15
16
17char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
18
14static FILE *config_file; 19static FILE *config_file;
15static const char *config_file_name; 20static const char *config_file_name;
16static int config_linenr; 21static int config_linenr;
@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
127 break; 132 break;
128 if (!iskeychar(c)) 133 if (!iskeychar(c))
129 break; 134 break;
130 name[len++] = tolower(c); 135 name[len++] = c;
131 if (len >= MAXNAME) 136 if (len >= MAXNAME)
132 return -1; 137 return -1;
133 } 138 }
@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value)
327 return !!perf_config_bool_or_int(name, value, &discard); 332 return !!perf_config_bool_or_int(name, value, &discard);
328} 333}
329 334
335const char *perf_config_dirname(const char *name, const char *value)
336{
337 if (!name)
338 return NULL;
339 return value;
340}
341
330static int perf_default_core_config(const char *var __used, const char *value __used) 342static int perf_default_core_config(const char *var __used, const char *value __used)
331{ 343{
332 /* Add other config variables here and to Documentation/config.txt. */ 344 /* Add other config variables here and to Documentation/config.txt. */
@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var)
428{ 440{
429 return error("Missing value for '%s'", var); 441 return error("Missing value for '%s'", var);
430} 442}
443
444struct buildid_dir_config {
445 char *dir;
446};
447
448static int buildid_dir_command_config(const char *var, const char *value,
449 void *data)
450{
451 struct buildid_dir_config *c = data;
452 const char *v;
453
454 /* same dir for all commands */
455 if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
456 v = perf_config_dirname(var, value);
457 if (!v)
458 return -1;
459 strncpy(c->dir, v, MAXPATHLEN-1);
460 c->dir[MAXPATHLEN-1] = '\0';
461 }
462 return 0;
463}
464
465static void check_buildid_dir_config(void)
466{
467 struct buildid_dir_config c;
468 c.dir = buildid_dir;
469 perf_config(buildid_dir_command_config, &c);
470}
471
472void set_buildid_dir(void)
473{
474 buildid_dir[0] = '\0';
475
476 /* try config file */
477 check_buildid_dir_config();
478
479 /* default to $HOME/.debug */
480 if (buildid_dir[0] == '\0') {
481 char *v = getenv("HOME");
482 if (v) {
483 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
484 v, DEBUG_CACHE_DIR);
485 } else {
486 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
487 }
488 buildid_dir[MAXPATHLEN-1] = '\0';
489 }
490 /* for communicating with external commands */
491 setenv("PERF_BUILDID_DIR", buildid_dir, 1);
492}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 4e01490e51e5..0f9b8d7a7d7e 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -20,7 +20,7 @@ static int default_cpu_map(void)
20 return nr_cpus; 20 return nr_cpus;
21} 21}
22 22
23int read_cpu_map(void) 23static int read_all_cpu_map(void)
24{ 24{
25 FILE *onlnf; 25 FILE *onlnf;
26 int nr_cpus = 0; 26 int nr_cpus = 0;
@@ -57,3 +57,58 @@ int read_cpu_map(void)
57 57
58 return default_cpu_map(); 58 return default_cpu_map();
59} 59}
60
61int read_cpu_map(const char *cpu_list)
62{
63 unsigned long start_cpu, end_cpu = 0;
64 char *p = NULL;
65 int i, nr_cpus = 0;
66
67 if (!cpu_list)
68 return read_all_cpu_map();
69
70 if (!isdigit(*cpu_list))
71 goto invalid;
72
73 while (isdigit(*cpu_list)) {
74 p = NULL;
75 start_cpu = strtoul(cpu_list, &p, 0);
76 if (start_cpu >= INT_MAX
77 || (*p != '\0' && *p != ',' && *p != '-'))
78 goto invalid;
79
80 if (*p == '-') {
81 cpu_list = ++p;
82 p = NULL;
83 end_cpu = strtoul(cpu_list, &p, 0);
84
85 if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
86 goto invalid;
87
88 if (end_cpu < start_cpu)
89 goto invalid;
90 } else {
91 end_cpu = start_cpu;
92 }
93
94 for (; start_cpu <= end_cpu; start_cpu++) {
95 /* check for duplicates */
96 for (i = 0; i < nr_cpus; i++)
97 if (cpumap[i] == (int)start_cpu)
98 goto invalid;
99
100 assert(nr_cpus < MAX_NR_CPUS);
101 cpumap[nr_cpus++] = (int)start_cpu;
102 }
103 if (*p)
104 ++p;
105
106 cpu_list = p;
107 }
108 if (nr_cpus > 0)
109 return nr_cpus;
110
111 return default_cpu_map();
112invalid:
113 return -1;
114}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 86c78bb33098..3e60f56e490e 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4extern int read_cpu_map(void); 4extern int read_cpu_map(const char *cpu_list);
5extern int cpumap[]; 5extern int cpumap[];
6 6
7#endif /* __PERF_CPUMAP_H */ 7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 6cddff2bc970..318dab15d177 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -86,12 +86,10 @@ void trace_event(event_t *event)
86 dump_printf_color(" ", color); 86 dump_printf_color(" ", color);
87 for (j = 0; j < 15-(i & 15); j++) 87 for (j = 0; j < 15-(i & 15); j++)
88 dump_printf_color(" ", color); 88 dump_printf_color(" ", color);
89 for (j = 0; j < (i & 15); j++) { 89 for (j = i & ~15; j <= i; j++) {
90 if (isprint(raw_event[i-15+j])) 90 dump_printf_color("%c", color,
91 dump_printf_color("%c", color, 91 isprint(raw_event[j]) ?
92 raw_event[i-15+j]); 92 raw_event[j] : '.');
93 else
94 dump_printf_color(".", color);
95 } 93 }
96 dump_printf_color("\n", color); 94 dump_printf_color("\n", color);
97 } 95 }
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2fbf6a463c81..dab9e754a281 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -151,7 +151,6 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
151 continue; 151 continue;
152 pbf += n + 3; 152 pbf += n + 3;
153 if (*pbf == 'x') { /* vm_exec */ 153 if (*pbf == 'x') { /* vm_exec */
154 u64 vm_pgoff;
155 char *execname = strchr(bf, '/'); 154 char *execname = strchr(bf, '/');
156 155
157 /* Catch VDSO */ 156 /* Catch VDSO */
@@ -162,12 +161,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
162 continue; 161 continue;
163 162
164 pbf += 3; 163 pbf += 3;
165 n = hex2u64(pbf, &vm_pgoff); 164 n = hex2u64(pbf, &ev.mmap.pgoff);
166 /* pgoff is in bytes, not pages */
167 if (n >= 0)
168 ev.mmap.pgoff = vm_pgoff << getpagesize();
169 else
170 ev.mmap.pgoff = 0;
171 165
172 size = strlen(execname); 166 size = strlen(execname);
173 execname[size - 1] = '\0'; /* Remove \n */ 167 execname[size - 1] = '\0'; /* Remove \n */
@@ -340,30 +334,29 @@ int event__synthesize_kernel_mmap(event__handler_t process,
340 return process(&ev, session); 334 return process(&ev, session);
341} 335}
342 336
343static void thread__comm_adjust(struct thread *self) 337static void thread__comm_adjust(struct thread *self, struct hists *hists)
344{ 338{
345 char *comm = self->comm; 339 char *comm = self->comm;
346 340
347 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 341 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
348 (!symbol_conf.comm_list || 342 (!symbol_conf.comm_list ||
349 strlist__has_entry(symbol_conf.comm_list, comm))) { 343 strlist__has_entry(symbol_conf.comm_list, comm))) {
350 unsigned int slen = strlen(comm); 344 u16 slen = strlen(comm);
351 345
352 if (slen > comms__col_width) { 346 if (hists__new_col_len(hists, HISTC_COMM, slen))
353 comms__col_width = slen; 347 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
354 threads__col_width = slen + 6;
355 }
356 } 348 }
357} 349}
358 350
359static int thread__set_comm_adjust(struct thread *self, const char *comm) 351static int thread__set_comm_adjust(struct thread *self, const char *comm,
352 struct hists *hists)
360{ 353{
361 int ret = thread__set_comm(self, comm); 354 int ret = thread__set_comm(self, comm);
362 355
363 if (ret) 356 if (ret)
364 return ret; 357 return ret;
365 358
366 thread__comm_adjust(self); 359 thread__comm_adjust(self, hists);
367 360
368 return 0; 361 return 0;
369} 362}
@@ -374,7 +367,8 @@ int event__process_comm(event_t *self, struct perf_session *session)
374 367
375 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); 368 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
376 369
377 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 370 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
371 &session->hists)) {
378 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 372 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
379 return -1; 373 return -1;
380 } 374 }
@@ -456,6 +450,7 @@ static int event__process_kernel_mmap(event_t *self,
456 goto out_problem; 450 goto out_problem;
457 451
458 map->dso->short_name = name; 452 map->dso->short_name = name;
453 map->dso->sname_alloc = 1;
459 map->end = map->start + self->mmap.len; 454 map->end = map->start + self->mmap.len;
460 } else if (is_kernel_mmap) { 455 } else if (is_kernel_mmap) {
461 const char *symbol_name = (self->mmap.filename + 456 const char *symbol_name = (self->mmap.filename +
@@ -514,12 +509,13 @@ int event__process_mmap(event_t *self, struct perf_session *session)
514 if (machine == NULL) 509 if (machine == NULL)
515 goto out_problem; 510 goto out_problem;
516 thread = perf_session__findnew(session, self->mmap.pid); 511 thread = perf_session__findnew(session, self->mmap.pid);
512 if (thread == NULL)
513 goto out_problem;
517 map = map__new(&machine->user_dsos, self->mmap.start, 514 map = map__new(&machine->user_dsos, self->mmap.start,
518 self->mmap.len, self->mmap.pgoff, 515 self->mmap.len, self->mmap.pgoff,
519 self->mmap.pid, self->mmap.filename, 516 self->mmap.pid, self->mmap.filename,
520 MAP__FUNCTION, session->cwd, session->cwdlen); 517 MAP__FUNCTION);
521 518 if (map == NULL)
522 if (thread == NULL || map == NULL)
523 goto out_problem; 519 goto out_problem;
524 520
525 thread__insert_map(thread, map); 521 thread__insert_map(thread, map);
@@ -552,6 +548,26 @@ int event__process_task(event_t *self, struct perf_session *session)
552 return 0; 548 return 0;
553} 549}
554 550
551int event__process(event_t *event, struct perf_session *session)
552{
553 switch (event->header.type) {
554 case PERF_RECORD_COMM:
555 event__process_comm(event, session);
556 break;
557 case PERF_RECORD_MMAP:
558 event__process_mmap(event, session);
559 break;
560 case PERF_RECORD_FORK:
561 case PERF_RECORD_EXIT:
562 event__process_task(event, session);
563 break;
564 default:
565 break;
566 }
567
568 return 0;
569}
570
555void thread__find_addr_map(struct thread *self, 571void thread__find_addr_map(struct thread *self,
556 struct perf_session *session, u8 cpumode, 572 struct perf_session *session, u8 cpumode,
557 enum map_type type, pid_t pid, u64 addr, 573 enum map_type type, pid_t pid, u64 addr,
@@ -641,27 +657,49 @@ void thread__find_addr_location(struct thread *self,
641 al->sym = NULL; 657 al->sym = NULL;
642} 658}
643 659
644static void dso__calc_col_width(struct dso *self) 660static void dso__calc_col_width(struct dso *self, struct hists *hists)
645{ 661{
646 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 662 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
647 (!symbol_conf.dso_list || 663 (!symbol_conf.dso_list ||
648 strlist__has_entry(symbol_conf.dso_list, self->name))) { 664 strlist__has_entry(symbol_conf.dso_list, self->name))) {
649 u16 slen = self->short_name_len; 665 u16 slen = dso__name_len(self);
650 if (verbose) 666 hists__new_col_len(hists, HISTC_DSO, slen);
651 slen = self->long_name_len;
652 if (dsos__col_width < slen)
653 dsos__col_width = slen;
654 } 667 }
655 668
656 self->slen_calculated = 1; 669 self->slen_calculated = 1;
657} 670}
658 671
659int event__preprocess_sample(const event_t *self, struct perf_session *session, 672int event__preprocess_sample(const event_t *self, struct perf_session *session,
660 struct addr_location *al, symbol_filter_t filter) 673 struct addr_location *al, struct sample_data *data,
674 symbol_filter_t filter)
661{ 675{
662 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 676 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
663 struct thread *thread = perf_session__findnew(session, self->ip.pid); 677 struct thread *thread;
664 678
679 event__parse_sample(self, session->sample_type, data);
680
681 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
682 self->header.misc, data->pid, data->tid, data->ip,
683 data->period, data->cpu);
684
685 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
686 unsigned int i;
687
688 dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
689
690 if (!ip_callchain__valid(data->callchain, self)) {
691 pr_debug("call-chain problem with event, "
692 "skipping it.\n");
693 goto out_filtered;
694 }
695
696 if (dump_trace) {
697 for (i = 0; i < data->callchain->nr; i++)
698 dump_printf("..... %2d: %016Lx\n",
699 i, data->callchain->ips[i]);
700 }
701 }
702 thread = perf_session__findnew(session, self->ip.pid);
665 if (thread == NULL) 703 if (thread == NULL)
666 return -1; 704 return -1;
667 705
@@ -687,6 +725,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
687 al->map ? al->map->dso->long_name : 725 al->map ? al->map->dso->long_name :
688 al->level == 'H' ? "[hypervisor]" : "<not found>"); 726 al->level == 'H' ? "[hypervisor]" : "<not found>");
689 al->sym = NULL; 727 al->sym = NULL;
728 al->cpu = data->cpu;
690 729
691 if (al->map) { 730 if (al->map) {
692 if (symbol_conf.dso_list && 731 if (symbol_conf.dso_list &&
@@ -703,16 +742,17 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
703 * sampled. 742 * sampled.
704 */ 743 */
705 if (!sort_dso.elide && !al->map->dso->slen_calculated) 744 if (!sort_dso.elide && !al->map->dso->slen_calculated)
706 dso__calc_col_width(al->map->dso); 745 dso__calc_col_width(al->map->dso, &session->hists);
707 746
708 al->sym = map__find_symbol(al->map, al->addr, filter); 747 al->sym = map__find_symbol(al->map, al->addr, filter);
709 } else { 748 } else {
710 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 749 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
711 750
712 if (dsos__col_width < unresolved_col_width && 751 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
713 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 752 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
714 !symbol_conf.dso_list) 753 !symbol_conf.dso_list)
715 dsos__col_width = unresolved_col_width; 754 hists__set_col_len(&session->hists, HISTC_DSO,
755 unresolved_col_width);
716 } 756 }
717 757
718 if (symbol_conf.sym_list && al->sym && 758 if (symbol_conf.sym_list && al->sym &&
@@ -726,9 +766,9 @@ out_filtered:
726 return 0; 766 return 0;
727} 767}
728 768
729int event__parse_sample(event_t *event, u64 type, struct sample_data *data) 769int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
730{ 770{
731 u64 *array = event->sample.array; 771 const u64 *array = event->sample.array;
732 772
733 if (type & PERF_SAMPLE_IP) { 773 if (type & PERF_SAMPLE_IP) {
734 data->ip = event->ip.ip; 774 data->ip = event->ip.ip;
@@ -767,7 +807,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
767 u32 *p = (u32 *)array; 807 u32 *p = (u32 *)array;
768 data->cpu = *p; 808 data->cpu = *p;
769 array++; 809 array++;
770 } 810 } else
811 data->cpu = -1;
771 812
772 if (type & PERF_SAMPLE_PERIOD) { 813 if (type & PERF_SAMPLE_PERIOD) {
773 data->period = *array; 814 data->period = *array;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8577085db067..8e790dae7026 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -154,11 +154,13 @@ int event__process_comm(event_t *self, struct perf_session *session);
154int event__process_lost(event_t *self, struct perf_session *session); 154int event__process_lost(event_t *self, struct perf_session *session);
155int event__process_mmap(event_t *self, struct perf_session *session); 155int event__process_mmap(event_t *self, struct perf_session *session);
156int event__process_task(event_t *self, struct perf_session *session); 156int event__process_task(event_t *self, struct perf_session *session);
157int event__process(event_t *event, struct perf_session *session);
157 158
158struct addr_location; 159struct addr_location;
159int event__preprocess_sample(const event_t *self, struct perf_session *session, 160int event__preprocess_sample(const event_t *self, struct perf_session *session,
160 struct addr_location *al, symbol_filter_t filter); 161 struct addr_location *al, struct sample_data *data,
161int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 162 symbol_filter_t filter);
163int event__parse_sample(const event_t *event, u64 type, struct sample_data *data);
162 164
163extern const char *event__name[]; 165extern const char *event__name[];
164 166
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1f62435f96c2..d7e67b167ea3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -16,6 +16,8 @@
16#include "symbol.h" 16#include "symbol.h"
17#include "debug.h" 17#include "debug.h"
18 18
19static bool no_buildid_cache = false;
20
19/* 21/*
20 * Create new perf.data header attribute: 22 * Create new perf.data header attribute:
21 */ 23 */
@@ -385,8 +387,7 @@ static int perf_session__cache_build_ids(struct perf_session *self)
385 int ret; 387 int ret;
386 char debugdir[PATH_MAX]; 388 char debugdir[PATH_MAX];
387 389
388 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), 390 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
389 DEBUG_CACHE_DIR);
390 391
391 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 392 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
392 return -1; 393 return -1;
@@ -471,7 +472,8 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
471 } 472 }
472 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - 473 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
473 buildid_sec->offset; 474 buildid_sec->offset;
474 perf_session__cache_build_ids(session); 475 if (!no_buildid_cache)
476 perf_session__cache_build_ids(session);
475 } 477 }
476 478
477 lseek(fd, sec_start, SEEK_SET); 479 lseek(fd, sec_start, SEEK_SET);
@@ -1190,3 +1192,8 @@ int event__process_build_id(event_t *self,
1190 session); 1192 session);
1191 return 0; 1193 return 0;
1192} 1194}
1195
1196void disable_buildid_cache(void)
1197{
1198 no_buildid_cache = true;
1199}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 784ee0bdda77..e7263d49bcf0 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -5,11 +5,61 @@
5#include "sort.h" 5#include "sort.h"
6#include <math.h> 6#include <math.h>
7 7
8enum hist_filter {
9 HIST_FILTER__DSO,
10 HIST_FILTER__THREAD,
11 HIST_FILTER__PARENT,
12};
13
8struct callchain_param callchain_param = { 14struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 15 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5 16 .min_percent = 0.5
11}; 17};
12 18
19u16 hists__col_len(struct hists *self, enum hist_column col)
20{
21 return self->col_len[col];
22}
23
24void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
25{
26 self->col_len[col] = len;
27}
28
29bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
30{
31 if (len > hists__col_len(self, col)) {
32 hists__set_col_len(self, col, len);
33 return true;
34 }
35 return false;
36}
37
38static void hists__reset_col_len(struct hists *self)
39{
40 enum hist_column col;
41
42 for (col = 0; col < HISTC_NR_COLS; ++col)
43 hists__set_col_len(self, col, 0);
44}
45
46static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
47{
48 u16 len;
49
50 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
52
53 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len))
55 hists__set_col_len(self, HISTC_THREAD, len + 6);
56
57 if (h->ms.map) {
58 len = dso__name_len(h->ms.map->dso);
59 hists__new_col_len(self, HISTC_DSO, len);
60 }
61}
62
13static void hist_entry__add_cpumode_period(struct hist_entry *self, 63static void hist_entry__add_cpumode_period(struct hist_entry *self,
14 unsigned int cpumode, u64 period) 64 unsigned int cpumode, u64 period)
15{ 65{
@@ -43,6 +93,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
43 if (self != NULL) { 93 if (self != NULL) {
44 *self = *template; 94 *self = *template;
45 self->nr_events = 1; 95 self->nr_events = 1;
96 if (self->ms.map)
97 self->ms.map->referenced = true;
46 if (symbol_conf.use_callchain) 98 if (symbol_conf.use_callchain)
47 callchain_init(self->callchain); 99 callchain_init(self->callchain);
48 } 100 }
@@ -50,11 +102,19 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
50 return self; 102 return self;
51} 103}
52 104
53static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry) 105static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
54{ 106{
55 if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen) 107 if (!h->filtered) {
56 self->max_sym_namelen = entry->ms.sym->namelen; 108 hists__calc_col_len(self, h);
57 ++self->nr_entries; 109 ++self->nr_entries;
110 }
111}
112
113static u8 symbol__parent_filter(const struct symbol *parent)
114{
115 if (symbol_conf.exclude_other && parent == NULL)
116 return 1 << HIST_FILTER__PARENT;
117 return 0;
58} 118}
59 119
60struct hist_entry *__hists__add_entry(struct hists *self, 120struct hist_entry *__hists__add_entry(struct hists *self,
@@ -70,10 +130,12 @@ struct hist_entry *__hists__add_entry(struct hists *self,
70 .map = al->map, 130 .map = al->map,
71 .sym = al->sym, 131 .sym = al->sym,
72 }, 132 },
133 .cpu = al->cpu,
73 .ip = al->addr, 134 .ip = al->addr,
74 .level = al->level, 135 .level = al->level,
75 .period = period, 136 .period = period,
76 .parent = sym_parent, 137 .parent = sym_parent,
138 .filtered = symbol__parent_filter(sym_parent),
77 }; 139 };
78 int cmp; 140 int cmp;
79 141
@@ -191,7 +253,7 @@ void hists__collapse_resort(struct hists *self)
191 tmp = RB_ROOT; 253 tmp = RB_ROOT;
192 next = rb_first(&self->entries); 254 next = rb_first(&self->entries);
193 self->nr_entries = 0; 255 self->nr_entries = 0;
194 self->max_sym_namelen = 0; 256 hists__reset_col_len(self);
195 257
196 while (next) { 258 while (next) {
197 n = rb_entry(next, struct hist_entry, rb_node); 259 n = rb_entry(next, struct hist_entry, rb_node);
@@ -248,7 +310,7 @@ void hists__output_resort(struct hists *self)
248 next = rb_first(&self->entries); 310 next = rb_first(&self->entries);
249 311
250 self->nr_entries = 0; 312 self->nr_entries = 0;
251 self->max_sym_namelen = 0; 313 hists__reset_col_len(self);
252 314
253 while (next) { 315 while (next) {
254 n = rb_entry(next, struct hist_entry, rb_node); 316 n = rb_entry(next, struct hist_entry, rb_node);
@@ -515,8 +577,9 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
515} 577}
516 578
517int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 579int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
518 struct hists *pair_hists, bool show_displacement, 580 struct hists *hists, struct hists *pair_hists,
519 long displacement, bool color, u64 session_total) 581 bool show_displacement, long displacement,
582 bool color, u64 session_total)
520{ 583{
521 struct sort_entry *se; 584 struct sort_entry *se;
522 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 585 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
@@ -620,29 +683,25 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
620 683
621 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 684 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
622 ret += se->se_snprintf(self, s + ret, size - ret, 685 ret += se->se_snprintf(self, s + ret, size - ret,
623 se->se_width ? *se->se_width : 0); 686 hists__col_len(hists, se->se_width_idx));
624 } 687 }
625 688
626 return ret; 689 return ret;
627} 690}
628 691
629int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, 692int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
630 bool show_displacement, long displacement, FILE *fp, 693 struct hists *pair_hists, bool show_displacement,
631 u64 session_total) 694 long displacement, FILE *fp, u64 session_total)
632{ 695{
633 char bf[512]; 696 char bf[512];
634 int ret; 697 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
635 698 show_displacement, displacement,
636 ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists, 699 true, session_total);
637 show_displacement, displacement,
638 true, session_total);
639 if (!ret)
640 return 0;
641
642 return fprintf(fp, "%s\n", bf); 700 return fprintf(fp, "%s\n", bf);
643} 701}
644 702
645static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, 703static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
704 struct hists *hists, FILE *fp,
646 u64 session_total) 705 u64 session_total)
647{ 706{
648 int left_margin = 0; 707 int left_margin = 0;
@@ -650,7 +709,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
650 if (sort__first_dimension == SORT_COMM) { 709 if (sort__first_dimension == SORT_COMM) {
651 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 710 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
652 typeof(*se), list); 711 typeof(*se), list);
653 left_margin = se->se_width ? *se->se_width : 0; 712 left_margin = hists__col_len(hists, se->se_width_idx);
654 left_margin -= thread__comm_len(self->thread); 713 left_margin -= thread__comm_len(self->thread);
655 } 714 }
656 715
@@ -721,17 +780,17 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
721 continue; 780 continue;
722 } 781 }
723 width = strlen(se->se_header); 782 width = strlen(se->se_header);
724 if (se->se_width) { 783 if (symbol_conf.col_width_list_str) {
725 if (symbol_conf.col_width_list_str) { 784 if (col_width) {
726 if (col_width) { 785 hists__set_col_len(self, se->se_width_idx,
727 *se->se_width = atoi(col_width); 786 atoi(col_width));
728 col_width = strchr(col_width, ','); 787 col_width = strchr(col_width, ',');
729 if (col_width) 788 if (col_width)
730 ++col_width; 789 ++col_width;
731 }
732 } 790 }
733 width = *se->se_width = max(*se->se_width, width);
734 } 791 }
792 if (!hists__new_col_len(self, se->se_width_idx, width))
793 width = hists__col_len(self, se->se_width_idx);
735 fprintf(fp, " %*s", width, se->se_header); 794 fprintf(fp, " %*s", width, se->se_header);
736 } 795 }
737 fprintf(fp, "\n"); 796 fprintf(fp, "\n");
@@ -754,9 +813,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
754 continue; 813 continue;
755 814
756 fprintf(fp, " "); 815 fprintf(fp, " ");
757 if (se->se_width) 816 width = hists__col_len(self, se->se_width_idx);
758 width = *se->se_width; 817 if (width == 0)
759 else
760 width = strlen(se->se_header); 818 width = strlen(se->se_header);
761 for (i = 0; i < width; i++) 819 for (i = 0; i < width; i++)
762 fprintf(fp, "."); 820 fprintf(fp, ".");
@@ -767,7 +825,6 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
767print_entries: 825print_entries:
768 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 826 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
769 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 827 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
770 int cnt;
771 828
772 if (show_displacement) { 829 if (show_displacement) {
773 if (h->pair != NULL) 830 if (h->pair != NULL)
@@ -777,17 +834,12 @@ print_entries:
777 displacement = 0; 834 displacement = 0;
778 ++position; 835 ++position;
779 } 836 }
780 cnt = hist_entry__fprintf(h, pair, show_displacement, 837 ret += hist_entry__fprintf(h, self, pair, show_displacement,
781 displacement, fp, self->stats.total_period); 838 displacement, fp, self->stats.total_period);
782 /* Ignore those that didn't match the parent filter */
783 if (!cnt)
784 continue;
785
786 ret += cnt;
787 839
788 if (symbol_conf.use_callchain) 840 if (symbol_conf.use_callchain)
789 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); 841 ret += hist_entry__fprintf_callchain(h, self, fp,
790 842 self->stats.total_period);
791 if (h->ms.map == NULL && verbose > 1) { 843 if (h->ms.map == NULL && verbose > 1) {
792 __map_groups__fprintf_maps(&h->thread->mg, 844 __map_groups__fprintf_maps(&h->thread->mg,
793 MAP__FUNCTION, verbose, fp); 845 MAP__FUNCTION, verbose, fp);
@@ -800,10 +852,49 @@ print_entries:
800 return ret; 852 return ret;
801} 853}
802 854
803enum hist_filter { 855/*
804 HIST_FILTER__DSO, 856 * See hists__fprintf to match the column widths
805 HIST_FILTER__THREAD, 857 */
806}; 858unsigned int hists__sort_list_width(struct hists *self)
859{
860 struct sort_entry *se;
861 int ret = 9; /* total % */
862
863 if (symbol_conf.show_cpu_utilization) {
864 ret += 7; /* count_sys % */
865 ret += 6; /* count_us % */
866 if (perf_guest) {
867 ret += 13; /* count_guest_sys % */
868 ret += 12; /* count_guest_us % */
869 }
870 }
871
872 if (symbol_conf.show_nr_samples)
873 ret += 11;
874
875 list_for_each_entry(se, &hist_entry__sort_list, list)
876 if (!se->elide)
877 ret += 2 + hists__col_len(self, se->se_width_idx);
878
879 return ret;
880}
881
882static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
883 enum hist_filter filter)
884{
885 h->filtered &= ~(1 << filter);
886 if (h->filtered)
887 return;
888
889 ++self->nr_entries;
890 if (h->ms.unfolded)
891 self->nr_entries += h->nr_rows;
892 h->row_offset = 0;
893 self->stats.total_period += h->period;
894 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
895
896 hists__calc_col_len(self, h);
897}
807 898
808void hists__filter_by_dso(struct hists *self, const struct dso *dso) 899void hists__filter_by_dso(struct hists *self, const struct dso *dso)
809{ 900{
@@ -811,7 +902,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
811 902
812 self->nr_entries = self->stats.total_period = 0; 903 self->nr_entries = self->stats.total_period = 0;
813 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 904 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
814 self->max_sym_namelen = 0; 905 hists__reset_col_len(self);
815 906
816 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 907 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
817 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 908 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -824,15 +915,7 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
824 continue; 915 continue;
825 } 916 }
826 917
827 h->filtered &= ~(1 << HIST_FILTER__DSO); 918 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
828 if (!h->filtered) {
829 ++self->nr_entries;
830 self->stats.total_period += h->period;
831 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
832 if (h->ms.sym &&
833 self->max_sym_namelen < h->ms.sym->namelen)
834 self->max_sym_namelen = h->ms.sym->namelen;
835 }
836 } 919 }
837} 920}
838 921
@@ -842,7 +925,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
842 925
843 self->nr_entries = self->stats.total_period = 0; 926 self->nr_entries = self->stats.total_period = 0;
844 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 927 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
845 self->max_sym_namelen = 0; 928 hists__reset_col_len(self);
846 929
847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { 930 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 931 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -851,15 +934,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
851 h->filtered |= (1 << HIST_FILTER__THREAD); 934 h->filtered |= (1 << HIST_FILTER__THREAD);
852 continue; 935 continue;
853 } 936 }
854 h->filtered &= ~(1 << HIST_FILTER__THREAD); 937
855 if (!h->filtered) { 938 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
856 ++self->nr_entries;
857 self->stats.total_period += h->period;
858 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
859 if (h->ms.sym &&
860 self->max_sym_namelen < h->ms.sym->namelen)
861 self->max_sym_namelen = h->ms.sym->namelen;
862 }
863 } 939 }
864} 940}
865 941
@@ -1052,7 +1128,7 @@ fallback:
1052 dso, dso->long_name, sym, sym->name); 1128 dso, dso->long_name, sym, sym->name);
1053 1129
1054 snprintf(command, sizeof(command), 1130 snprintf(command, sizeof(command),
1055 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand", 1131 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1056 map__rip_2objdump(map, sym->start), 1132 map__rip_2objdump(map, sym->start),
1057 map__rip_2objdump(map, sym->end), 1133 map__rip_2objdump(map, sym->end),
1058 filename, filename); 1134 filename, filename);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 83fa33a7b38b..65a48db46a29 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -56,6 +56,16 @@ struct events_stats {
56 u32 nr_unknown_events; 56 u32 nr_unknown_events;
57}; 57};
58 58
59enum hist_column {
60 HISTC_SYMBOL,
61 HISTC_DSO,
62 HISTC_THREAD,
63 HISTC_COMM,
64 HISTC_PARENT,
65 HISTC_CPU,
66 HISTC_NR_COLS, /* Last entry */
67};
68
59struct hists { 69struct hists {
60 struct rb_node rb_node; 70 struct rb_node rb_node;
61 struct rb_root entries; 71 struct rb_root entries;
@@ -64,7 +74,7 @@ struct hists {
64 u64 config; 74 u64 config;
65 u64 event_stream; 75 u64 event_stream;
66 u32 type; 76 u32 type;
67 u32 max_sym_namelen; 77 u16 col_len[HISTC_NR_COLS];
68}; 78};
69 79
70struct hist_entry *__hists__add_entry(struct hists *self, 80struct hist_entry *__hists__add_entry(struct hists *self,
@@ -72,12 +82,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
72 struct symbol *parent, u64 period); 82 struct symbol *parent, u64 period);
73extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 83extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
74extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 84extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
75int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists, 85int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
76 bool show_displacement, long displacement, FILE *fp, 86 struct hists *pair_hists, bool show_displacement,
77 u64 total); 87 long displacement, FILE *fp, u64 total);
78int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, 88int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
79 struct hists *pair_hists, bool show_displacement, 89 struct hists *hists, struct hists *pair_hists,
80 long displacement, bool color, u64 total); 90 bool show_displacement, long displacement,
91 bool color, u64 total);
81void hist_entry__free(struct hist_entry *); 92void hist_entry__free(struct hist_entry *);
82 93
83void hists__output_resort(struct hists *self); 94void hists__output_resort(struct hists *self);
@@ -95,6 +106,10 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head);
95void hists__filter_by_dso(struct hists *self, const struct dso *dso); 106void hists__filter_by_dso(struct hists *self, const struct dso *dso);
96void hists__filter_by_thread(struct hists *self, const struct thread *thread); 107void hists__filter_by_thread(struct hists *self, const struct thread *thread);
97 108
109u16 hists__col_len(struct hists *self, enum hist_column col);
110void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
111bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
112
98#ifdef NO_NEWT_SUPPORT 113#ifdef NO_NEWT_SUPPORT
99static inline int hists__browse(struct hists *self __used, 114static inline int hists__browse(struct hists *self __used,
100 const char *helpline __used, 115 const char *helpline __used,
@@ -126,4 +141,7 @@ int hist_entry__tui_annotate(struct hist_entry *self);
126 141
127int hists__tui_browse_tree(struct rb_root *self, const char *help); 142int hists__tui_browse_tree(struct rb_root *self, const char *help);
128#endif 143#endif
144
145unsigned int hists__sort_list_width(struct hists *self);
146
129#endif /* __PERF_HIST_H */ 147#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index e672f2fef65b..3a7eb6ec0eec 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -17,16 +17,6 @@ static inline int is_anon_memory(const char *filename)
17 return strcmp(filename, "//anon") == 0; 17 return strcmp(filename, "//anon") == 0;
18} 18}
19 19
20static int strcommon(const char *pathname, char *cwd, int cwdlen)
21{
22 int n = 0;
23
24 while (n < cwdlen && pathname[n] == cwd[n])
25 ++n;
26
27 return n;
28}
29
30void map__init(struct map *self, enum map_type type, 20void map__init(struct map *self, enum map_type type,
31 u64 start, u64 end, u64 pgoff, struct dso *dso) 21 u64 start, u64 end, u64 pgoff, struct dso *dso)
32{ 22{
@@ -39,11 +29,12 @@ void map__init(struct map *self, enum map_type type,
39 self->unmap_ip = map__unmap_ip; 29 self->unmap_ip = map__unmap_ip;
40 RB_CLEAR_NODE(&self->rb_node); 30 RB_CLEAR_NODE(&self->rb_node);
41 self->groups = NULL; 31 self->groups = NULL;
32 self->referenced = false;
42} 33}
43 34
44struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 35struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
45 u64 pgoff, u32 pid, char *filename, 36 u64 pgoff, u32 pid, char *filename,
46 enum map_type type, char *cwd, int cwdlen) 37 enum map_type type)
47{ 38{
48 struct map *self = malloc(sizeof(*self)); 39 struct map *self = malloc(sizeof(*self));
49 40
@@ -52,16 +43,6 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
52 struct dso *dso; 43 struct dso *dso;
53 int anon; 44 int anon;
54 45
55 if (cwd) {
56 int n = strcommon(filename, cwd, cwdlen);
57
58 if (n == cwdlen) {
59 snprintf(newfilename, sizeof(newfilename),
60 ".%s", filename + n);
61 filename = newfilename;
62 }
63 }
64
65 anon = is_anon_memory(filename); 46 anon = is_anon_memory(filename);
66 47
67 if (anon) { 48 if (anon) {
@@ -248,6 +229,39 @@ void map_groups__init(struct map_groups *self)
248 self->machine = NULL; 229 self->machine = NULL;
249} 230}
250 231
232static void maps__delete(struct rb_root *self)
233{
234 struct rb_node *next = rb_first(self);
235
236 while (next) {
237 struct map *pos = rb_entry(next, struct map, rb_node);
238
239 next = rb_next(&pos->rb_node);
240 rb_erase(&pos->rb_node, self);
241 map__delete(pos);
242 }
243}
244
245static void maps__delete_removed(struct list_head *self)
246{
247 struct map *pos, *n;
248
249 list_for_each_entry_safe(pos, n, self, node) {
250 list_del(&pos->node);
251 map__delete(pos);
252 }
253}
254
255void map_groups__exit(struct map_groups *self)
256{
257 int i;
258
259 for (i = 0; i < MAP__NR_TYPES; ++i) {
260 maps__delete(&self->maps[i]);
261 maps__delete_removed(&self->removed_maps[i]);
262 }
263}
264
251void map_groups__flush(struct map_groups *self) 265void map_groups__flush(struct map_groups *self)
252{ 266{
253 int type; 267 int type;
@@ -374,6 +388,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
374{ 388{
375 struct rb_root *root = &self->maps[map->type]; 389 struct rb_root *root = &self->maps[map->type];
376 struct rb_node *next = rb_first(root); 390 struct rb_node *next = rb_first(root);
391 int err = 0;
377 392
378 while (next) { 393 while (next) {
379 struct map *pos = rb_entry(next, struct map, rb_node); 394 struct map *pos = rb_entry(next, struct map, rb_node);
@@ -390,20 +405,16 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
390 405
391 rb_erase(&pos->rb_node, root); 406 rb_erase(&pos->rb_node, root);
392 /* 407 /*
393 * We may have references to this map, for instance in some
394 * hist_entry instances, so just move them to a separate
395 * list.
396 */
397 list_add_tail(&pos->node, &self->removed_maps[map->type]);
398 /*
399 * Now check if we need to create new maps for areas not 408 * Now check if we need to create new maps for areas not
400 * overlapped by the new map: 409 * overlapped by the new map:
401 */ 410 */
402 if (map->start > pos->start) { 411 if (map->start > pos->start) {
403 struct map *before = map__clone(pos); 412 struct map *before = map__clone(pos);
404 413
405 if (before == NULL) 414 if (before == NULL) {
406 return -ENOMEM; 415 err = -ENOMEM;
416 goto move_map;
417 }
407 418
408 before->end = map->start - 1; 419 before->end = map->start - 1;
409 map_groups__insert(self, before); 420 map_groups__insert(self, before);
@@ -414,14 +425,27 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
414 if (map->end < pos->end) { 425 if (map->end < pos->end) {
415 struct map *after = map__clone(pos); 426 struct map *after = map__clone(pos);
416 427
417 if (after == NULL) 428 if (after == NULL) {
418 return -ENOMEM; 429 err = -ENOMEM;
430 goto move_map;
431 }
419 432
420 after->start = map->end + 1; 433 after->start = map->end + 1;
421 map_groups__insert(self, after); 434 map_groups__insert(self, after);
422 if (verbose >= 2) 435 if (verbose >= 2)
423 map__fprintf(after, fp); 436 map__fprintf(after, fp);
424 } 437 }
438move_map:
439 /*
440 * If we have references, just move them to a separate list.
441 */
442 if (pos->referenced)
443 list_add_tail(&pos->node, &self->removed_maps[map->type]);
444 else
445 map__delete(pos);
446
447 if (err)
448 return err;
425 } 449 }
426 450
427 return 0; 451 return 0;
@@ -493,6 +517,11 @@ void maps__insert(struct rb_root *maps, struct map *map)
493 rb_insert_color(&map->rb_node, maps); 517 rb_insert_color(&map->rb_node, maps);
494} 518}
495 519
520void maps__remove(struct rb_root *self, struct map *map)
521{
522 rb_erase(&map->rb_node, self);
523}
524
496struct map *maps__find(struct rb_root *maps, u64 ip) 525struct map *maps__find(struct rb_root *maps, u64 ip)
497{ 526{
498 struct rb_node **p = &maps->rb_node; 527 struct rb_node **p = &maps->rb_node;
@@ -526,6 +555,31 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
526 return self->root_dir == NULL ? -ENOMEM : 0; 555 return self->root_dir == NULL ? -ENOMEM : 0;
527} 556}
528 557
558static void dsos__delete(struct list_head *self)
559{
560 struct dso *pos, *n;
561
562 list_for_each_entry_safe(pos, n, self, node) {
563 list_del(&pos->node);
564 dso__delete(pos);
565 }
566}
567
568void machine__exit(struct machine *self)
569{
570 map_groups__exit(&self->kmaps);
571 dsos__delete(&self->user_dsos);
572 dsos__delete(&self->kernel_dsos);
573 free(self->root_dir);
574 self->root_dir = NULL;
575}
576
577void machine__delete(struct machine *self)
578{
579 machine__exit(self);
580 free(self);
581}
582
529struct machine *machines__add(struct rb_root *self, pid_t pid, 583struct machine *machines__add(struct rb_root *self, pid_t pid,
530 const char *root_dir) 584 const char *root_dir)
531{ 585{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f39134512829..78575796d5f3 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -29,7 +29,8 @@ struct map {
29 }; 29 };
30 u64 start; 30 u64 start;
31 u64 end; 31 u64 end;
32 enum map_type type; 32 u8 /* enum map_type */ type;
33 bool referenced;
33 u32 priv; 34 u32 priv;
34 u64 pgoff; 35 u64 pgoff;
35 36
@@ -106,7 +107,7 @@ void map__init(struct map *self, enum map_type type,
106 u64 start, u64 end, u64 pgoff, struct dso *dso); 107 u64 start, u64 end, u64 pgoff, struct dso *dso);
107struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 108struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
108 u64 pgoff, u32 pid, char *filename, 109 u64 pgoff, u32 pid, char *filename,
109 enum map_type type, char *cwd, int cwdlen); 110 enum map_type type);
110void map__delete(struct map *self); 111void map__delete(struct map *self);
111struct map *map__clone(struct map *self); 112struct map *map__clone(struct map *self);
112int map__overlap(struct map *l, struct map *r); 113int map__overlap(struct map *l, struct map *r);
@@ -125,8 +126,10 @@ void map__reloc_vmlinux(struct map *self);
125size_t __map_groups__fprintf_maps(struct map_groups *self, 126size_t __map_groups__fprintf_maps(struct map_groups *self,
126 enum map_type type, int verbose, FILE *fp); 127 enum map_type type, int verbose, FILE *fp);
127void maps__insert(struct rb_root *maps, struct map *map); 128void maps__insert(struct rb_root *maps, struct map *map);
129void maps__remove(struct rb_root *self, struct map *map);
128struct map *maps__find(struct rb_root *maps, u64 addr); 130struct map *maps__find(struct rb_root *maps, u64 addr);
129void map_groups__init(struct map_groups *self); 131void map_groups__init(struct map_groups *self);
132void map_groups__exit(struct map_groups *self);
130int map_groups__clone(struct map_groups *self, 133int map_groups__clone(struct map_groups *self,
131 struct map_groups *parent, enum map_type type); 134 struct map_groups *parent, enum map_type type);
132size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); 135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
@@ -142,6 +145,8 @@ struct machine *machines__find(struct rb_root *self, pid_t pid);
142struct machine *machines__findnew(struct rb_root *self, pid_t pid); 145struct machine *machines__findnew(struct rb_root *self, pid_t pid);
143char *machine__mmap_name(struct machine *self, char *bf, size_t size); 146char *machine__mmap_name(struct machine *self, char *bf, size_t size);
144int machine__init(struct machine *self, const char *root_dir, pid_t pid); 147int machine__init(struct machine *self, const char *root_dir, pid_t pid);
148void machine__exit(struct machine *self);
149void machine__delete(struct machine *self);
145 150
146/* 151/*
147 * Default guest kernel is defined by parameter --guestkallsyms 152 * Default guest kernel is defined by parameter --guestkallsyms
@@ -163,6 +168,11 @@ static inline void map_groups__insert(struct map_groups *self, struct map *map)
163 map->groups = self; 168 map->groups = self;
164} 169}
165 170
171static inline void map_groups__remove(struct map_groups *self, struct map *map)
172{
173 maps__remove(&self->maps[map->type], map);
174}
175
166static inline struct map *map_groups__find(struct map_groups *self, 176static inline struct map *map_groups__find(struct map_groups *self,
167 enum map_type type, u64 addr) 177 enum map_type type, u64 addr)
168{ 178{
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 7537ca15900b..91de99b58445 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -11,6 +11,7 @@
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG 11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif 12#endif
13#include <slang.h> 13#include <slang.h>
14#include <signal.h>
14#include <stdlib.h> 15#include <stdlib.h>
15#include <newt.h> 16#include <newt.h>
16#include <sys/ttydefaults.h> 17#include <sys/ttydefaults.h>
@@ -278,9 +279,48 @@ struct ui_browser {
278 void *first_visible_entry, *entries; 279 void *first_visible_entry, *entries;
279 u16 top, left, width, height; 280 u16 top, left, width, height;
280 void *priv; 281 void *priv;
282 unsigned int (*refresh_entries)(struct ui_browser *self);
283 void (*seek)(struct ui_browser *self,
284 off_t offset, int whence);
281 u32 nr_entries; 285 u32 nr_entries;
282}; 286};
283 287
288static void ui_browser__list_head_seek(struct ui_browser *self,
289 off_t offset, int whence)
290{
291 struct list_head *head = self->entries;
292 struct list_head *pos;
293
294 switch (whence) {
295 case SEEK_SET:
296 pos = head->next;
297 break;
298 case SEEK_CUR:
299 pos = self->first_visible_entry;
300 break;
301 case SEEK_END:
302 pos = head->prev;
303 break;
304 default:
305 return;
306 }
307
308 if (offset > 0) {
309 while (offset-- != 0)
310 pos = pos->next;
311 } else {
312 while (offset++ != 0)
313 pos = pos->prev;
314 }
315
316 self->first_visible_entry = pos;
317}
318
319static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
320{
321 return (self->first_visible_entry_idx + row) == self->index;
322}
323
284static void ui_browser__refresh_dimensions(struct ui_browser *self) 324static void ui_browser__refresh_dimensions(struct ui_browser *self)
285{ 325{
286 int cols, rows; 326 int cols, rows;
@@ -297,8 +337,36 @@ static void ui_browser__refresh_dimensions(struct ui_browser *self)
297 337
298static void ui_browser__reset_index(struct ui_browser *self) 338static void ui_browser__reset_index(struct ui_browser *self)
299{ 339{
300 self->index = self->first_visible_entry_idx = 0; 340 self->index = self->first_visible_entry_idx = 0;
301 self->first_visible_entry = NULL; 341 self->seek(self, 0, SEEK_SET);
342}
343
344static int ui_browser__show(struct ui_browser *self, const char *title)
345{
346 if (self->form != NULL) {
347 newtFormDestroy(self->form);
348 newtPopWindow();
349 }
350 ui_browser__refresh_dimensions(self);
351 newtCenteredWindow(self->width, self->height, title);
352 self->form = newt_form__new();
353 if (self->form == NULL)
354 return -1;
355
356 self->sb = newtVerticalScrollbar(self->width, 0, self->height,
357 HE_COLORSET_NORMAL,
358 HE_COLORSET_SELECTED);
359 if (self->sb == NULL)
360 return -1;
361
362 newtFormAddHotKey(self->form, NEWT_KEY_UP);
363 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
364 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
365 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
366 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
367 newtFormAddHotKey(self->form, NEWT_KEY_END);
368 newtFormAddComponent(self->form, self->sb);
369 return 0;
302} 370}
303 371
304static int objdump_line__show(struct objdump_line *self, struct list_head *head, 372static int objdump_line__show(struct objdump_line *self, struct list_head *head,
@@ -352,26 +420,10 @@ static int objdump_line__show(struct objdump_line *self, struct list_head *head,
352 420
353static int ui_browser__refresh_entries(struct ui_browser *self) 421static int ui_browser__refresh_entries(struct ui_browser *self)
354{ 422{
355 struct objdump_line *pos; 423 int row;
356 struct list_head *head = self->entries;
357 struct hist_entry *he = self->priv;
358 int row = 0;
359 int len = he->ms.sym->end - he->ms.sym->start;
360
361 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
362 self->first_visible_entry = head->next;
363
364 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
365
366 list_for_each_entry_from(pos, head, node) {
367 bool current_entry = (self->first_visible_entry_idx + row) == self->index;
368 SLsmg_gotorc(self->top + row, self->left);
369 objdump_line__show(pos, head, self->width,
370 he, len, current_entry);
371 if (++row == self->height)
372 break;
373 }
374 424
425 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
426 row = self->refresh_entries(self);
375 SLsmg_set_color(HE_COLORSET_NORMAL); 427 SLsmg_set_color(HE_COLORSET_NORMAL);
376 SLsmg_fill_region(self->top + row, self->left, 428 SLsmg_fill_region(self->top + row, self->left,
377 self->height - row, self->width, ' '); 429 self->height - row, self->width, ' ');
@@ -379,42 +431,13 @@ static int ui_browser__refresh_entries(struct ui_browser *self)
379 return 0; 431 return 0;
380} 432}
381 433
382static int ui_browser__run(struct ui_browser *self, const char *title, 434static int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
383 struct newtExitStruct *es)
384{ 435{
385 if (self->form) {
386 newtFormDestroy(self->form);
387 newtPopWindow();
388 }
389
390 ui_browser__refresh_dimensions(self);
391 newtCenteredWindow(self->width + 2, self->height, title);
392 self->form = newt_form__new();
393 if (self->form == NULL)
394 return -1;
395
396 self->sb = newtVerticalScrollbar(self->width + 1, 0, self->height,
397 HE_COLORSET_NORMAL,
398 HE_COLORSET_SELECTED);
399 if (self->sb == NULL)
400 return -1;
401
402 newtFormAddHotKey(self->form, NEWT_KEY_UP);
403 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
404 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
405 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
406 newtFormAddHotKey(self->form, ' ');
407 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
408 newtFormAddHotKey(self->form, NEWT_KEY_END);
409 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
410 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
411
412 if (ui_browser__refresh_entries(self) < 0) 436 if (ui_browser__refresh_entries(self) < 0)
413 return -1; 437 return -1;
414 newtFormAddComponent(self->form, self->sb);
415 438
416 while (1) { 439 while (1) {
417 unsigned int offset; 440 off_t offset;
418 441
419 newtFormRun(self->form, es); 442 newtFormRun(self->form, es);
420 443
@@ -428,9 +451,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
428 break; 451 break;
429 ++self->index; 452 ++self->index;
430 if (self->index == self->first_visible_entry_idx + self->height) { 453 if (self->index == self->first_visible_entry_idx + self->height) {
431 struct list_head *pos = self->first_visible_entry;
432 ++self->first_visible_entry_idx; 454 ++self->first_visible_entry_idx;
433 self->first_visible_entry = pos->next; 455 self->seek(self, +1, SEEK_CUR);
434 } 456 }
435 break; 457 break;
436 case NEWT_KEY_UP: 458 case NEWT_KEY_UP:
@@ -438,9 +460,8 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
438 break; 460 break;
439 --self->index; 461 --self->index;
440 if (self->index < self->first_visible_entry_idx) { 462 if (self->index < self->first_visible_entry_idx) {
441 struct list_head *pos = self->first_visible_entry;
442 --self->first_visible_entry_idx; 463 --self->first_visible_entry_idx;
443 self->first_visible_entry = pos->prev; 464 self->seek(self, -1, SEEK_CUR);
444 } 465 }
445 break; 466 break;
446 case NEWT_KEY_PGDN: 467 case NEWT_KEY_PGDN:
@@ -453,12 +474,7 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
453 offset = self->nr_entries - 1 - self->index; 474 offset = self->nr_entries - 1 - self->index;
454 self->index += offset; 475 self->index += offset;
455 self->first_visible_entry_idx += offset; 476 self->first_visible_entry_idx += offset;
456 477 self->seek(self, +offset, SEEK_CUR);
457 while (offset--) {
458 struct list_head *pos = self->first_visible_entry;
459 self->first_visible_entry = pos->next;
460 }
461
462 break; 478 break;
463 case NEWT_KEY_PGUP: 479 case NEWT_KEY_PGUP:
464 if (self->first_visible_entry_idx == 0) 480 if (self->first_visible_entry_idx == 0)
@@ -471,36 +487,22 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
471 487
472 self->index -= offset; 488 self->index -= offset;
473 self->first_visible_entry_idx -= offset; 489 self->first_visible_entry_idx -= offset;
474 490 self->seek(self, -offset, SEEK_CUR);
475 while (offset--) {
476 struct list_head *pos = self->first_visible_entry;
477 self->first_visible_entry = pos->prev;
478 }
479 break; 491 break;
480 case NEWT_KEY_HOME: 492 case NEWT_KEY_HOME:
481 ui_browser__reset_index(self); 493 ui_browser__reset_index(self);
482 break; 494 break;
483 case NEWT_KEY_END: { 495 case NEWT_KEY_END:
484 struct list_head *head = self->entries;
485 offset = self->height - 1; 496 offset = self->height - 1;
497 if (offset >= self->nr_entries)
498 offset = self->nr_entries - 1;
486 499
487 if (offset > self->nr_entries) 500 self->index = self->nr_entries - 1;
488 offset = self->nr_entries; 501 self->first_visible_entry_idx = self->index - offset;
489 502 self->seek(self, -offset, SEEK_END);
490 self->index = self->first_visible_entry_idx = self->nr_entries - 1 - offset;
491 self->first_visible_entry = head->prev;
492 while (offset-- != 0) {
493 struct list_head *pos = self->first_visible_entry;
494 self->first_visible_entry = pos->prev;
495 }
496 }
497 break; 503 break;
498 case NEWT_KEY_RIGHT:
499 case NEWT_KEY_LEFT:
500 case NEWT_KEY_TAB:
501 return es->u.key;
502 default: 504 default:
503 continue; 505 return es->u.key;
504 } 506 }
505 if (ui_browser__refresh_entries(self) < 0) 507 if (ui_browser__refresh_entries(self) < 0)
506 return -1; 508 return -1;
@@ -508,38 +510,6 @@ static int ui_browser__run(struct ui_browser *self, const char *title,
508 return 0; 510 return 0;
509} 511}
510 512
511/*
512 * When debugging newt problems it was useful to be able to "unroll"
513 * the calls to newtCheckBoxTreeAdd{Array,Item}, so that we can generate
514 * a source file with the sequence of calls to these methods, to then
515 * tweak the arrays to get the intended results, so I'm keeping this code
516 * here, may be useful again in the future.
517 */
518#undef NEWT_DEBUG
519
520static void newt_checkbox_tree__add(newtComponent tree, const char *str,
521 void *priv, int *indexes)
522{
523#ifdef NEWT_DEBUG
524 /* Print the newtCheckboxTreeAddArray to tinker with its index arrays */
525 int i = 0, len = 40 - strlen(str);
526
527 fprintf(stderr,
528 "\tnewtCheckboxTreeAddItem(tree, %*.*s\"%s\", (void *)%p, 0, ",
529 len, len, " ", str, priv);
530 while (indexes[i] != NEWT_ARG_LAST) {
531 if (indexes[i] != NEWT_ARG_APPEND)
532 fprintf(stderr, " %d,", indexes[i]);
533 else
534 fprintf(stderr, " %s,", "NEWT_ARG_APPEND");
535 ++i;
536 }
537 fprintf(stderr, " %s", " NEWT_ARG_LAST);\n");
538 fflush(stderr);
539#endif
540 newtCheckboxTreeAddArray(tree, str, priv, 0, indexes);
541}
542
543static char *callchain_list__sym_name(struct callchain_list *self, 513static char *callchain_list__sym_name(struct callchain_list *self,
544 char *bf, size_t bfsize) 514 char *bf, size_t bfsize)
545{ 515{
@@ -550,144 +520,29 @@ static char *callchain_list__sym_name(struct callchain_list *self,
550 return bf; 520 return bf;
551} 521}
552 522
553static void __callchain__append_graph_browser(struct callchain_node *self, 523static unsigned int hist_entry__annotate_browser_refresh(struct ui_browser *self)
554 newtComponent tree, u64 total,
555 int *indexes, int depth)
556{ 524{
557 struct rb_node *node; 525 struct objdump_line *pos;
558 u64 new_total, remaining; 526 struct list_head *head = self->entries;
559 int idx = 0; 527 struct hist_entry *he = self->priv;
560 528 int row = 0;
561 if (callchain_param.mode == CHAIN_GRAPH_REL) 529 int len = he->ms.sym->end - he->ms.sym->start;
562 new_total = self->children_hit;
563 else
564 new_total = total;
565
566 remaining = new_total;
567 node = rb_first(&self->rb_root);
568 while (node) {
569 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
570 struct rb_node *next = rb_next(node);
571 u64 cumul = cumul_hits(child);
572 struct callchain_list *chain;
573 int first = true, printed = 0;
574 int chain_idx = -1;
575 remaining -= cumul;
576
577 indexes[depth] = NEWT_ARG_APPEND;
578 indexes[depth + 1] = NEWT_ARG_LAST;
579
580 list_for_each_entry(chain, &child->val, list) {
581 char ipstr[BITS_PER_LONG / 4 + 1],
582 *alloc_str = NULL;
583 const char *str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
584
585 if (first) {
586 double percent = cumul * 100.0 / new_total;
587
588 first = false;
589 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
590 str = "Not enough memory!";
591 else
592 str = alloc_str;
593 } else {
594 indexes[depth] = idx;
595 indexes[depth + 1] = NEWT_ARG_APPEND;
596 indexes[depth + 2] = NEWT_ARG_LAST;
597 ++chain_idx;
598 }
599 newt_checkbox_tree__add(tree, str, &chain->ms, indexes);
600 free(alloc_str);
601 ++printed;
602 }
603
604 indexes[depth] = idx;
605 if (chain_idx != -1)
606 indexes[depth + 1] = chain_idx;
607 if (printed != 0)
608 ++idx;
609 __callchain__append_graph_browser(child, tree, new_total, indexes,
610 depth + (chain_idx != -1 ? 2 : 1));
611 node = next;
612 }
613}
614
615static void callchain__append_graph_browser(struct callchain_node *self,
616 newtComponent tree, u64 total,
617 int *indexes, int parent_idx)
618{
619 struct callchain_list *chain;
620 int i = 0;
621
622 indexes[1] = NEWT_ARG_APPEND;
623 indexes[2] = NEWT_ARG_LAST;
624
625 list_for_each_entry(chain, &self->val, list) {
626 char ipstr[BITS_PER_LONG / 4 + 1], *str;
627
628 if (chain->ip >= PERF_CONTEXT_MAX)
629 continue;
630
631 if (!i++ && sort__first_dimension == SORT_SYM)
632 continue;
633 530
634 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); 531 if (self->first_visible_entry == NULL || self->first_visible_entry == self->entries)
635 newt_checkbox_tree__add(tree, str, &chain->ms, indexes); 532 self->first_visible_entry = head->next;
636 }
637 533
638 indexes[1] = parent_idx; 534 pos = list_entry(self->first_visible_entry, struct objdump_line, node);
639 indexes[2] = NEWT_ARG_APPEND;
640 indexes[3] = NEWT_ARG_LAST;
641 __callchain__append_graph_browser(self, tree, total, indexes, 2);
642}
643 535
644static void hist_entry__append_callchain_browser(struct hist_entry *self, 536 list_for_each_entry_from(pos, head, node) {
645 newtComponent tree, u64 total, int parent_idx) 537 bool current_entry = ui_browser__is_current_entry(self, row);
646{ 538 SLsmg_gotorc(self->top + row, self->left);
647 struct rb_node *rb_node; 539 objdump_line__show(pos, head, self->width,
648 int indexes[1024] = { [0] = parent_idx, }; 540 he, len, current_entry);
649 int idx = 0; 541 if (++row == self->height)
650 struct callchain_node *chain;
651
652 rb_node = rb_first(&self->sorted_chain);
653 while (rb_node) {
654 chain = rb_entry(rb_node, struct callchain_node, rb_node);
655 switch (callchain_param.mode) {
656 case CHAIN_FLAT:
657 break;
658 case CHAIN_GRAPH_ABS: /* falldown */
659 case CHAIN_GRAPH_REL:
660 callchain__append_graph_browser(chain, tree, total, indexes, idx++);
661 break;
662 case CHAIN_NONE:
663 default:
664 break; 542 break;
665 }
666 rb_node = rb_next(rb_node);
667 } 543 }
668}
669
670static size_t hist_entry__append_browser(struct hist_entry *self,
671 newtComponent tree, u64 total)
672{
673 char s[256];
674 size_t ret;
675
676 if (symbol_conf.exclude_other && !self->parent)
677 return 0;
678 544
679 ret = hist_entry__snprintf(self, s, sizeof(s), NULL, 545 return row;
680 false, 0, false, total);
681 if (symbol_conf.use_callchain) {
682 int indexes[2];
683
684 indexes[0] = NEWT_ARG_APPEND;
685 indexes[1] = NEWT_ARG_LAST;
686 newt_checkbox_tree__add(tree, s, &self->ms, indexes);
687 } else
688 newtListboxAppendEntry(tree, s, &self->ms);
689
690 return ret;
691} 546}
692 547
693int hist_entry__tui_annotate(struct hist_entry *self) 548int hist_entry__tui_annotate(struct hist_entry *self)
@@ -712,7 +567,9 @@ int hist_entry__tui_annotate(struct hist_entry *self)
712 ui_helpline__push("Press <- or ESC to exit"); 567 ui_helpline__push("Press <- or ESC to exit");
713 568
714 memset(&browser, 0, sizeof(browser)); 569 memset(&browser, 0, sizeof(browser));
715 browser.entries = &head; 570 browser.entries = &head;
571 browser.refresh_entries = hist_entry__annotate_browser_refresh;
572 browser.seek = ui_browser__list_head_seek;
716 browser.priv = self; 573 browser.priv = self;
717 list_for_each_entry(pos, &head, node) { 574 list_for_each_entry(pos, &head, node) {
718 size_t line_len = strlen(pos->line); 575 size_t line_len = strlen(pos->line);
@@ -722,7 +579,9 @@ int hist_entry__tui_annotate(struct hist_entry *self)
722 } 579 }
723 580
724 browser.width += 18; /* Percentage */ 581 browser.width += 18; /* Percentage */
725 ret = ui_browser__run(&browser, self->ms.sym->name, &es); 582 ui_browser__show(&browser, self->ms.sym->name);
583 newtFormAddHotKey(browser.form, ' ');
584 ret = ui_browser__run(&browser, &es);
726 newtFormDestroy(browser.form); 585 newtFormDestroy(browser.form);
727 newtPopWindow(); 586 newtPopWindow();
728 list_for_each_entry_safe(pos, n, &head, node) { 587 list_for_each_entry_safe(pos, n, &head, node) {
@@ -733,157 +592,48 @@ int hist_entry__tui_annotate(struct hist_entry *self)
733 return ret; 592 return ret;
734} 593}
735 594
736static const void *newt__symbol_tree_get_current(newtComponent self)
737{
738 if (symbol_conf.use_callchain)
739 return newtCheckboxTreeGetCurrent(self);
740 return newtListboxGetCurrent(self);
741}
742
743static void hist_browser__selection(newtComponent self, void *data)
744{
745 const struct map_symbol **symbol_ptr = data;
746 *symbol_ptr = newt__symbol_tree_get_current(self);
747}
748
749struct hist_browser { 595struct hist_browser {
750 newtComponent form, tree; 596 struct ui_browser b;
751 const struct map_symbol *selection; 597 struct hists *hists;
598 struct hist_entry *he_selection;
599 struct map_symbol *selection;
752}; 600};
753 601
754static struct hist_browser *hist_browser__new(void) 602static void hist_browser__reset(struct hist_browser *self);
603static int hist_browser__run(struct hist_browser *self, const char *title,
604 struct newtExitStruct *es);
605static unsigned int hist_browser__refresh_entries(struct ui_browser *self);
606static void ui_browser__hists_seek(struct ui_browser *self,
607 off_t offset, int whence);
608
609static struct hist_browser *hist_browser__new(struct hists *hists)
755{ 610{
756 struct hist_browser *self = malloc(sizeof(*self)); 611 struct hist_browser *self = zalloc(sizeof(*self));
757 612
758 if (self != NULL) 613 if (self) {
759 self->form = NULL; 614 self->hists = hists;
615 self->b.refresh_entries = hist_browser__refresh_entries;
616 self->b.seek = ui_browser__hists_seek;
617 }
760 618
761 return self; 619 return self;
762} 620}
763 621
764static void hist_browser__delete(struct hist_browser *self) 622static void hist_browser__delete(struct hist_browser *self)
765{ 623{
766 newtFormDestroy(self->form); 624 newtFormDestroy(self->b.form);
767 newtPopWindow(); 625 newtPopWindow();
768 free(self); 626 free(self);
769} 627}
770 628
771static int hist_browser__populate(struct hist_browser *self, struct hists *hists,
772 const char *title)
773{
774 int max_len = 0, idx, cols, rows;
775 struct ui_progress *progress;
776 struct rb_node *nd;
777 u64 curr_hist = 0;
778 char seq[] = ".", unit;
779 char str[256];
780 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
781
782 if (self->form) {
783 newtFormDestroy(self->form);
784 newtPopWindow();
785 }
786
787 nr_events = convert_unit(nr_events, &unit);
788 snprintf(str, sizeof(str), "Events: %lu%c ",
789 nr_events, unit);
790 newtDrawRootText(0, 0, str);
791
792 newtGetScreenSize(NULL, &rows);
793
794 if (symbol_conf.use_callchain)
795 self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
796 NEWT_FLAG_SCROLL);
797 else
798 self->tree = newtListbox(0, 0, rows - 5,
799 (NEWT_FLAG_SCROLL |
800 NEWT_FLAG_RETURNEXIT));
801
802 newtComponentAddCallback(self->tree, hist_browser__selection,
803 &self->selection);
804
805 progress = ui_progress__new("Adding entries to the browser...",
806 hists->nr_entries);
807 if (progress == NULL)
808 return -1;
809
810 idx = 0;
811 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
812 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
813 int len;
814
815 if (h->filtered)
816 continue;
817
818 len = hist_entry__append_browser(h, self->tree, hists->stats.total_period);
819 if (len > max_len)
820 max_len = len;
821 if (symbol_conf.use_callchain)
822 hist_entry__append_callchain_browser(h, self->tree,
823 hists->stats.total_period, idx++);
824 ++curr_hist;
825 if (curr_hist % 5)
826 ui_progress__update(progress, curr_hist);
827 }
828
829 ui_progress__delete(progress);
830
831 newtGetScreenSize(&cols, &rows);
832
833 if (max_len > cols)
834 max_len = cols - 3;
835
836 if (!symbol_conf.use_callchain)
837 newtListboxSetWidth(self->tree, max_len);
838
839 newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
840 rows - 5, title);
841 self->form = newt_form__new();
842 if (self->form == NULL)
843 return -1;
844
845 newtFormAddHotKey(self->form, 'A');
846 newtFormAddHotKey(self->form, 'a');
847 newtFormAddHotKey(self->form, 'D');
848 newtFormAddHotKey(self->form, 'd');
849 newtFormAddHotKey(self->form, 'T');
850 newtFormAddHotKey(self->form, 't');
851 newtFormAddHotKey(self->form, '?');
852 newtFormAddHotKey(self->form, 'H');
853 newtFormAddHotKey(self->form, 'h');
854 newtFormAddHotKey(self->form, NEWT_KEY_F1);
855 newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
856 newtFormAddHotKey(self->form, NEWT_KEY_TAB);
857 newtFormAddHotKey(self->form, NEWT_KEY_UNTAB);
858 newtFormAddComponents(self->form, self->tree, NULL);
859 self->selection = newt__symbol_tree_get_current(self->tree);
860
861 return 0;
862}
863
864static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self) 629static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
865{ 630{
866 int *indexes; 631 return self->he_selection;
867
868 if (!symbol_conf.use_callchain)
869 goto out;
870
871 indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection);
872 if (indexes) {
873 bool is_hist_entry = indexes[1] == NEWT_ARG_LAST;
874 free(indexes);
875 if (is_hist_entry)
876 goto out;
877 }
878 return NULL;
879out:
880 return container_of(self->selection, struct hist_entry, ms);
881} 632}
882 633
883static struct thread *hist_browser__selected_thread(struct hist_browser *self) 634static struct thread *hist_browser__selected_thread(struct hist_browser *self)
884{ 635{
885 struct hist_entry *he = hist_browser__selected_entry(self); 636 return self->he_selection->thread;
886 return he ? he->thread : NULL;
887} 637}
888 638
889static int hist_browser__title(char *bf, size_t size, const char *ev_name, 639static int hist_browser__title(char *bf, size_t size, const char *ev_name,
@@ -905,7 +655,7 @@ static int hist_browser__title(char *bf, size_t size, const char *ev_name,
905 655
906int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 656int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
907{ 657{
908 struct hist_browser *browser = hist_browser__new(); 658 struct hist_browser *browser = hist_browser__new(self);
909 struct pstack *fstack; 659 struct pstack *fstack;
910 const struct thread *thread_filter = NULL; 660 const struct thread *thread_filter = NULL;
911 const struct dso *dso_filter = NULL; 661 const struct dso *dso_filter = NULL;
@@ -924,8 +674,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
924 674
925 hist_browser__title(msg, sizeof(msg), ev_name, 675 hist_browser__title(msg, sizeof(msg), ev_name,
926 dso_filter, thread_filter); 676 dso_filter, thread_filter);
927 if (hist_browser__populate(browser, self, msg) < 0)
928 goto out_free_stack;
929 677
930 while (1) { 678 while (1) {
931 const struct thread *thread; 679 const struct thread *thread;
@@ -934,7 +682,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
934 int nr_options = 0, choice = 0, i, 682 int nr_options = 0, choice = 0, i,
935 annotate = -2, zoom_dso = -2, zoom_thread = -2; 683 annotate = -2, zoom_dso = -2, zoom_thread = -2;
936 684
937 newtFormRun(browser->form, &es); 685 if (hist_browser__run(browser, msg, &es))
686 break;
938 687
939 thread = hist_browser__selected_thread(browser); 688 thread = hist_browser__selected_thread(browser);
940 dso = browser->selection->map ? browser->selection->map->dso : NULL; 689 dso = browser->selection->map ? browser->selection->map->dso : NULL;
@@ -1069,8 +818,7 @@ zoom_out_dso:
1069 hists__filter_by_dso(self, dso_filter); 818 hists__filter_by_dso(self, dso_filter);
1070 hist_browser__title(msg, sizeof(msg), ev_name, 819 hist_browser__title(msg, sizeof(msg), ev_name,
1071 dso_filter, thread_filter); 820 dso_filter, thread_filter);
1072 if (hist_browser__populate(browser, self, msg) < 0) 821 hist_browser__reset(browser);
1073 goto out;
1074 } else if (choice == zoom_thread) { 822 } else if (choice == zoom_thread) {
1075zoom_thread: 823zoom_thread:
1076 if (thread_filter) { 824 if (thread_filter) {
@@ -1088,8 +836,7 @@ zoom_out_thread:
1088 hists__filter_by_thread(self, thread_filter); 836 hists__filter_by_thread(self, thread_filter);
1089 hist_browser__title(msg, sizeof(msg), ev_name, 837 hist_browser__title(msg, sizeof(msg), ev_name,
1090 dso_filter, thread_filter); 838 dso_filter, thread_filter);
1091 if (hist_browser__populate(browser, self, msg) < 0) 839 hist_browser__reset(browser);
1092 goto out;
1093 } 840 }
1094 } 841 }
1095out_free_stack: 842out_free_stack:
@@ -1145,6 +892,13 @@ static struct newtPercentTreeColors {
1145 "blue", "lightgray", 892 "blue", "lightgray",
1146}; 893};
1147 894
895static void newt_suspend(void *d __used)
896{
897 newtSuspend();
898 raise(SIGTSTP);
899 newtResume();
900}
901
1148void setup_browser(void) 902void setup_browser(void)
1149{ 903{
1150 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 904 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
@@ -1158,6 +912,7 @@ void setup_browser(void)
1158 use_browser = 1; 912 use_browser = 1;
1159 newtInit(); 913 newtInit();
1160 newtCls(); 914 newtCls();
915 newtSetSuspendCallback(newt_suspend, NULL);
1161 ui_helpline__puts(" "); 916 ui_helpline__puts(" ");
1162 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 917 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
1163 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 918 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
@@ -1176,3 +931,638 @@ void exit_browser(bool wait_for_ok)
1176 newtFinished(); 931 newtFinished();
1177 } 932 }
1178} 933}
934
935static void hist_browser__refresh_dimensions(struct hist_browser *self)
936{
937 /* 3 == +/- toggle symbol before actual hist_entry rendering */
938 self->b.width = 3 + (hists__sort_list_width(self->hists) +
939 sizeof("[k]"));
940}
941
942static void hist_browser__reset(struct hist_browser *self)
943{
944 self->b.nr_entries = self->hists->nr_entries;
945 hist_browser__refresh_dimensions(self);
946 ui_browser__reset_index(&self->b);
947}
948
949static char tree__folded_sign(bool unfolded)
950{
951 return unfolded ? '-' : '+';
952}
953
954static char map_symbol__folded(const struct map_symbol *self)
955{
956 return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
957}
958
959static char hist_entry__folded(const struct hist_entry *self)
960{
961 return map_symbol__folded(&self->ms);
962}
963
964static char callchain_list__folded(const struct callchain_list *self)
965{
966 return map_symbol__folded(&self->ms);
967}
968
969static bool map_symbol__toggle_fold(struct map_symbol *self)
970{
971 if (!self->has_children)
972 return false;
973
974 self->unfolded = !self->unfolded;
975 return true;
976}
977
978#define LEVEL_OFFSET_STEP 3
979
980static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
981 struct callchain_node *chain_node,
982 u64 total, int level,
983 unsigned short row,
984 off_t *row_offset,
985 bool *is_current_entry)
986{
987 struct rb_node *node;
988 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
989 u64 new_total, remaining;
990
991 if (callchain_param.mode == CHAIN_GRAPH_REL)
992 new_total = chain_node->children_hit;
993 else
994 new_total = total;
995
996 remaining = new_total;
997 node = rb_first(&chain_node->rb_root);
998 while (node) {
999 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1000 struct rb_node *next = rb_next(node);
1001 u64 cumul = cumul_hits(child);
1002 struct callchain_list *chain;
1003 char folded_sign = ' ';
1004 int first = true;
1005 int extra_offset = 0;
1006
1007 remaining -= cumul;
1008
1009 list_for_each_entry(chain, &child->val, list) {
1010 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
1011 const char *str;
1012 int color;
1013 bool was_first = first;
1014
1015 if (first) {
1016 first = false;
1017 chain->ms.has_children = chain->list.next != &child->val ||
1018 rb_first(&child->rb_root) != NULL;
1019 } else {
1020 extra_offset = LEVEL_OFFSET_STEP;
1021 chain->ms.has_children = chain->list.next == &child->val &&
1022 rb_first(&child->rb_root) != NULL;
1023 }
1024
1025 folded_sign = callchain_list__folded(chain);
1026 if (*row_offset != 0) {
1027 --*row_offset;
1028 goto do_next;
1029 }
1030
1031 alloc_str = NULL;
1032 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
1033 if (was_first) {
1034 double percent = cumul * 100.0 / new_total;
1035
1036 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1037 str = "Not enough memory!";
1038 else
1039 str = alloc_str;
1040 }
1041
1042 color = HE_COLORSET_NORMAL;
1043 width = self->b.width - (offset + extra_offset + 2);
1044 if (ui_browser__is_current_entry(&self->b, row)) {
1045 self->selection = &chain->ms;
1046 color = HE_COLORSET_SELECTED;
1047 *is_current_entry = true;
1048 }
1049
1050 SLsmg_set_color(color);
1051 SLsmg_gotorc(self->b.top + row, self->b.left);
1052 slsmg_write_nstring(" ", offset + extra_offset);
1053 slsmg_printf("%c ", folded_sign);
1054 slsmg_write_nstring(str, width);
1055 free(alloc_str);
1056
1057 if (++row == self->b.height)
1058 goto out;
1059do_next:
1060 if (folded_sign == '+')
1061 break;
1062 }
1063
1064 if (folded_sign == '-') {
1065 const int new_level = level + (extra_offset ? 2 : 1);
1066 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
1067 new_level, row, row_offset,
1068 is_current_entry);
1069 }
1070 if (row == self->b.height)
1071 goto out;
1072 node = next;
1073 }
1074out:
1075 return row - first_row;
1076}
1077
1078static int hist_browser__show_callchain_node(struct hist_browser *self,
1079 struct callchain_node *node,
1080 int level, unsigned short row,
1081 off_t *row_offset,
1082 bool *is_current_entry)
1083{
1084 struct callchain_list *chain;
1085 int first_row = row,
1086 offset = level * LEVEL_OFFSET_STEP,
1087 width = self->b.width - offset;
1088 char folded_sign = ' ';
1089
1090 list_for_each_entry(chain, &node->val, list) {
1091 char ipstr[BITS_PER_LONG / 4 + 1], *s;
1092 int color;
1093 /*
1094 * FIXME: This should be moved to somewhere else,
1095 * probably when the callchain is created, so as not to
1096 * traverse it all over again
1097 */
1098 chain->ms.has_children = rb_first(&node->rb_root) != NULL;
1099 folded_sign = callchain_list__folded(chain);
1100
1101 if (*row_offset != 0) {
1102 --*row_offset;
1103 continue;
1104 }
1105
1106 color = HE_COLORSET_NORMAL;
1107 if (ui_browser__is_current_entry(&self->b, row)) {
1108 self->selection = &chain->ms;
1109 color = HE_COLORSET_SELECTED;
1110 *is_current_entry = true;
1111 }
1112
1113 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
1114 SLsmg_gotorc(self->b.top + row, self->b.left);
1115 SLsmg_set_color(color);
1116 slsmg_write_nstring(" ", offset);
1117 slsmg_printf("%c ", folded_sign);
1118 slsmg_write_nstring(s, width - 2);
1119
1120 if (++row == self->b.height)
1121 goto out;
1122 }
1123
1124 if (folded_sign == '-')
1125 row += hist_browser__show_callchain_node_rb_tree(self, node,
1126 self->hists->stats.total_period,
1127 level + 1, row,
1128 row_offset,
1129 is_current_entry);
1130out:
1131 return row - first_row;
1132}
1133
1134static int hist_browser__show_callchain(struct hist_browser *self,
1135 struct rb_root *chain,
1136 int level, unsigned short row,
1137 off_t *row_offset,
1138 bool *is_current_entry)
1139{
1140 struct rb_node *nd;
1141 int first_row = row;
1142
1143 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1144 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1145
1146 row += hist_browser__show_callchain_node(self, node, level,
1147 row, row_offset,
1148 is_current_entry);
1149 if (row == self->b.height)
1150 break;
1151 }
1152
1153 return row - first_row;
1154}
1155
1156static int hist_browser__show_entry(struct hist_browser *self,
1157 struct hist_entry *entry,
1158 unsigned short row)
1159{
1160 char s[256];
1161 double percent;
1162 int printed = 0;
1163 int color, width = self->b.width;
1164 char folded_sign = ' ';
1165 bool current_entry = ui_browser__is_current_entry(&self->b, row);
1166 off_t row_offset = entry->row_offset;
1167
1168 if (current_entry) {
1169 self->he_selection = entry;
1170 self->selection = &entry->ms;
1171 }
1172
1173 if (symbol_conf.use_callchain) {
1174 entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain);
1175 folded_sign = hist_entry__folded(entry);
1176 }
1177
1178 if (row_offset == 0) {
1179 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false,
1180 0, false, self->hists->stats.total_period);
1181 percent = (entry->period * 100.0) / self->hists->stats.total_period;
1182
1183 color = HE_COLORSET_SELECTED;
1184 if (!current_entry) {
1185 if (percent >= MIN_RED)
1186 color = HE_COLORSET_TOP;
1187 else if (percent >= MIN_GREEN)
1188 color = HE_COLORSET_MEDIUM;
1189 else
1190 color = HE_COLORSET_NORMAL;
1191 }
1192
1193 SLsmg_set_color(color);
1194 SLsmg_gotorc(self->b.top + row, self->b.left);
1195 if (symbol_conf.use_callchain) {
1196 slsmg_printf("%c ", folded_sign);
1197 width -= 2;
1198 }
1199 slsmg_write_nstring(s, width);
1200 ++row;
1201 ++printed;
1202 } else
1203 --row_offset;
1204
1205 if (folded_sign == '-' && row != self->b.height) {
1206 printed += hist_browser__show_callchain(self, &entry->sorted_chain,
1207 1, row, &row_offset,
1208 &current_entry);
1209 if (current_entry)
1210 self->he_selection = entry;
1211 }
1212
1213 return printed;
1214}
1215
1216static unsigned int hist_browser__refresh_entries(struct ui_browser *self)
1217{
1218 unsigned row = 0;
1219 struct rb_node *nd;
1220 struct hist_browser *hb = container_of(self, struct hist_browser, b);
1221
1222 if (self->first_visible_entry == NULL)
1223 self->first_visible_entry = rb_first(&hb->hists->entries);
1224
1225 for (nd = self->first_visible_entry; nd; nd = rb_next(nd)) {
1226 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1227
1228 if (h->filtered)
1229 continue;
1230
1231 row += hist_browser__show_entry(hb, h, row);
1232 if (row == self->height)
1233 break;
1234 }
1235
1236 return row;
1237}
1238
1239static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
1240{
1241 struct rb_node *nd = rb_first(&self->rb_root);
1242
1243 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
1244 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
1245 struct callchain_list *chain;
1246 int first = true;
1247
1248 list_for_each_entry(chain, &child->val, list) {
1249 if (first) {
1250 first = false;
1251 chain->ms.has_children = chain->list.next != &child->val ||
1252 rb_first(&child->rb_root) != NULL;
1253 } else
1254 chain->ms.has_children = chain->list.next == &child->val &&
1255 rb_first(&child->rb_root) != NULL;
1256 }
1257
1258 callchain_node__init_have_children_rb_tree(child);
1259 }
1260}
1261
1262static void callchain_node__init_have_children(struct callchain_node *self)
1263{
1264 struct callchain_list *chain;
1265
1266 list_for_each_entry(chain, &self->val, list)
1267 chain->ms.has_children = rb_first(&self->rb_root) != NULL;
1268
1269 callchain_node__init_have_children_rb_tree(self);
1270}
1271
1272static void callchain__init_have_children(struct rb_root *self)
1273{
1274 struct rb_node *nd;
1275
1276 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1277 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1278 callchain_node__init_have_children(node);
1279 }
1280}
1281
1282static void hist_entry__init_have_children(struct hist_entry *self)
1283{
1284 if (!self->init_have_children) {
1285 callchain__init_have_children(&self->sorted_chain);
1286 self->init_have_children = true;
1287 }
1288}
1289
1290static struct rb_node *hists__filter_entries(struct rb_node *nd)
1291{
1292 while (nd != NULL) {
1293 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1294 if (!h->filtered)
1295 return nd;
1296
1297 nd = rb_next(nd);
1298 }
1299
1300 return NULL;
1301}
1302
1303static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
1304{
1305 while (nd != NULL) {
1306 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1307 if (!h->filtered)
1308 return nd;
1309
1310 nd = rb_prev(nd);
1311 }
1312
1313 return NULL;
1314}
1315
1316static void ui_browser__hists_seek(struct ui_browser *self,
1317 off_t offset, int whence)
1318{
1319 struct hist_entry *h;
1320 struct rb_node *nd;
1321 bool first = true;
1322
1323 switch (whence) {
1324 case SEEK_SET:
1325 nd = hists__filter_entries(rb_first(self->entries));
1326 break;
1327 case SEEK_CUR:
1328 nd = self->first_visible_entry;
1329 goto do_offset;
1330 case SEEK_END:
1331 nd = hists__filter_prev_entries(rb_last(self->entries));
1332 first = false;
1333 break;
1334 default:
1335 return;
1336 }
1337
1338 /*
1339 * Moves not relative to the first visible entry invalidates its
1340 * row_offset:
1341 */
1342 h = rb_entry(self->first_visible_entry, struct hist_entry, rb_node);
1343 h->row_offset = 0;
1344
1345 /*
1346 * Here we have to check if nd is expanded (+), if it is we can't go
1347 * the next top level hist_entry, instead we must compute an offset of
1348 * what _not_ to show and not change the first visible entry.
1349 *
1350 * This offset increments when we are going from top to bottom and
1351 * decreases when we're going from bottom to top.
1352 *
1353 * As we don't have backpointers to the top level in the callchains
1354 * structure, we need to always print the whole hist_entry callchain,
1355 * skipping the first ones that are before the first visible entry
1356 * and stop when we printed enough lines to fill the screen.
1357 */
1358do_offset:
1359 if (offset > 0) {
1360 do {
1361 h = rb_entry(nd, struct hist_entry, rb_node);
1362 if (h->ms.unfolded) {
1363 u16 remaining = h->nr_rows - h->row_offset;
1364 if (offset > remaining) {
1365 offset -= remaining;
1366 h->row_offset = 0;
1367 } else {
1368 h->row_offset += offset;
1369 offset = 0;
1370 self->first_visible_entry = nd;
1371 break;
1372 }
1373 }
1374 nd = hists__filter_entries(rb_next(nd));
1375 if (nd == NULL)
1376 break;
1377 --offset;
1378 self->first_visible_entry = nd;
1379 } while (offset != 0);
1380 } else if (offset < 0) {
1381 while (1) {
1382 h = rb_entry(nd, struct hist_entry, rb_node);
1383 if (h->ms.unfolded) {
1384 if (first) {
1385 if (-offset > h->row_offset) {
1386 offset += h->row_offset;
1387 h->row_offset = 0;
1388 } else {
1389 h->row_offset += offset;
1390 offset = 0;
1391 self->first_visible_entry = nd;
1392 break;
1393 }
1394 } else {
1395 if (-offset > h->nr_rows) {
1396 offset += h->nr_rows;
1397 h->row_offset = 0;
1398 } else {
1399 h->row_offset = h->nr_rows + offset;
1400 offset = 0;
1401 self->first_visible_entry = nd;
1402 break;
1403 }
1404 }
1405 }
1406
1407 nd = hists__filter_prev_entries(rb_prev(nd));
1408 if (nd == NULL)
1409 break;
1410 ++offset;
1411 self->first_visible_entry = nd;
1412 if (offset == 0) {
1413 /*
1414 * Last unfiltered hist_entry, check if it is
1415 * unfolded, if it is then we should have
1416 * row_offset at its last entry.
1417 */
1418 h = rb_entry(nd, struct hist_entry, rb_node);
1419 if (h->ms.unfolded)
1420 h->row_offset = h->nr_rows;
1421 break;
1422 }
1423 first = false;
1424 }
1425 } else {
1426 self->first_visible_entry = nd;
1427 h = rb_entry(nd, struct hist_entry, rb_node);
1428 h->row_offset = 0;
1429 }
1430}
1431
1432static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
1433{
1434 int n = 0;
1435 struct rb_node *nd;
1436
1437 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
1438 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
1439 struct callchain_list *chain;
1440 char folded_sign = ' '; /* No children */
1441
1442 list_for_each_entry(chain, &child->val, list) {
1443 ++n;
1444 /* We need this because we may not have children */
1445 folded_sign = callchain_list__folded(chain);
1446 if (folded_sign == '+')
1447 break;
1448 }
1449
1450 if (folded_sign == '-') /* Have children and they're unfolded */
1451 n += callchain_node__count_rows_rb_tree(child);
1452 }
1453
1454 return n;
1455}
1456
1457static int callchain_node__count_rows(struct callchain_node *node)
1458{
1459 struct callchain_list *chain;
1460 bool unfolded = false;
1461 int n = 0;
1462
1463 list_for_each_entry(chain, &node->val, list) {
1464 ++n;
1465 unfolded = chain->ms.unfolded;
1466 }
1467
1468 if (unfolded)
1469 n += callchain_node__count_rows_rb_tree(node);
1470
1471 return n;
1472}
1473
1474static int callchain__count_rows(struct rb_root *chain)
1475{
1476 struct rb_node *nd;
1477 int n = 0;
1478
1479 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
1480 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
1481 n += callchain_node__count_rows(node);
1482 }
1483
1484 return n;
1485}
1486
1487static bool hist_browser__toggle_fold(struct hist_browser *self)
1488{
1489 if (map_symbol__toggle_fold(self->selection)) {
1490 struct hist_entry *he = self->he_selection;
1491
1492 hist_entry__init_have_children(he);
1493 self->hists->nr_entries -= he->nr_rows;
1494
1495 if (he->ms.unfolded)
1496 he->nr_rows = callchain__count_rows(&he->sorted_chain);
1497 else
1498 he->nr_rows = 0;
1499 self->hists->nr_entries += he->nr_rows;
1500 self->b.nr_entries = self->hists->nr_entries;
1501
1502 return true;
1503 }
1504
1505 /* If it doesn't have children, no toggling performed */
1506 return false;
1507}
1508
1509static int hist_browser__run(struct hist_browser *self, const char *title,
1510 struct newtExitStruct *es)
1511{
1512 char str[256], unit;
1513 unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE];
1514
1515 self->b.entries = &self->hists->entries;
1516 self->b.nr_entries = self->hists->nr_entries;
1517
1518 hist_browser__refresh_dimensions(self);
1519
1520 nr_events = convert_unit(nr_events, &unit);
1521 snprintf(str, sizeof(str), "Events: %lu%c ",
1522 nr_events, unit);
1523 newtDrawRootText(0, 0, str);
1524
1525 if (ui_browser__show(&self->b, title) < 0)
1526 return -1;
1527
1528 newtFormAddHotKey(self->b.form, 'A');
1529 newtFormAddHotKey(self->b.form, 'a');
1530 newtFormAddHotKey(self->b.form, '?');
1531 newtFormAddHotKey(self->b.form, 'h');
1532 newtFormAddHotKey(self->b.form, 'H');
1533 newtFormAddHotKey(self->b.form, 'd');
1534
1535 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
1536 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
1537 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
1538
1539 while (1) {
1540 ui_browser__run(&self->b, es);
1541
1542 if (es->reason != NEWT_EXIT_HOTKEY)
1543 break;
1544 switch (es->u.key) {
1545 case 'd': { /* Debug */
1546 static int seq;
1547 struct hist_entry *h = rb_entry(self->b.first_visible_entry,
1548 struct hist_entry, rb_node);
1549 ui_helpline__pop();
1550 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
1551 seq++, self->b.nr_entries,
1552 self->hists->nr_entries,
1553 self->b.height,
1554 self->b.index,
1555 self->b.first_visible_entry_idx,
1556 h->row_offset, h->nr_rows);
1557 }
1558 continue;
1559 case NEWT_KEY_ENTER:
1560 if (hist_browser__toggle_fold(self))
1561 break;
1562 /* fall thru */
1563 default:
1564 return 0;
1565 }
1566 }
1567 return 0;
1568}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9bf0f402ca73..4af5bd59cfd1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -602,8 +602,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
602 return EVT_FAILED; 602 return EVT_FAILED;
603 } 603 }
604 604
605 /* We should find a nice way to override the access type */ 605 /*
606 attr->bp_len = HW_BREAKPOINT_LEN_4; 606 * We should find a nice way to override the access length
607 * Provide some defaults for now
608 */
609 if (attr->bp_type == HW_BREAKPOINT_X)
610 attr->bp_len = sizeof(long);
611 else
612 attr->bp_len = HW_BREAKPOINT_LEN_4;
613
607 attr->type = PERF_TYPE_BREAKPOINT; 614 attr->type = PERF_TYPE_BREAKPOINT;
608 615
609 return EVT_HANDLED; 616 return EVT_HANDLED;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914c67095d96..2e665cb84055 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter 2 * probe-event.c : perf-probe definition to probe_events format converter
3 * 3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com> 4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 * 5 *
@@ -120,8 +120,11 @@ static int open_vmlinux(void)
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
121} 121}
122 122
123/* Convert trace point to probe point with debuginfo */ 123/*
124static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, 124 * Convert trace point to probe point with debuginfo
125 * Currently only handles kprobes.
126 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
125 struct perf_probe_point *pp) 128 struct perf_probe_point *pp)
126{ 129{
127 struct symbol *sym; 130 struct symbol *sym;
@@ -151,8 +154,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
151} 154}
152 155
153/* Try to find perf_probe_event with debuginfo */ 156/* Try to find perf_probe_event with debuginfo */
154static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, 157static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
155 struct kprobe_trace_event **tevs, 158 struct probe_trace_event **tevs,
156 int max_tevs) 159 int max_tevs)
157{ 160{
158 bool need_dwarf = perf_probe_event_need_dwarf(pev); 161 bool need_dwarf = perf_probe_event_need_dwarf(pev);
@@ -169,11 +172,11 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
169 } 172 }
170 173
171 /* Searching trace events corresponding to probe event */ 174 /* Searching trace events corresponding to probe event */
172 ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs); 175 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
173 close(fd); 176 close(fd);
174 177
175 if (ntevs > 0) { /* Succeeded to find trace events */ 178 if (ntevs > 0) { /* Succeeded to find trace events */
176 pr_debug("find %d kprobe_trace_events.\n", ntevs); 179 pr_debug("find %d probe_trace_events.\n", ntevs);
177 return ntevs; 180 return ntevs;
178 } 181 }
179 182
@@ -195,6 +198,65 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
195 return ntevs; 198 return ntevs;
196} 199}
197 200
201/*
202 * Find a src file from a DWARF tag path. Prepend optional source path prefix
203 * and chop off leading directories that do not exist. Result is passed back as
204 * a newly allocated path on success.
205 * Return 0 if file was found and readable, -errno otherwise.
206 */
207static int get_real_path(const char *raw_path, const char *comp_dir,
208 char **new_path)
209{
210 const char *prefix = symbol_conf.source_prefix;
211
212 if (!prefix) {
213 if (raw_path[0] != '/' && comp_dir)
214 /* If not an absolute path, try to use comp_dir */
215 prefix = comp_dir;
216 else {
217 if (access(raw_path, R_OK) == 0) {
218 *new_path = strdup(raw_path);
219 return 0;
220 } else
221 return -errno;
222 }
223 }
224
225 *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
226 if (!*new_path)
227 return -ENOMEM;
228
229 for (;;) {
230 sprintf(*new_path, "%s/%s", prefix, raw_path);
231
232 if (access(*new_path, R_OK) == 0)
233 return 0;
234
235 if (!symbol_conf.source_prefix)
236 /* In case of searching comp_dir, don't retry */
237 return -errno;
238
239 switch (errno) {
240 case ENAMETOOLONG:
241 case ENOENT:
242 case EROFS:
243 case EFAULT:
244 raw_path = strchr(++raw_path, '/');
245 if (!raw_path) {
246 free(*new_path);
247 *new_path = NULL;
248 return -ENOENT;
249 }
250 continue;
251
252 default:
253 free(*new_path);
254 *new_path = NULL;
255 return -errno;
256 }
257 }
258}
259
198#define LINEBUF_SIZE 256 260#define LINEBUF_SIZE 256
199#define NR_ADDITIONAL_LINES 2 261#define NR_ADDITIONAL_LINES 2
200 262
@@ -244,6 +306,7 @@ int show_line_range(struct line_range *lr)
244 struct line_node *ln; 306 struct line_node *ln;
245 FILE *fp; 307 FILE *fp;
246 int fd, ret; 308 int fd, ret;
309 char *tmp;
247 310
248 /* Search a line range */ 311 /* Search a line range */
249 ret = init_vmlinux(); 312 ret = init_vmlinux();
@@ -266,6 +329,15 @@ int show_line_range(struct line_range *lr)
266 return ret; 329 return ret;
267 } 330 }
268 331
332 /* Convert source file path */
333 tmp = lr->path;
334 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
335 free(tmp); /* Free old path */
336 if (ret < 0) {
337 pr_warning("Failed to find source file. (%d)\n", ret);
338 return ret;
339 }
340
269 setup_pager(); 341 setup_pager();
270 342
271 if (lr->function) 343 if (lr->function)
@@ -308,8 +380,8 @@ end:
308 380
309#else /* !DWARF_SUPPORT */ 381#else /* !DWARF_SUPPORT */
310 382
311static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, 383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
312 struct perf_probe_point *pp) 384 struct perf_probe_point *pp)
313{ 385{
314 pp->function = strdup(tp->symbol); 386 pp->function = strdup(tp->symbol);
315 if (pp->function == NULL) 387 if (pp->function == NULL)
@@ -320,8 +392,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
320 return 0; 392 return 0;
321} 393}
322 394
323static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, 395static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
324 struct kprobe_trace_event **tevs __unused, 396 struct probe_trace_event **tevs __unused,
325 int max_tevs __unused) 397 int max_tevs __unused)
326{ 398{
327 if (perf_probe_event_need_dwarf(pev)) { 399 if (perf_probe_event_need_dwarf(pev)) {
@@ -557,7 +629,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
557/* Parse perf-probe event argument */ 629/* Parse perf-probe event argument */
558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 630static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
559{ 631{
560 char *tmp; 632 char *tmp, *goodname;
561 struct perf_probe_arg_field **fieldp; 633 struct perf_probe_arg_field **fieldp;
562 634
563 pr_debug("parsing arg: %s into ", str); 635 pr_debug("parsing arg: %s into ", str);
@@ -580,7 +652,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
580 pr_debug("type:%s ", arg->type); 652 pr_debug("type:%s ", arg->type);
581 } 653 }
582 654
583 tmp = strpbrk(str, "-."); 655 tmp = strpbrk(str, "-.[");
584 if (!is_c_varname(str) || !tmp) { 656 if (!is_c_varname(str) || !tmp) {
585 /* A variable, register, symbol or special value */ 657 /* A variable, register, symbol or special value */
586 arg->var = strdup(str); 658 arg->var = strdup(str);
@@ -590,10 +662,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
590 return 0; 662 return 0;
591 } 663 }
592 664
593 /* Structure fields */ 665 /* Structure fields or array element */
594 arg->var = strndup(str, tmp - str); 666 arg->var = strndup(str, tmp - str);
595 if (arg->var == NULL) 667 if (arg->var == NULL)
596 return -ENOMEM; 668 return -ENOMEM;
669 goodname = arg->var;
597 pr_debug("%s, ", arg->var); 670 pr_debug("%s, ", arg->var);
598 fieldp = &arg->field; 671 fieldp = &arg->field;
599 672
@@ -601,22 +674,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
601 *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 674 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
602 if (*fieldp == NULL) 675 if (*fieldp == NULL)
603 return -ENOMEM; 676 return -ENOMEM;
604 if (*tmp == '.') { 677 if (*tmp == '[') { /* Array */
605 str = tmp + 1; 678 str = tmp;
606 (*fieldp)->ref = false; 679 (*fieldp)->index = strtol(str + 1, &tmp, 0);
607 } else if (tmp[1] == '>') {
608 str = tmp + 2;
609 (*fieldp)->ref = true; 680 (*fieldp)->ref = true;
610 } else { 681 if (*tmp != ']' || tmp == str + 1) {
611 semantic_error("Argument parse error: %s\n", str); 682 semantic_error("Array index must be a"
612 return -EINVAL; 683 " number.\n");
684 return -EINVAL;
685 }
686 tmp++;
687 if (*tmp == '\0')
688 tmp = NULL;
689 } else { /* Structure */
690 if (*tmp == '.') {
691 str = tmp + 1;
692 (*fieldp)->ref = false;
693 } else if (tmp[1] == '>') {
694 str = tmp + 2;
695 (*fieldp)->ref = true;
696 } else {
697 semantic_error("Argument parse error: %s\n",
698 str);
699 return -EINVAL;
700 }
701 tmp = strpbrk(str, "-.[");
613 } 702 }
614
615 tmp = strpbrk(str, "-.");
616 if (tmp) { 703 if (tmp) {
617 (*fieldp)->name = strndup(str, tmp - str); 704 (*fieldp)->name = strndup(str, tmp - str);
618 if ((*fieldp)->name == NULL) 705 if ((*fieldp)->name == NULL)
619 return -ENOMEM; 706 return -ENOMEM;
707 if (*str != '[')
708 goodname = (*fieldp)->name;
620 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 709 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
621 fieldp = &(*fieldp)->next; 710 fieldp = &(*fieldp)->next;
622 } 711 }
@@ -624,11 +713,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
624 (*fieldp)->name = strdup(str); 713 (*fieldp)->name = strdup(str);
625 if ((*fieldp)->name == NULL) 714 if ((*fieldp)->name == NULL)
626 return -ENOMEM; 715 return -ENOMEM;
716 if (*str != '[')
717 goodname = (*fieldp)->name;
627 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 718 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
628 719
629 /* If no name is specified, set the last field name */ 720 /* If no name is specified, set the last field name (not array index)*/
630 if (!arg->name) { 721 if (!arg->name) {
631 arg->name = strdup((*fieldp)->name); 722 arg->name = strdup(goodname);
632 if (arg->name == NULL) 723 if (arg->name == NULL)
633 return -ENOMEM; 724 return -ENOMEM;
634 } 725 }
@@ -693,16 +784,17 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
693 return false; 784 return false;
694} 785}
695 786
696/* Parse kprobe_events event into struct probe_point */ 787/* Parse probe_events event into struct probe_point */
697int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) 788static int parse_probe_trace_command(const char *cmd,
789 struct probe_trace_event *tev)
698{ 790{
699 struct kprobe_trace_point *tp = &tev->point; 791 struct probe_trace_point *tp = &tev->point;
700 char pr; 792 char pr;
701 char *p; 793 char *p;
702 int ret, i, argc; 794 int ret, i, argc;
703 char **argv; 795 char **argv;
704 796
705 pr_debug("Parsing kprobe_events: %s\n", cmd); 797 pr_debug("Parsing probe_events: %s\n", cmd);
706 argv = argv_split(cmd, &argc); 798 argv = argv_split(cmd, &argc);
707 if (!argv) { 799 if (!argv) {
708 pr_debug("Failed to split arguments.\n"); 800 pr_debug("Failed to split arguments.\n");
@@ -734,7 +826,7 @@ int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
734 tp->offset = 0; 826 tp->offset = 0;
735 827
736 tev->nargs = argc - 2; 828 tev->nargs = argc - 2;
737 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); 829 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
738 if (tev->args == NULL) { 830 if (tev->args == NULL) {
739 ret = -ENOMEM; 831 ret = -ENOMEM;
740 goto out; 832 goto out;
@@ -776,8 +868,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
776 len -= ret; 868 len -= ret;
777 869
778 while (field) { 870 while (field) {
779 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", 871 if (field->name[0] == '[')
780 field->name); 872 ret = e_snprintf(tmp, len, "%s", field->name);
873 else
874 ret = e_snprintf(tmp, len, "%s%s",
875 field->ref ? "->" : ".", field->name);
781 if (ret <= 0) 876 if (ret <= 0)
782 goto error; 877 goto error;
783 tmp += ret; 878 tmp += ret;
@@ -877,13 +972,13 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev)
877} 972}
878#endif 973#endif
879 974
880static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref, 975static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
881 char **buf, size_t *buflen, 976 char **buf, size_t *buflen,
882 int depth) 977 int depth)
883{ 978{
884 int ret; 979 int ret;
885 if (ref->next) { 980 if (ref->next) {
886 depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf, 981 depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
887 buflen, depth + 1); 982 buflen, depth + 1);
888 if (depth < 0) 983 if (depth < 0)
889 goto out; 984 goto out;
@@ -901,9 +996,10 @@ out:
901 996
902} 997}
903 998
904static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, 999static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
905 char *buf, size_t buflen) 1000 char *buf, size_t buflen)
906{ 1001{
1002 struct probe_trace_arg_ref *ref = arg->ref;
907 int ret, depth = 0; 1003 int ret, depth = 0;
908 char *tmp = buf; 1004 char *tmp = buf;
909 1005
@@ -917,16 +1013,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
917 buf += ret; 1013 buf += ret;
918 buflen -= ret; 1014 buflen -= ret;
919 1015
1016 /* Special case: @XXX */
1017 if (arg->value[0] == '@' && arg->ref)
1018 ref = ref->next;
1019
920 /* Dereferencing arguments */ 1020 /* Dereferencing arguments */
921 if (arg->ref) { 1021 if (ref) {
922 depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, 1022 depth = __synthesize_probe_trace_arg_ref(ref, &buf,
923 &buflen, 1); 1023 &buflen, 1);
924 if (depth < 0) 1024 if (depth < 0)
925 return depth; 1025 return depth;
926 } 1026 }
927 1027
928 /* Print argument value */ 1028 /* Print argument value */
929 ret = e_snprintf(buf, buflen, "%s", arg->value); 1029 if (arg->value[0] == '@' && arg->ref)
1030 ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1031 arg->ref->offset);
1032 else
1033 ret = e_snprintf(buf, buflen, "%s", arg->value);
930 if (ret < 0) 1034 if (ret < 0)
931 return ret; 1035 return ret;
932 buf += ret; 1036 buf += ret;
@@ -951,9 +1055,9 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
951 return buf - tmp; 1055 return buf - tmp;
952} 1056}
953 1057
954char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) 1058char *synthesize_probe_trace_command(struct probe_trace_event *tev)
955{ 1059{
956 struct kprobe_trace_point *tp = &tev->point; 1060 struct probe_trace_point *tp = &tev->point;
957 char *buf; 1061 char *buf;
958 int i, len, ret; 1062 int i, len, ret;
959 1063
@@ -969,7 +1073,7 @@ char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
969 goto error; 1073 goto error;
970 1074
971 for (i = 0; i < tev->nargs; i++) { 1075 for (i = 0; i < tev->nargs; i++) {
972 ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len, 1076 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
973 MAX_CMDLEN - len); 1077 MAX_CMDLEN - len);
974 if (ret <= 0) 1078 if (ret <= 0)
975 goto error; 1079 goto error;
@@ -982,7 +1086,7 @@ error:
982 return NULL; 1086 return NULL;
983} 1087}
984 1088
985int convert_to_perf_probe_event(struct kprobe_trace_event *tev, 1089static int convert_to_perf_probe_event(struct probe_trace_event *tev,
986 struct perf_probe_event *pev) 1090 struct perf_probe_event *pev)
987{ 1091{
988 char buf[64] = ""; 1092 char buf[64] = "";
@@ -995,7 +1099,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
995 return -ENOMEM; 1099 return -ENOMEM;
996 1100
997 /* Convert trace_point to probe_point */ 1101 /* Convert trace_point to probe_point */
998 ret = convert_to_perf_probe_point(&tev->point, &pev->point); 1102 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
999 if (ret < 0) 1103 if (ret < 0)
1000 return ret; 1104 return ret;
1001 1105
@@ -1008,7 +1112,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
1008 if (tev->args[i].name) 1112 if (tev->args[i].name)
1009 pev->args[i].name = strdup(tev->args[i].name); 1113 pev->args[i].name = strdup(tev->args[i].name);
1010 else { 1114 else {
1011 ret = synthesize_kprobe_trace_arg(&tev->args[i], 1115 ret = synthesize_probe_trace_arg(&tev->args[i],
1012 buf, 64); 1116 buf, 64);
1013 pev->args[i].name = strdup(buf); 1117 pev->args[i].name = strdup(buf);
1014 } 1118 }
@@ -1059,9 +1163,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
1059 memset(pev, 0, sizeof(*pev)); 1163 memset(pev, 0, sizeof(*pev));
1060} 1164}
1061 1165
1062void clear_kprobe_trace_event(struct kprobe_trace_event *tev) 1166static void clear_probe_trace_event(struct probe_trace_event *tev)
1063{ 1167{
1064 struct kprobe_trace_arg_ref *ref, *next; 1168 struct probe_trace_arg_ref *ref, *next;
1065 int i; 1169 int i;
1066 1170
1067 if (tev->event) 1171 if (tev->event)
@@ -1122,7 +1226,7 @@ static int open_kprobe_events(bool readwrite)
1122} 1226}
1123 1227
1124/* Get raw string list of current kprobe_events */ 1228/* Get raw string list of current kprobe_events */
1125static struct strlist *get_kprobe_trace_command_rawlist(int fd) 1229static struct strlist *get_probe_trace_command_rawlist(int fd)
1126{ 1230{
1127 int ret, idx; 1231 int ret, idx;
1128 FILE *fp; 1232 FILE *fp;
@@ -1190,7 +1294,7 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1190int show_perf_probe_events(void) 1294int show_perf_probe_events(void)
1191{ 1295{
1192 int fd, ret; 1296 int fd, ret;
1193 struct kprobe_trace_event tev; 1297 struct probe_trace_event tev;
1194 struct perf_probe_event pev; 1298 struct perf_probe_event pev;
1195 struct strlist *rawlist; 1299 struct strlist *rawlist;
1196 struct str_node *ent; 1300 struct str_node *ent;
@@ -1207,20 +1311,20 @@ int show_perf_probe_events(void)
1207 if (fd < 0) 1311 if (fd < 0)
1208 return fd; 1312 return fd;
1209 1313
1210 rawlist = get_kprobe_trace_command_rawlist(fd); 1314 rawlist = get_probe_trace_command_rawlist(fd);
1211 close(fd); 1315 close(fd);
1212 if (!rawlist) 1316 if (!rawlist)
1213 return -ENOENT; 1317 return -ENOENT;
1214 1318
1215 strlist__for_each(ent, rawlist) { 1319 strlist__for_each(ent, rawlist) {
1216 ret = parse_kprobe_trace_command(ent->s, &tev); 1320 ret = parse_probe_trace_command(ent->s, &tev);
1217 if (ret >= 0) { 1321 if (ret >= 0) {
1218 ret = convert_to_perf_probe_event(&tev, &pev); 1322 ret = convert_to_perf_probe_event(&tev, &pev);
1219 if (ret >= 0) 1323 if (ret >= 0)
1220 ret = show_perf_probe_event(&pev); 1324 ret = show_perf_probe_event(&pev);
1221 } 1325 }
1222 clear_perf_probe_event(&pev); 1326 clear_perf_probe_event(&pev);
1223 clear_kprobe_trace_event(&tev); 1327 clear_probe_trace_event(&tev);
1224 if (ret < 0) 1328 if (ret < 0)
1225 break; 1329 break;
1226 } 1330 }
@@ -1230,20 +1334,19 @@ int show_perf_probe_events(void)
1230} 1334}
1231 1335
1232/* Get current perf-probe event names */ 1336/* Get current perf-probe event names */
1233static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) 1337static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1234{ 1338{
1235 char buf[128]; 1339 char buf[128];
1236 struct strlist *sl, *rawlist; 1340 struct strlist *sl, *rawlist;
1237 struct str_node *ent; 1341 struct str_node *ent;
1238 struct kprobe_trace_event tev; 1342 struct probe_trace_event tev;
1239 int ret = 0; 1343 int ret = 0;
1240 1344
1241 memset(&tev, 0, sizeof(tev)); 1345 memset(&tev, 0, sizeof(tev));
1242 1346 rawlist = get_probe_trace_command_rawlist(fd);
1243 rawlist = get_kprobe_trace_command_rawlist(fd);
1244 sl = strlist__new(true, NULL); 1347 sl = strlist__new(true, NULL);
1245 strlist__for_each(ent, rawlist) { 1348 strlist__for_each(ent, rawlist) {
1246 ret = parse_kprobe_trace_command(ent->s, &tev); 1349 ret = parse_probe_trace_command(ent->s, &tev);
1247 if (ret < 0) 1350 if (ret < 0)
1248 break; 1351 break;
1249 if (include_group) { 1352 if (include_group) {
@@ -1253,7 +1356,7 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
1253 ret = strlist__add(sl, buf); 1356 ret = strlist__add(sl, buf);
1254 } else 1357 } else
1255 ret = strlist__add(sl, tev.event); 1358 ret = strlist__add(sl, tev.event);
1256 clear_kprobe_trace_event(&tev); 1359 clear_probe_trace_event(&tev);
1257 if (ret < 0) 1360 if (ret < 0)
1258 break; 1361 break;
1259 } 1362 }
@@ -1266,13 +1369,13 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
1266 return sl; 1369 return sl;
1267} 1370}
1268 1371
1269static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) 1372static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
1270{ 1373{
1271 int ret = 0; 1374 int ret = 0;
1272 char *buf = synthesize_kprobe_trace_command(tev); 1375 char *buf = synthesize_probe_trace_command(tev);
1273 1376
1274 if (!buf) { 1377 if (!buf) {
1275 pr_debug("Failed to synthesize kprobe trace event.\n"); 1378 pr_debug("Failed to synthesize probe trace event.\n");
1276 return -EINVAL; 1379 return -EINVAL;
1277 } 1380 }
1278 1381
@@ -1325,12 +1428,12 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
1325 return ret; 1428 return ret;
1326} 1429}
1327 1430
1328static int __add_kprobe_trace_events(struct perf_probe_event *pev, 1431static int __add_probe_trace_events(struct perf_probe_event *pev,
1329 struct kprobe_trace_event *tevs, 1432 struct probe_trace_event *tevs,
1330 int ntevs, bool allow_suffix) 1433 int ntevs, bool allow_suffix)
1331{ 1434{
1332 int i, fd, ret; 1435 int i, fd, ret;
1333 struct kprobe_trace_event *tev = NULL; 1436 struct probe_trace_event *tev = NULL;
1334 char buf[64]; 1437 char buf[64];
1335 const char *event, *group; 1438 const char *event, *group;
1336 struct strlist *namelist; 1439 struct strlist *namelist;
@@ -1339,7 +1442,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1339 if (fd < 0) 1442 if (fd < 0)
1340 return fd; 1443 return fd;
1341 /* Get current event names */ 1444 /* Get current event names */
1342 namelist = get_kprobe_trace_event_names(fd, false); 1445 namelist = get_probe_trace_event_names(fd, false);
1343 if (!namelist) { 1446 if (!namelist) {
1344 pr_debug("Failed to get current event list.\n"); 1447 pr_debug("Failed to get current event list.\n");
1345 return -EIO; 1448 return -EIO;
@@ -1374,7 +1477,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1374 ret = -ENOMEM; 1477 ret = -ENOMEM;
1375 break; 1478 break;
1376 } 1479 }
1377 ret = write_kprobe_trace_event(fd, tev); 1480 ret = write_probe_trace_event(fd, tev);
1378 if (ret < 0) 1481 if (ret < 0)
1379 break; 1482 break;
1380 /* Add added event name to namelist */ 1483 /* Add added event name to namelist */
@@ -1411,21 +1514,21 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev,
1411 return ret; 1514 return ret;
1412} 1515}
1413 1516
1414static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, 1517static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1415 struct kprobe_trace_event **tevs, 1518 struct probe_trace_event **tevs,
1416 int max_tevs) 1519 int max_tevs)
1417{ 1520{
1418 struct symbol *sym; 1521 struct symbol *sym;
1419 int ret = 0, i; 1522 int ret = 0, i;
1420 struct kprobe_trace_event *tev; 1523 struct probe_trace_event *tev;
1421 1524
1422 /* Convert perf_probe_event with debuginfo */ 1525 /* Convert perf_probe_event with debuginfo */
1423 ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs); 1526 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
1424 if (ret != 0) 1527 if (ret != 0)
1425 return ret; 1528 return ret;
1426 1529
1427 /* Allocate trace event buffer */ 1530 /* Allocate trace event buffer */
1428 tev = *tevs = zalloc(sizeof(struct kprobe_trace_event)); 1531 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1429 if (tev == NULL) 1532 if (tev == NULL)
1430 return -ENOMEM; 1533 return -ENOMEM;
1431 1534
@@ -1438,7 +1541,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1438 tev->point.offset = pev->point.offset; 1541 tev->point.offset = pev->point.offset;
1439 tev->nargs = pev->nargs; 1542 tev->nargs = pev->nargs;
1440 if (tev->nargs) { 1543 if (tev->nargs) {
1441 tev->args = zalloc(sizeof(struct kprobe_trace_arg) 1544 tev->args = zalloc(sizeof(struct probe_trace_arg)
1442 * tev->nargs); 1545 * tev->nargs);
1443 if (tev->args == NULL) { 1546 if (tev->args == NULL) {
1444 ret = -ENOMEM; 1547 ret = -ENOMEM;
@@ -1479,7 +1582,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
1479 1582
1480 return 1; 1583 return 1;
1481error: 1584error:
1482 clear_kprobe_trace_event(tev); 1585 clear_probe_trace_event(tev);
1483 free(tev); 1586 free(tev);
1484 *tevs = NULL; 1587 *tevs = NULL;
1485 return ret; 1588 return ret;
@@ -1487,7 +1590,7 @@ error:
1487 1590
1488struct __event_package { 1591struct __event_package {
1489 struct perf_probe_event *pev; 1592 struct perf_probe_event *pev;
1490 struct kprobe_trace_event *tevs; 1593 struct probe_trace_event *tevs;
1491 int ntevs; 1594 int ntevs;
1492}; 1595};
1493 1596
@@ -1510,7 +1613,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1510 for (i = 0; i < npevs; i++) { 1613 for (i = 0; i < npevs; i++) {
1511 pkgs[i].pev = &pevs[i]; 1614 pkgs[i].pev = &pevs[i];
1512 /* Convert with or without debuginfo */ 1615 /* Convert with or without debuginfo */
1513 ret = convert_to_kprobe_trace_events(pkgs[i].pev, 1616 ret = convert_to_probe_trace_events(pkgs[i].pev,
1514 &pkgs[i].tevs, max_tevs); 1617 &pkgs[i].tevs, max_tevs);
1515 if (ret < 0) 1618 if (ret < 0)
1516 goto end; 1619 goto end;
@@ -1519,24 +1622,24 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1519 1622
1520 /* Loop 2: add all events */ 1623 /* Loop 2: add all events */
1521 for (i = 0; i < npevs && ret >= 0; i++) 1624 for (i = 0; i < npevs && ret >= 0; i++)
1522 ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, 1625 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1523 pkgs[i].ntevs, force_add); 1626 pkgs[i].ntevs, force_add);
1524end: 1627end:
1525 /* Loop 3: cleanup trace events */ 1628 /* Loop 3: cleanup trace events */
1526 for (i = 0; i < npevs; i++) 1629 for (i = 0; i < npevs; i++)
1527 for (j = 0; j < pkgs[i].ntevs; j++) 1630 for (j = 0; j < pkgs[i].ntevs; j++)
1528 clear_kprobe_trace_event(&pkgs[i].tevs[j]); 1631 clear_probe_trace_event(&pkgs[i].tevs[j]);
1529 1632
1530 return ret; 1633 return ret;
1531} 1634}
1532 1635
1533static int __del_trace_kprobe_event(int fd, struct str_node *ent) 1636static int __del_trace_probe_event(int fd, struct str_node *ent)
1534{ 1637{
1535 char *p; 1638 char *p;
1536 char buf[128]; 1639 char buf[128];
1537 int ret; 1640 int ret;
1538 1641
1539 /* Convert from perf-probe event to trace-kprobe event */ 1642 /* Convert from perf-probe event to trace-probe event */
1540 ret = e_snprintf(buf, 128, "-:%s", ent->s); 1643 ret = e_snprintf(buf, 128, "-:%s", ent->s);
1541 if (ret < 0) 1644 if (ret < 0)
1542 goto error; 1645 goto error;
@@ -1562,7 +1665,7 @@ error:
1562 return ret; 1665 return ret;
1563} 1666}
1564 1667
1565static int del_trace_kprobe_event(int fd, const char *group, 1668static int del_trace_probe_event(int fd, const char *group,
1566 const char *event, struct strlist *namelist) 1669 const char *event, struct strlist *namelist)
1567{ 1670{
1568 char buf[128]; 1671 char buf[128];
@@ -1579,7 +1682,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
1579 strlist__for_each_safe(ent, n, namelist) 1682 strlist__for_each_safe(ent, n, namelist)
1580 if (strglobmatch(ent->s, buf)) { 1683 if (strglobmatch(ent->s, buf)) {
1581 found++; 1684 found++;
1582 ret = __del_trace_kprobe_event(fd, ent); 1685 ret = __del_trace_probe_event(fd, ent);
1583 if (ret < 0) 1686 if (ret < 0)
1584 break; 1687 break;
1585 strlist__remove(namelist, ent); 1688 strlist__remove(namelist, ent);
@@ -1588,7 +1691,7 @@ static int del_trace_kprobe_event(int fd, const char *group,
1588 ent = strlist__find(namelist, buf); 1691 ent = strlist__find(namelist, buf);
1589 if (ent) { 1692 if (ent) {
1590 found++; 1693 found++;
1591 ret = __del_trace_kprobe_event(fd, ent); 1694 ret = __del_trace_probe_event(fd, ent);
1592 if (ret >= 0) 1695 if (ret >= 0)
1593 strlist__remove(namelist, ent); 1696 strlist__remove(namelist, ent);
1594 } 1697 }
@@ -1612,7 +1715,7 @@ int del_perf_probe_events(struct strlist *dellist)
1612 return fd; 1715 return fd;
1613 1716
1614 /* Get current event names */ 1717 /* Get current event names */
1615 namelist = get_kprobe_trace_event_names(fd, true); 1718 namelist = get_probe_trace_event_names(fd, true);
1616 if (namelist == NULL) 1719 if (namelist == NULL)
1617 return -EINVAL; 1720 return -EINVAL;
1618 1721
@@ -1633,7 +1736,7 @@ int del_perf_probe_events(struct strlist *dellist)
1633 event = str; 1736 event = str;
1634 } 1737 }
1635 pr_debug("Group: %s, Event: %s\n", group, event); 1738 pr_debug("Group: %s, Event: %s\n", group, event);
1636 ret = del_trace_kprobe_event(fd, group, event, namelist); 1739 ret = del_trace_probe_event(fd, group, event, namelist);
1637 free(str); 1740 free(str);
1638 if (ret < 0) 1741 if (ret < 0)
1639 break; 1742 break;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e9db1a214ca4..5af39243a25b 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,33 +7,33 @@
7extern bool probe_event_dry_run; 7extern bool probe_event_dry_run;
8 8
9/* kprobe-tracer tracing point */ 9/* kprobe-tracer tracing point */
10struct kprobe_trace_point { 10struct probe_trace_point {
11 char *symbol; /* Base symbol */ 11 char *symbol; /* Base symbol */
12 unsigned long offset; /* Offset from symbol */ 12 unsigned long offset; /* Offset from symbol */
13 bool retprobe; /* Return probe flag */ 13 bool retprobe; /* Return probe flag */
14}; 14};
15 15
16/* kprobe-tracer tracing argument referencing offset */ 16/* probe-tracer tracing argument referencing offset */
17struct kprobe_trace_arg_ref { 17struct probe_trace_arg_ref {
18 struct kprobe_trace_arg_ref *next; /* Next reference */ 18 struct probe_trace_arg_ref *next; /* Next reference */
19 long offset; /* Offset value */ 19 long offset; /* Offset value */
20}; 20};
21 21
22/* kprobe-tracer tracing argument */ 22/* kprobe-tracer tracing argument */
23struct kprobe_trace_arg { 23struct probe_trace_arg {
24 char *name; /* Argument name */ 24 char *name; /* Argument name */
25 char *value; /* Base value */ 25 char *value; /* Base value */
26 char *type; /* Type name */ 26 char *type; /* Type name */
27 struct kprobe_trace_arg_ref *ref; /* Referencing offset */ 27 struct probe_trace_arg_ref *ref; /* Referencing offset */
28}; 28};
29 29
30/* kprobe-tracer tracing event (point + arg) */ 30/* kprobe-tracer tracing event (point + arg) */
31struct kprobe_trace_event { 31struct probe_trace_event {
32 char *event; /* Event name */ 32 char *event; /* Event name */
33 char *group; /* Group name */ 33 char *group; /* Group name */
34 struct kprobe_trace_point point; /* Trace point */ 34 struct probe_trace_point point; /* Trace point */
35 int nargs; /* Number of args */ 35 int nargs; /* Number of args */
36 struct kprobe_trace_arg *args; /* Arguments */ 36 struct probe_trace_arg *args; /* Arguments */
37}; 37};
38 38
39/* Perf probe probing point */ 39/* Perf probe probing point */
@@ -50,6 +50,7 @@ struct perf_probe_point {
50struct perf_probe_arg_field { 50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */ 51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */ 52 char *name; /* Name of the field */
53 long index; /* Array index number */
53 bool ref; /* Referencing flag */ 54 bool ref; /* Referencing flag */
54}; 55};
55 56
@@ -85,31 +86,25 @@ struct line_range {
85 int end; /* End line number */ 86 int end; /* End line number */
86 int offset; /* Start line offset */ 87 int offset; /* Start line offset */
87 char *path; /* Real path name */ 88 char *path; /* Real path name */
89 char *comp_dir; /* Compile directory */
88 struct list_head line_list; /* Visible lines */ 90 struct list_head line_list; /* Visible lines */
89}; 91};
90 92
91/* Command string to events */ 93/* Command string to events */
92extern int parse_perf_probe_command(const char *cmd, 94extern int parse_perf_probe_command(const char *cmd,
93 struct perf_probe_event *pev); 95 struct perf_probe_event *pev);
94extern int parse_kprobe_trace_command(const char *cmd,
95 struct kprobe_trace_event *tev);
96 96
97/* Events to command string */ 97/* Events to command string */
98extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); 98extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
99extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev); 99extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
100extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, 100extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
101 size_t len); 101 size_t len);
102 102
103/* Check the perf_probe_event needs debuginfo */ 103/* Check the perf_probe_event needs debuginfo */
104extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); 104extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
105 105
106/* Convert from kprobe_trace_event to perf_probe_event */
107extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
108 struct perf_probe_event *pev);
109
110/* Release event contents */ 106/* Release event contents */
111extern void clear_perf_probe_event(struct perf_probe_event *pev); 107extern void clear_perf_probe_event(struct perf_probe_event *pev);
112extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
113 108
114/* Command string to line-range */ 109/* Command string to line-range */
115extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 110extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d964cb199c67..840f1aabbb74 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -37,6 +37,7 @@
37#include "event.h" 37#include "event.h"
38#include "debug.h" 38#include "debug.h"
39#include "util.h" 39#include "util.h"
40#include "symbol.h"
40#include "probe-finder.h" 41#include "probe-finder.h"
41 42
42/* Kprobe tracer basic type is up to u64 */ 43/* Kprobe tracer basic type is up to u64 */
@@ -143,12 +144,21 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
143 return src; 144 return src;
144} 145}
145 146
147/* Get DW_AT_comp_dir (should be NULL with older gcc) */
148static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
149{
150 Dwarf_Attribute attr;
151 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
152 return NULL;
153 return dwarf_formstring(&attr);
154}
155
146/* Compare diename and tname */ 156/* Compare diename and tname */
147static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) 157static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
148{ 158{
149 const char *name; 159 const char *name;
150 name = dwarf_diename(dw_die); 160 name = dwarf_diename(dw_die);
151 return name ? strcmp(tname, name) : -1; 161 return name ? (strcmp(tname, name) == 0) : false;
152} 162}
153 163
154/* Get type die, but skip qualifiers and typedef */ 164/* Get type die, but skip qualifiers and typedef */
@@ -319,7 +329,7 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
319 tag = dwarf_tag(die_mem); 329 tag = dwarf_tag(die_mem);
320 if ((tag == DW_TAG_formal_parameter || 330 if ((tag == DW_TAG_formal_parameter ||
321 tag == DW_TAG_variable) && 331 tag == DW_TAG_variable) &&
322 (die_compare_name(die_mem, name) == 0)) 332 die_compare_name(die_mem, name))
323 return DIE_FIND_CB_FOUND; 333 return DIE_FIND_CB_FOUND;
324 334
325 return DIE_FIND_CB_CONTINUE; 335 return DIE_FIND_CB_CONTINUE;
@@ -338,7 +348,7 @@ static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
338 const char *name = data; 348 const char *name = data;
339 349
340 if ((dwarf_tag(die_mem) == DW_TAG_member) && 350 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
341 (die_compare_name(die_mem, name) == 0)) 351 die_compare_name(die_mem, name))
342 return DIE_FIND_CB_FOUND; 352 return DIE_FIND_CB_FOUND;
343 353
344 return DIE_FIND_CB_SIBLING; 354 return DIE_FIND_CB_SIBLING;
@@ -356,14 +366,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
356 * Probe finder related functions 366 * Probe finder related functions
357 */ 367 */
358 368
369static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
370{
371 struct probe_trace_arg_ref *ref;
372 ref = zalloc(sizeof(struct probe_trace_arg_ref));
373 if (ref != NULL)
374 ref->offset = offs;
375 return ref;
376}
377
359/* Show a location */ 378/* Show a location */
360static int convert_location(Dwarf_Op *op, struct probe_finder *pf) 379static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
361{ 380{
381 Dwarf_Attribute attr;
382 Dwarf_Op *op;
383 size_t nops;
362 unsigned int regn; 384 unsigned int regn;
363 Dwarf_Word offs = 0; 385 Dwarf_Word offs = 0;
364 bool ref = false; 386 bool ref = false;
365 const char *regs; 387 const char *regs;
366 struct kprobe_trace_arg *tvar = pf->tvar; 388 struct probe_trace_arg *tvar = pf->tvar;
389 int ret;
390
391 /* TODO: handle more than 1 exprs */
392 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
393 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
394 nops == 0) {
395 /* TODO: Support const_value */
396 pr_err("Failed to find the location of %s at this address.\n"
397 " Perhaps, it has been optimized out.\n", pf->pvar->var);
398 return -ENOENT;
399 }
400
401 if (op->atom == DW_OP_addr) {
402 /* Static variables on memory (not stack), make @varname */
403 ret = strlen(dwarf_diename(vr_die));
404 tvar->value = zalloc(ret + 2);
405 if (tvar->value == NULL)
406 return -ENOMEM;
407 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
408 tvar->ref = alloc_trace_arg_ref((long)offs);
409 if (tvar->ref == NULL)
410 return -ENOMEM;
411 return 0;
412 }
367 413
368 /* If this is based on frame buffer, set the offset */ 414 /* If this is based on frame buffer, set the offset */
369 if (op->atom == DW_OP_fbreg) { 415 if (op->atom == DW_OP_fbreg) {
@@ -405,27 +451,72 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
405 return -ENOMEM; 451 return -ENOMEM;
406 452
407 if (ref) { 453 if (ref) {
408 tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 454 tvar->ref = alloc_trace_arg_ref((long)offs);
409 if (tvar->ref == NULL) 455 if (tvar->ref == NULL)
410 return -ENOMEM; 456 return -ENOMEM;
411 tvar->ref->offset = (long)offs;
412 } 457 }
413 return 0; 458 return 0;
414} 459}
415 460
416static int convert_variable_type(Dwarf_Die *vr_die, 461static int convert_variable_type(Dwarf_Die *vr_die,
417 struct kprobe_trace_arg *targ) 462 struct probe_trace_arg *tvar,
463 const char *cast)
418{ 464{
465 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
419 Dwarf_Die type; 466 Dwarf_Die type;
420 char buf[16]; 467 char buf[16];
421 int ret; 468 int ret;
422 469
470 /* TODO: check all types */
471 if (cast && strcmp(cast, "string") != 0) {
472 /* Non string type is OK */
473 tvar->type = strdup(cast);
474 return (tvar->type == NULL) ? -ENOMEM : 0;
475 }
476
423 if (die_get_real_type(vr_die, &type) == NULL) { 477 if (die_get_real_type(vr_die, &type) == NULL) {
424 pr_warning("Failed to get a type information of %s.\n", 478 pr_warning("Failed to get a type information of %s.\n",
425 dwarf_diename(vr_die)); 479 dwarf_diename(vr_die));
426 return -ENOENT; 480 return -ENOENT;
427 } 481 }
428 482
483 pr_debug("%s type is %s.\n",
484 dwarf_diename(vr_die), dwarf_diename(&type));
485
486 if (cast && strcmp(cast, "string") == 0) { /* String type */
487 ret = dwarf_tag(&type);
488 if (ret != DW_TAG_pointer_type &&
489 ret != DW_TAG_array_type) {
490 pr_warning("Failed to cast into string: "
491 "%s(%s) is not a pointer nor array.",
492 dwarf_diename(vr_die), dwarf_diename(&type));
493 return -EINVAL;
494 }
495 if (ret == DW_TAG_pointer_type) {
496 if (die_get_real_type(&type, &type) == NULL) {
497 pr_warning("Failed to get a type information.");
498 return -ENOENT;
499 }
500 while (*ref_ptr)
501 ref_ptr = &(*ref_ptr)->next;
502 /* Add new reference with offset +0 */
503 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
504 if (*ref_ptr == NULL) {
505 pr_warning("Out of memory error\n");
506 return -ENOMEM;
507 }
508 }
509 if (!die_compare_name(&type, "char") &&
510 !die_compare_name(&type, "unsigned char")) {
511 pr_warning("Failed to cast into string: "
512 "%s is not (unsigned) char *.",
513 dwarf_diename(vr_die));
514 return -EINVAL;
515 }
516 tvar->type = strdup(cast);
517 return (tvar->type == NULL) ? -ENOMEM : 0;
518 }
519
429 ret = die_get_byte_size(&type) * 8; 520 ret = die_get_byte_size(&type) * 8;
430 if (ret) { 521 if (ret) {
431 /* Check the bitwidth */ 522 /* Check the bitwidth */
@@ -445,8 +536,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
445 strerror(-ret)); 536 strerror(-ret));
446 return ret; 537 return ret;
447 } 538 }
448 targ->type = strdup(buf); 539 tvar->type = strdup(buf);
449 if (targ->type == NULL) 540 if (tvar->type == NULL)
450 return -ENOMEM; 541 return -ENOMEM;
451 } 542 }
452 return 0; 543 return 0;
@@ -454,22 +545,50 @@ static int convert_variable_type(Dwarf_Die *vr_die,
454 545
455static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 546static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
456 struct perf_probe_arg_field *field, 547 struct perf_probe_arg_field *field,
457 struct kprobe_trace_arg_ref **ref_ptr, 548 struct probe_trace_arg_ref **ref_ptr,
458 Dwarf_Die *die_mem) 549 Dwarf_Die *die_mem)
459{ 550{
460 struct kprobe_trace_arg_ref *ref = *ref_ptr; 551 struct probe_trace_arg_ref *ref = *ref_ptr;
461 Dwarf_Die type; 552 Dwarf_Die type;
462 Dwarf_Word offs; 553 Dwarf_Word offs;
463 int ret; 554 int ret, tag;
464 555
465 pr_debug("converting %s in %s\n", field->name, varname); 556 pr_debug("converting %s in %s\n", field->name, varname);
466 if (die_get_real_type(vr_die, &type) == NULL) { 557 if (die_get_real_type(vr_die, &type) == NULL) {
467 pr_warning("Failed to get the type of %s.\n", varname); 558 pr_warning("Failed to get the type of %s.\n", varname);
468 return -ENOENT; 559 return -ENOENT;
469 } 560 }
470 561 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
471 /* Check the pointer and dereference */ 562 tag = dwarf_tag(&type);
472 if (dwarf_tag(&type) == DW_TAG_pointer_type) { 563
564 if (field->name[0] == '[' &&
565 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
566 if (field->next)
567 /* Save original type for next field */
568 memcpy(die_mem, &type, sizeof(*die_mem));
569 /* Get the type of this array */
570 if (die_get_real_type(&type, &type) == NULL) {
571 pr_warning("Failed to get the type of %s.\n", varname);
572 return -ENOENT;
573 }
574 pr_debug2("Array real type: (%x)\n",
575 (unsigned)dwarf_dieoffset(&type));
576 if (tag == DW_TAG_pointer_type) {
577 ref = zalloc(sizeof(struct probe_trace_arg_ref));
578 if (ref == NULL)
579 return -ENOMEM;
580 if (*ref_ptr)
581 (*ref_ptr)->next = ref;
582 else
583 *ref_ptr = ref;
584 }
585 ref->offset += die_get_byte_size(&type) * field->index;
586 if (!field->next)
587 /* Save vr_die for converting types */
588 memcpy(die_mem, vr_die, sizeof(*die_mem));
589 goto next;
590 } else if (tag == DW_TAG_pointer_type) {
591 /* Check the pointer and dereference */
473 if (!field->ref) { 592 if (!field->ref) {
474 pr_err("Semantic error: %s must be referred by '->'\n", 593 pr_err("Semantic error: %s must be referred by '->'\n",
475 field->name); 594 field->name);
@@ -486,7 +605,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
486 return -EINVAL; 605 return -EINVAL;
487 } 606 }
488 607
489 ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 608 ref = zalloc(sizeof(struct probe_trace_arg_ref));
490 if (ref == NULL) 609 if (ref == NULL)
491 return -ENOMEM; 610 return -ENOMEM;
492 if (*ref_ptr) 611 if (*ref_ptr)
@@ -495,10 +614,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
495 *ref_ptr = ref; 614 *ref_ptr = ref;
496 } else { 615 } else {
497 /* Verify it is a data structure */ 616 /* Verify it is a data structure */
498 if (dwarf_tag(&type) != DW_TAG_structure_type) { 617 if (tag != DW_TAG_structure_type) {
499 pr_warning("%s is not a data structure.\n", varname); 618 pr_warning("%s is not a data structure.\n", varname);
500 return -EINVAL; 619 return -EINVAL;
501 } 620 }
621 if (field->name[0] == '[') {
622 pr_err("Semantic error: %s is not a pointor nor array.",
623 varname);
624 return -EINVAL;
625 }
502 if (field->ref) { 626 if (field->ref) {
503 pr_err("Semantic error: %s must be referred by '.'\n", 627 pr_err("Semantic error: %s must be referred by '.'\n",
504 field->name); 628 field->name);
@@ -525,6 +649,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
525 } 649 }
526 ref->offset += (long)offs; 650 ref->offset += (long)offs;
527 651
652next:
528 /* Converting next field */ 653 /* Converting next field */
529 if (field->next) 654 if (field->next)
530 return convert_variable_fields(die_mem, field->name, 655 return convert_variable_fields(die_mem, field->name,
@@ -536,51 +661,32 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
536/* Show a variables in kprobe event format */ 661/* Show a variables in kprobe event format */
537static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 662static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
538{ 663{
539 Dwarf_Attribute attr;
540 Dwarf_Die die_mem; 664 Dwarf_Die die_mem;
541 Dwarf_Op *expr;
542 size_t nexpr;
543 int ret; 665 int ret;
544 666
545 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 667 pr_debug("Converting variable %s into trace event.\n",
546 goto error; 668 dwarf_diename(vr_die));
547 /* TODO: handle more than 1 exprs */
548 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
549 if (ret <= 0 || nexpr == 0)
550 goto error;
551 669
552 ret = convert_location(expr, pf); 670 ret = convert_variable_location(vr_die, pf);
553 if (ret == 0 && pf->pvar->field) { 671 if (ret == 0 && pf->pvar->field) {
554 ret = convert_variable_fields(vr_die, pf->pvar->var, 672 ret = convert_variable_fields(vr_die, pf->pvar->var,
555 pf->pvar->field, &pf->tvar->ref, 673 pf->pvar->field, &pf->tvar->ref,
556 &die_mem); 674 &die_mem);
557 vr_die = &die_mem; 675 vr_die = &die_mem;
558 } 676 }
559 if (ret == 0) { 677 if (ret == 0)
560 if (pf->pvar->type) { 678 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
561 pf->tvar->type = strdup(pf->pvar->type);
562 if (pf->tvar->type == NULL)
563 ret = -ENOMEM;
564 } else
565 ret = convert_variable_type(vr_die, pf->tvar);
566 }
567 /* *expr will be cached in libdw. Don't free it. */ 679 /* *expr will be cached in libdw. Don't free it. */
568 return ret; 680 return ret;
569error:
570 /* TODO: Support const_value */
571 pr_err("Failed to find the location of %s at this address.\n"
572 " Perhaps, it has been optimized out.\n", pf->pvar->var);
573 return -ENOENT;
574} 681}
575 682
576/* Find a variable in a subprogram die */ 683/* Find a variable in a subprogram die */
577static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 684static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
578{ 685{
579 Dwarf_Die vr_die; 686 Dwarf_Die vr_die, *scopes;
580 char buf[32], *ptr; 687 char buf[32], *ptr;
581 int ret; 688 int ret, nscopes;
582 689
583 /* TODO: Support arrays */
584 if (pf->pvar->name) 690 if (pf->pvar->name)
585 pf->tvar->name = strdup(pf->pvar->name); 691 pf->tvar->name = strdup(pf->pvar->name);
586 else { 692 else {
@@ -607,18 +713,32 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
607 pr_debug("Searching '%s' variable in context.\n", 713 pr_debug("Searching '%s' variable in context.\n",
608 pf->pvar->var); 714 pf->pvar->var);
609 /* Search child die for local variables and parameters. */ 715 /* Search child die for local variables and parameters. */
610 if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { 716 if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
717 ret = convert_variable(&vr_die, pf);
718 else {
719 /* Search upper class */
720 nscopes = dwarf_getscopes_die(sp_die, &scopes);
721 if (nscopes > 0) {
722 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
723 0, NULL, 0, 0, &vr_die);
724 if (ret >= 0)
725 ret = convert_variable(&vr_die, pf);
726 else
727 ret = -ENOENT;
728 free(scopes);
729 } else
730 ret = -ENOENT;
731 }
732 if (ret < 0)
611 pr_warning("Failed to find '%s' in this function.\n", 733 pr_warning("Failed to find '%s' in this function.\n",
612 pf->pvar->var); 734 pf->pvar->var);
613 return -ENOENT; 735 return ret;
614 }
615 return convert_variable(&vr_die, pf);
616} 736}
617 737
618/* Show a probe point to output buffer */ 738/* Show a probe point to output buffer */
619static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 739static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
620{ 740{
621 struct kprobe_trace_event *tev; 741 struct probe_trace_event *tev;
622 Dwarf_Addr eaddr; 742 Dwarf_Addr eaddr;
623 Dwarf_Die die_mem; 743 Dwarf_Die die_mem;
624 const char *name; 744 const char *name;
@@ -683,7 +803,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
683 803
684 /* Find each argument */ 804 /* Find each argument */
685 tev->nargs = pf->pev->nargs; 805 tev->nargs = pf->pev->nargs;
686 tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); 806 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
687 if (tev->args == NULL) 807 if (tev->args == NULL)
688 return -ENOMEM; 808 return -ENOMEM;
689 for (i = 0; i < pf->pev->nargs; i++) { 809 for (i = 0; i < pf->pev->nargs; i++) {
@@ -897,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
897 1017
898 /* Check tag and diename */ 1018 /* Check tag and diename */
899 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 1019 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
900 die_compare_name(sp_die, pp->function) != 0) 1020 !die_compare_name(sp_die, pp->function))
901 return DWARF_CB_OK; 1021 return DWARF_CB_OK;
902 1022
903 pf->fname = dwarf_decl_file(sp_die); 1023 pf->fname = dwarf_decl_file(sp_die);
@@ -940,9 +1060,9 @@ static int find_probe_point_by_func(struct probe_finder *pf)
940 return _param.retval; 1060 return _param.retval;
941} 1061}
942 1062
943/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ 1063/* Find probe_trace_events specified by perf_probe_event from debuginfo */
944int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, 1064int find_probe_trace_events(int fd, struct perf_probe_event *pev,
945 struct kprobe_trace_event **tevs, int max_tevs) 1065 struct probe_trace_event **tevs, int max_tevs)
946{ 1066{
947 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1067 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
948 struct perf_probe_point *pp = &pev->point; 1068 struct perf_probe_point *pp = &pev->point;
@@ -952,7 +1072,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
952 Dwarf *dbg; 1072 Dwarf *dbg;
953 int ret = 0; 1073 int ret = 0;
954 1074
955 pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs); 1075 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
956 if (pf.tevs == NULL) 1076 if (pf.tevs == NULL)
957 return -ENOMEM; 1077 return -ENOMEM;
958 *tevs = pf.tevs; 1078 *tevs = pf.tevs;
@@ -1096,7 +1216,7 @@ end:
1096static int line_range_add_line(const char *src, unsigned int lineno, 1216static int line_range_add_line(const char *src, unsigned int lineno,
1097 struct line_range *lr) 1217 struct line_range *lr)
1098{ 1218{
1099 /* Copy real path */ 1219 /* Copy source path */
1100 if (!lr->path) { 1220 if (!lr->path) {
1101 lr->path = strdup(src); 1221 lr->path = strdup(src);
1102 if (lr->path == NULL) 1222 if (lr->path == NULL)
@@ -1220,7 +1340,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1220 struct line_range *lr = lf->lr; 1340 struct line_range *lr = lf->lr;
1221 1341
1222 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1342 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1223 die_compare_name(sp_die, lr->function) == 0) { 1343 die_compare_name(sp_die, lr->function)) {
1224 lf->fname = dwarf_decl_file(sp_die); 1344 lf->fname = dwarf_decl_file(sp_die);
1225 dwarf_decl_line(sp_die, &lr->offset); 1345 dwarf_decl_line(sp_die, &lr->offset);
1226 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1346 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
@@ -1263,6 +1383,7 @@ int find_line_range(int fd, struct line_range *lr)
1263 size_t cuhl; 1383 size_t cuhl;
1264 Dwarf_Die *diep; 1384 Dwarf_Die *diep;
1265 Dwarf *dbg; 1385 Dwarf *dbg;
1386 const char *comp_dir;
1266 1387
1267 dbg = dwarf_begin(fd, DWARF_C_READ); 1388 dbg = dwarf_begin(fd, DWARF_C_READ);
1268 if (!dbg) { 1389 if (!dbg) {
@@ -1298,7 +1419,18 @@ int find_line_range(int fd, struct line_range *lr)
1298 } 1419 }
1299 off = noff; 1420 off = noff;
1300 } 1421 }
1301 pr_debug("path: %lx\n", (unsigned long)lr->path); 1422
1423 /* Store comp_dir */
1424 if (lf.found) {
1425 comp_dir = cu_get_comp_dir(&lf.cu_die);
1426 if (comp_dir) {
1427 lr->comp_dir = strdup(comp_dir);
1428 if (!lr->comp_dir)
1429 ret = -ENOMEM;
1430 }
1431 }
1432
1433 pr_debug("path: %s\n", lr->path);
1302 dwarf_end(dbg); 1434 dwarf_end(dbg);
1303 1435
1304 return (ret < 0) ? ret : lf.found; 1436 return (ret < 0) ? ret : lf.found;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index e1f61dcd18ff..4507d519f183 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -16,9 +16,9 @@ static inline int is_c_varname(const char *name)
16} 16}
17 17
18#ifdef DWARF_SUPPORT 18#ifdef DWARF_SUPPORT
19/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ 19/* Find probe_trace_events specified by perf_probe_event from debuginfo */
20extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, 20extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
21 struct kprobe_trace_event **tevs, 21 struct probe_trace_event **tevs,
22 int max_tevs); 22 int max_tevs);
23 23
24/* Find a perf_probe_point from debuginfo */ 24/* Find a perf_probe_point from debuginfo */
@@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr);
33 33
34struct probe_finder { 34struct probe_finder {
35 struct perf_probe_event *pev; /* Target probe event */ 35 struct perf_probe_event *pev; /* Target probe event */
36 struct kprobe_trace_event *tevs; /* Result trace events */ 36 struct probe_trace_event *tevs; /* Result trace events */
37 int ntevs; /* Number of trace events */ 37 int ntevs; /* Number of trace events */
38 int max_tevs; /* Max number of trace events */ 38 int max_tevs; /* Max number of trace events */
39 39
@@ -50,7 +50,7 @@ struct probe_finder {
50#endif 50#endif
51 Dwarf_Op *fb_ops; /* Frame base attribute */ 51 Dwarf_Op *fb_ops; /* Frame base attribute */
52 struct perf_probe_arg *pvar; /* Current target variable */ 52 struct perf_probe_arg *pvar; /* Current target variable */
53 struct kprobe_trace_arg *tvar; /* Current result variable */ 53 struct probe_trace_arg *tvar; /* Current result variable */
54}; 54};
55 55
56struct line_finder { 56struct line_finder {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c422cd676313..fa9d652c2dc3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -27,8 +27,10 @@ static int perf_session__open(struct perf_session *self, bool force)
27 27
28 self->fd = open(self->filename, O_RDONLY); 28 self->fd = open(self->filename, O_RDONLY);
29 if (self->fd < 0) { 29 if (self->fd < 0) {
30 pr_err("failed to open file: %s", self->filename); 30 int err = errno;
31 if (!strcmp(self->filename, "perf.data")) 31
32 pr_err("failed to open %s: %s", self->filename, strerror(err));
33 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
32 pr_err(" (try 'perf record' first)"); 34 pr_err(" (try 'perf record' first)");
33 pr_err("\n"); 35 pr_err("\n");
34 return -errno; 36 return -errno;
@@ -77,6 +79,12 @@ int perf_session__create_kernel_maps(struct perf_session *self)
77 return ret; 79 return ret;
78} 80}
79 81
82static void perf_session__destroy_kernel_maps(struct perf_session *self)
83{
84 machine__destroy_kernel_maps(&self->host_machine);
85 machines__destroy_guest_kernel_maps(&self->machines);
86}
87
80struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe) 88struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
81{ 89{
82 size_t len = filename ? strlen(filename) + 1 : 0; 90 size_t len = filename ? strlen(filename) + 1 : 0;
@@ -94,8 +102,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
94 self->hists_tree = RB_ROOT; 102 self->hists_tree = RB_ROOT;
95 self->last_match = NULL; 103 self->last_match = NULL;
96 self->mmap_window = 32; 104 self->mmap_window = 32;
97 self->cwd = NULL;
98 self->cwdlen = 0;
99 self->machines = RB_ROOT; 105 self->machines = RB_ROOT;
100 self->repipe = repipe; 106 self->repipe = repipe;
101 INIT_LIST_HEAD(&self->ordered_samples.samples_head); 107 INIT_LIST_HEAD(&self->ordered_samples.samples_head);
@@ -124,16 +130,43 @@ out_delete:
124 return NULL; 130 return NULL;
125} 131}
126 132
133static void perf_session__delete_dead_threads(struct perf_session *self)
134{
135 struct thread *n, *t;
136
137 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
138 list_del(&t->node);
139 thread__delete(t);
140 }
141}
142
143static void perf_session__delete_threads(struct perf_session *self)
144{
145 struct rb_node *nd = rb_first(&self->threads);
146
147 while (nd) {
148 struct thread *t = rb_entry(nd, struct thread, rb_node);
149
150 rb_erase(&t->rb_node, &self->threads);
151 nd = rb_next(nd);
152 thread__delete(t);
153 }
154}
155
127void perf_session__delete(struct perf_session *self) 156void perf_session__delete(struct perf_session *self)
128{ 157{
129 perf_header__exit(&self->header); 158 perf_header__exit(&self->header);
159 perf_session__destroy_kernel_maps(self);
160 perf_session__delete_dead_threads(self);
161 perf_session__delete_threads(self);
162 machine__exit(&self->host_machine);
130 close(self->fd); 163 close(self->fd);
131 free(self->cwd);
132 free(self); 164 free(self);
133} 165}
134 166
135void perf_session__remove_thread(struct perf_session *self, struct thread *th) 167void perf_session__remove_thread(struct perf_session *self, struct thread *th)
136{ 168{
169 self->last_match = NULL;
137 rb_erase(&th->rb_node, &self->threads); 170 rb_erase(&th->rb_node, &self->threads);
138 /* 171 /*
139 * We may have references to this thread, for instance in some hist_entry 172 * We may have references to this thread, for instance in some hist_entry
@@ -830,23 +863,6 @@ int perf_session__process_events(struct perf_session *self,
830 if (perf_session__register_idle_thread(self) == NULL) 863 if (perf_session__register_idle_thread(self) == NULL)
831 return -ENOMEM; 864 return -ENOMEM;
832 865
833 if (!symbol_conf.full_paths) {
834 char bf[PATH_MAX];
835
836 if (getcwd(bf, sizeof(bf)) == NULL) {
837 err = -errno;
838out_getcwd_err:
839 pr_err("failed to get the current directory\n");
840 goto out_err;
841 }
842 self->cwd = strdup(bf);
843 if (self->cwd == NULL) {
844 err = -ENOMEM;
845 goto out_getcwd_err;
846 }
847 self->cwdlen = strlen(self->cwd);
848 }
849
850 if (!self->fd_pipe) 866 if (!self->fd_pipe)
851 err = __perf_session__process_events(self, 867 err = __perf_session__process_events(self,
852 self->header.data_offset, 868 self->header.data_offset,
@@ -854,7 +870,7 @@ out_getcwd_err:
854 self->size, ops); 870 self->size, ops);
855 else 871 else
856 err = __perf_session__process_pipe_events(self, ops); 872 err = __perf_session__process_pipe_events(self, ops);
857out_err: 873
858 return err; 874 return err;
859} 875}
860 876
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2316cb5a4116..1c61a4f4aa8a 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,4 +1,5 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h"
2 3
3regex_t parent_regex; 4regex_t parent_regex;
4const char default_parent_pattern[] = "^sys_|^do_page_fault"; 5const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -10,10 +11,6 @@ int sort__has_parent = 0;
10 11
11enum sort_type sort__first_dimension; 12enum sort_type sort__first_dimension;
12 13
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep; 14char * field_sep;
18 15
19LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
@@ -28,12 +25,14 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
28 size_t size, unsigned int width); 25 size_t size, unsigned int width);
29static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, 26static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
30 size_t size, unsigned int width); 27 size_t size, unsigned int width);
28static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
29 size_t size, unsigned int width);
31 30
32struct sort_entry sort_thread = { 31struct sort_entry sort_thread = {
33 .se_header = "Command: Pid", 32 .se_header = "Command: Pid",
34 .se_cmp = sort__thread_cmp, 33 .se_cmp = sort__thread_cmp,
35 .se_snprintf = hist_entry__thread_snprintf, 34 .se_snprintf = hist_entry__thread_snprintf,
36 .se_width = &threads__col_width, 35 .se_width_idx = HISTC_THREAD,
37}; 36};
38 37
39struct sort_entry sort_comm = { 38struct sort_entry sort_comm = {
@@ -41,27 +40,35 @@ struct sort_entry sort_comm = {
41 .se_cmp = sort__comm_cmp, 40 .se_cmp = sort__comm_cmp,
42 .se_collapse = sort__comm_collapse, 41 .se_collapse = sort__comm_collapse,
43 .se_snprintf = hist_entry__comm_snprintf, 42 .se_snprintf = hist_entry__comm_snprintf,
44 .se_width = &comms__col_width, 43 .se_width_idx = HISTC_COMM,
45}; 44};
46 45
47struct sort_entry sort_dso = { 46struct sort_entry sort_dso = {
48 .se_header = "Shared Object", 47 .se_header = "Shared Object",
49 .se_cmp = sort__dso_cmp, 48 .se_cmp = sort__dso_cmp,
50 .se_snprintf = hist_entry__dso_snprintf, 49 .se_snprintf = hist_entry__dso_snprintf,
51 .se_width = &dsos__col_width, 50 .se_width_idx = HISTC_DSO,
52}; 51};
53 52
54struct sort_entry sort_sym = { 53struct sort_entry sort_sym = {
55 .se_header = "Symbol", 54 .se_header = "Symbol",
56 .se_cmp = sort__sym_cmp, 55 .se_cmp = sort__sym_cmp,
57 .se_snprintf = hist_entry__sym_snprintf, 56 .se_snprintf = hist_entry__sym_snprintf,
57 .se_width_idx = HISTC_SYMBOL,
58}; 58};
59 59
60struct sort_entry sort_parent = { 60struct sort_entry sort_parent = {
61 .se_header = "Parent symbol", 61 .se_header = "Parent symbol",
62 .se_cmp = sort__parent_cmp, 62 .se_cmp = sort__parent_cmp,
63 .se_snprintf = hist_entry__parent_snprintf, 63 .se_snprintf = hist_entry__parent_snprintf,
64 .se_width = &parent_symbol__col_width, 64 .se_width_idx = HISTC_PARENT,
65};
66
67struct sort_entry sort_cpu = {
68 .se_header = "CPU",
69 .se_cmp = sort__cpu_cmp,
70 .se_snprintf = hist_entry__cpu_snprintf,
71 .se_width_idx = HISTC_CPU,
65}; 72};
66 73
67struct sort_dimension { 74struct sort_dimension {
@@ -76,6 +83,7 @@ static struct sort_dimension sort_dimensions[] = {
76 { .name = "dso", .entry = &sort_dso, }, 83 { .name = "dso", .entry = &sort_dso, },
77 { .name = "symbol", .entry = &sort_sym, }, 84 { .name = "symbol", .entry = &sort_sym, },
78 { .name = "parent", .entry = &sort_parent, }, 85 { .name = "parent", .entry = &sort_parent, },
86 { .name = "cpu", .entry = &sort_cpu, },
79}; 87};
80 88
81int64_t cmp_null(void *l, void *r) 89int64_t cmp_null(void *l, void *r)
@@ -242,6 +250,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
242 self->parent ? self->parent->name : "[other]"); 250 self->parent ? self->parent->name : "[other]");
243} 251}
244 252
253/* --sort cpu */
254
255int64_t
256sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
257{
258 return right->cpu - left->cpu;
259}
260
261static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
262 size_t size, unsigned int width)
263{
264 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
265}
266
245int sort_dimension__add(const char *tok) 267int sort_dimension__add(const char *tok)
246{ 268{
247 unsigned int i; 269 unsigned int i;
@@ -281,6 +303,8 @@ int sort_dimension__add(const char *tok)
281 sort__first_dimension = SORT_SYM; 303 sort__first_dimension = SORT_SYM;
282 else if (!strcmp(sd->name, "parent")) 304 else if (!strcmp(sd->name, "parent"))
283 sort__first_dimension = SORT_PARENT; 305 sort__first_dimension = SORT_PARENT;
306 else if (!strcmp(sd->name, "cpu"))
307 sort__first_dimension = SORT_CPU;
284 } 308 }
285 309
286 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 310 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 0d61c4082f43..46e531d09e8b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -36,11 +36,14 @@ extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso; 36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym; 37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent; 38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension; 39extern enum sort_type sort__first_dimension;
43 40
41/**
42 * struct hist_entry - histogram entry
43 *
44 * @row_offset - offset from the first callchain expanded to appear on screen
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */
44struct hist_entry { 47struct hist_entry {
45 struct rb_node rb_node; 48 struct rb_node rb_node;
46 u64 period; 49 u64 period;
@@ -51,7 +54,14 @@ struct hist_entry {
51 struct map_symbol ms; 54 struct map_symbol ms;
52 struct thread *thread; 55 struct thread *thread;
53 u64 ip; 56 u64 ip;
57 s32 cpu;
54 u32 nr_events; 58 u32 nr_events;
59
60 /* XXX These two should move to some tree widget lib */
61 u16 row_offset;
62 u16 nr_rows;
63
64 bool init_have_children;
55 char level; 65 char level;
56 u8 filtered; 66 u8 filtered;
57 struct symbol *parent; 67 struct symbol *parent;
@@ -68,7 +78,8 @@ enum sort_type {
68 SORT_COMM, 78 SORT_COMM,
69 SORT_DSO, 79 SORT_DSO,
70 SORT_SYM, 80 SORT_SYM,
71 SORT_PARENT 81 SORT_PARENT,
82 SORT_CPU,
72}; 83};
73 84
74/* 85/*
@@ -84,7 +95,7 @@ struct sort_entry {
84 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 95 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
85 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, 96 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size,
86 unsigned int width); 97 unsigned int width);
87 unsigned int *se_width; 98 u8 se_width_idx;
88 bool elide; 99 bool elide;
89}; 100};
90 101
@@ -104,6 +115,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
104extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); 115extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
105extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); 116extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
106extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 117extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
118int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
107extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 119extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
108extern int sort_dimension__add(const char *); 120extern int sort_dimension__add(const char *);
109void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 121void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5b276833e2bf..6f0dd90c36ce 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -12,6 +12,7 @@
12#include <fcntl.h> 12#include <fcntl.h>
13#include <unistd.h> 13#include <unistd.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "debug.h"
15#include "symbol.h" 16#include "symbol.h"
16#include "strlist.h" 17#include "strlist.h"
17 18
@@ -25,6 +26,8 @@
25#define NT_GNU_BUILD_ID 3 26#define NT_GNU_BUILD_ID 3
26#endif 27#endif
27 28
29static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
30static int elf_read_build_id(Elf *elf, void *bf, size_t size);
28static void dsos__add(struct list_head *head, struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
29static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
30static int dso__load_kernel_sym(struct dso *self, struct map *map, 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -40,6 +43,14 @@ struct symbol_conf symbol_conf = {
40 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
41}; 44};
42 45
46int dso__name_len(const struct dso *self)
47{
48 if (verbose)
49 return self->long_name_len;
50
51 return self->short_name_len;
52}
53
43bool dso__loaded(const struct dso *self, enum map_type type) 54bool dso__loaded(const struct dso *self, enum map_type type)
44{ 55{
45 return self->loaded & (1 << type); 56 return self->loaded & (1 << type);
@@ -215,7 +226,9 @@ void dso__delete(struct dso *self)
215 int i; 226 int i;
216 for (i = 0; i < MAP__NR_TYPES; ++i) 227 for (i = 0; i < MAP__NR_TYPES; ++i)
217 symbols__delete(&self->symbols[i]); 228 symbols__delete(&self->symbols[i]);
218 if (self->long_name != self->name) 229 if (self->sname_alloc)
230 free((char *)self->short_name);
231 if (self->lname_alloc)
219 free(self->long_name); 232 free(self->long_name);
220 free(self); 233 free(self);
221} 234}
@@ -933,8 +946,28 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
933 } 946 }
934} 947}
935 948
949static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
950{
951 Elf_Scn *sec = NULL;
952 GElf_Shdr shdr;
953 size_t cnt = 1;
954
955 while ((sec = elf_nextscn(elf, sec)) != NULL) {
956 gelf_getshdr(sec, &shdr);
957
958 if ((addr >= shdr.sh_addr) &&
959 (addr < (shdr.sh_addr + shdr.sh_size)))
960 return cnt;
961
962 ++cnt;
963 }
964
965 return -1;
966}
967
936static int dso__load_sym(struct dso *self, struct map *map, const char *name, 968static int dso__load_sym(struct dso *self, struct map *map, const char *name,
937 int fd, symbol_filter_t filter, int kmodule) 969 int fd, symbol_filter_t filter, int kmodule,
970 int want_symtab)
938{ 971{
939 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 972 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
940 struct map *curr_map = map; 973 struct map *curr_map = map;
@@ -944,31 +977,51 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
944 int err = -1; 977 int err = -1;
945 uint32_t idx; 978 uint32_t idx;
946 GElf_Ehdr ehdr; 979 GElf_Ehdr ehdr;
947 GElf_Shdr shdr; 980 GElf_Shdr shdr, opdshdr;
948 Elf_Data *syms; 981 Elf_Data *syms, *opddata = NULL;
949 GElf_Sym sym; 982 GElf_Sym sym;
950 Elf_Scn *sec, *sec_strndx; 983 Elf_Scn *sec, *sec_strndx, *opdsec;
951 Elf *elf; 984 Elf *elf;
952 int nr = 0; 985 int nr = 0;
986 size_t opdidx = 0;
953 987
954 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 988 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
955 if (elf == NULL) { 989 if (elf == NULL) {
956 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 990 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
957 goto out_close; 991 goto out_close;
958 } 992 }
959 993
960 if (gelf_getehdr(elf, &ehdr) == NULL) { 994 if (gelf_getehdr(elf, &ehdr) == NULL) {
961 pr_err("%s: cannot get elf header.\n", __func__); 995 pr_debug("%s: cannot get elf header.\n", __func__);
962 goto out_elf_end; 996 goto out_elf_end;
963 } 997 }
964 998
999 /* Always reject images with a mismatched build-id: */
1000 if (self->has_build_id) {
1001 u8 build_id[BUILD_ID_SIZE];
1002
1003 if (elf_read_build_id(elf, build_id,
1004 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1005 goto out_elf_end;
1006
1007 if (!dso__build_id_equal(self, build_id))
1008 goto out_elf_end;
1009 }
1010
965 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 1011 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
966 if (sec == NULL) { 1012 if (sec == NULL) {
1013 if (want_symtab)
1014 goto out_elf_end;
1015
967 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1016 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
968 if (sec == NULL) 1017 if (sec == NULL)
969 goto out_elf_end; 1018 goto out_elf_end;
970 } 1019 }
971 1020
1021 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1022 if (opdsec)
1023 opddata = elf_rawdata(opdsec, NULL);
1024
972 syms = elf_getdata(sec, NULL); 1025 syms = elf_getdata(sec, NULL);
973 if (syms == NULL) 1026 if (syms == NULL)
974 goto out_elf_end; 1027 goto out_elf_end;
@@ -1013,6 +1066,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1013 if (!is_label && !elf_sym__is_a(&sym, map->type)) 1066 if (!is_label && !elf_sym__is_a(&sym, map->type))
1014 continue; 1067 continue;
1015 1068
1069 if (opdsec && sym.st_shndx == opdidx) {
1070 u32 offset = sym.st_value - opdshdr.sh_addr;
1071 u64 *opd = opddata->d_buf + offset;
1072 sym.st_value = *opd;
1073 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1074 }
1075
1016 sec = elf_getscn(elf, sym.st_shndx); 1076 sec = elf_getscn(elf, sym.st_shndx);
1017 if (!sec) 1077 if (!sec)
1018 goto out_elf_end; 1078 goto out_elf_end;
@@ -1151,37 +1211,26 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1151 */ 1211 */
1152#define NOTE_ALIGN(n) (((n) + 3) & -4U) 1212#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1153 1213
1154int filename__read_build_id(const char *filename, void *bf, size_t size) 1214static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1155{ 1215{
1156 int fd, err = -1; 1216 int err = -1;
1157 GElf_Ehdr ehdr; 1217 GElf_Ehdr ehdr;
1158 GElf_Shdr shdr; 1218 GElf_Shdr shdr;
1159 Elf_Data *data; 1219 Elf_Data *data;
1160 Elf_Scn *sec; 1220 Elf_Scn *sec;
1161 Elf_Kind ek; 1221 Elf_Kind ek;
1162 void *ptr; 1222 void *ptr;
1163 Elf *elf;
1164 1223
1165 if (size < BUILD_ID_SIZE) 1224 if (size < BUILD_ID_SIZE)
1166 goto out; 1225 goto out;
1167 1226
1168 fd = open(filename, O_RDONLY);
1169 if (fd < 0)
1170 goto out;
1171
1172 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1173 if (elf == NULL) {
1174 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1175 goto out_close;
1176 }
1177
1178 ek = elf_kind(elf); 1227 ek = elf_kind(elf);
1179 if (ek != ELF_K_ELF) 1228 if (ek != ELF_K_ELF)
1180 goto out_elf_end; 1229 goto out;
1181 1230
1182 if (gelf_getehdr(elf, &ehdr) == NULL) { 1231 if (gelf_getehdr(elf, &ehdr) == NULL) {
1183 pr_err("%s: cannot get elf header.\n", __func__); 1232 pr_err("%s: cannot get elf header.\n", __func__);
1184 goto out_elf_end; 1233 goto out;
1185 } 1234 }
1186 1235
1187 sec = elf_section_by_name(elf, &ehdr, &shdr, 1236 sec = elf_section_by_name(elf, &ehdr, &shdr,
@@ -1190,12 +1239,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1190 sec = elf_section_by_name(elf, &ehdr, &shdr, 1239 sec = elf_section_by_name(elf, &ehdr, &shdr,
1191 ".notes", NULL); 1240 ".notes", NULL);
1192 if (sec == NULL) 1241 if (sec == NULL)
1193 goto out_elf_end; 1242 goto out;
1194 } 1243 }
1195 1244
1196 data = elf_getdata(sec, NULL); 1245 data = elf_getdata(sec, NULL);
1197 if (data == NULL) 1246 if (data == NULL)
1198 goto out_elf_end; 1247 goto out;
1199 1248
1200 ptr = data->d_buf; 1249 ptr = data->d_buf;
1201 while (ptr < (data->d_buf + data->d_size)) { 1250 while (ptr < (data->d_buf + data->d_size)) {
@@ -1217,7 +1266,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1217 } 1266 }
1218 ptr += descsz; 1267 ptr += descsz;
1219 } 1268 }
1220out_elf_end: 1269
1270out:
1271 return err;
1272}
1273
1274int filename__read_build_id(const char *filename, void *bf, size_t size)
1275{
1276 int fd, err = -1;
1277 Elf *elf;
1278
1279 if (size < BUILD_ID_SIZE)
1280 goto out;
1281
1282 fd = open(filename, O_RDONLY);
1283 if (fd < 0)
1284 goto out;
1285
1286 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1287 if (elf == NULL) {
1288 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1289 goto out_close;
1290 }
1291
1292 err = elf_read_build_id(elf, bf, size);
1293
1221 elf_end(elf); 1294 elf_end(elf);
1222out_close: 1295out_close:
1223 close(fd); 1296 close(fd);
@@ -1293,11 +1366,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1293{ 1366{
1294 int size = PATH_MAX; 1367 int size = PATH_MAX;
1295 char *name; 1368 char *name;
1296 u8 build_id[BUILD_ID_SIZE];
1297 int ret = -1; 1369 int ret = -1;
1298 int fd; 1370 int fd;
1299 struct machine *machine; 1371 struct machine *machine;
1300 const char *root_dir; 1372 const char *root_dir;
1373 int want_symtab;
1301 1374
1302 dso__set_loaded(self, map->type); 1375 dso__set_loaded(self, map->type);
1303 1376
@@ -1324,13 +1397,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1324 return ret; 1397 return ret;
1325 } 1398 }
1326 1399
1327 self->origin = DSO__ORIG_BUILD_ID_CACHE; 1400 /* Iterate over candidate debug images.
1328 if (dso__build_id_filename(self, name, size) != NULL) 1401 * On the first pass, only load images if they have a full symtab.
1329 goto open_file; 1402 * Failing that, do a second pass where we accept .dynsym also
1330more: 1403 */
1331 do { 1404 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
1332 self->origin++; 1405 self->origin != DSO__ORIG_NOT_FOUND;
1406 self->origin++) {
1333 switch (self->origin) { 1407 switch (self->origin) {
1408 case DSO__ORIG_BUILD_ID_CACHE:
1409 if (dso__build_id_filename(self, name, size) == NULL)
1410 continue;
1411 break;
1334 case DSO__ORIG_FEDORA: 1412 case DSO__ORIG_FEDORA:
1335 snprintf(name, size, "/usr/lib/debug%s.debug", 1413 snprintf(name, size, "/usr/lib/debug%s.debug",
1336 self->long_name); 1414 self->long_name);
@@ -1339,21 +1417,20 @@ more:
1339 snprintf(name, size, "/usr/lib/debug%s", 1417 snprintf(name, size, "/usr/lib/debug%s",
1340 self->long_name); 1418 self->long_name);
1341 break; 1419 break;
1342 case DSO__ORIG_BUILDID: 1420 case DSO__ORIG_BUILDID: {
1343 if (filename__read_build_id(self->long_name, build_id, 1421 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1344 sizeof(build_id))) { 1422
1345 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1423 if (!self->has_build_id)
1346 build_id__sprintf(build_id, sizeof(build_id), 1424 continue;
1347 build_id_hex); 1425
1348 snprintf(name, size, 1426 build_id__sprintf(self->build_id,
1349 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1427 sizeof(self->build_id),
1350 build_id_hex, build_id_hex + 2); 1428 build_id_hex);
1351 if (self->has_build_id) 1429 snprintf(name, size,
1352 goto compare_build_id; 1430 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1353 break; 1431 build_id_hex, build_id_hex + 2);
1354 } 1432 }
1355 self->origin++; 1433 break;
1356 /* Fall thru */
1357 case DSO__ORIG_DSO: 1434 case DSO__ORIG_DSO:
1358 snprintf(name, size, "%s", self->long_name); 1435 snprintf(name, size, "%s", self->long_name);
1359 break; 1436 break;
@@ -1366,36 +1443,41 @@ more:
1366 break; 1443 break;
1367 1444
1368 default: 1445 default:
1369 goto out; 1446 /*
1447 * If we wanted a full symtab but no image had one,
1448 * relax our requirements and repeat the search.
1449 */
1450 if (want_symtab) {
1451 want_symtab = 0;
1452 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1453 } else
1454 continue;
1370 } 1455 }
1371 1456
1372 if (self->has_build_id) { 1457 /* Name is now the name of the next image to try */
1373 if (filename__read_build_id(name, build_id,
1374 sizeof(build_id)) < 0)
1375 goto more;
1376compare_build_id:
1377 if (!dso__build_id_equal(self, build_id))
1378 goto more;
1379 }
1380open_file:
1381 fd = open(name, O_RDONLY); 1458 fd = open(name, O_RDONLY);
1382 } while (fd < 0); 1459 if (fd < 0)
1460 continue;
1383 1461
1384 ret = dso__load_sym(self, map, name, fd, filter, 0); 1462 ret = dso__load_sym(self, map, name, fd, filter, 0,
1385 close(fd); 1463 want_symtab);
1464 close(fd);
1386 1465
1387 /* 1466 /*
1388 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 1467 * Some people seem to have debuginfo files _WITHOUT_ debug
1389 */ 1468 * info!?!?
1390 if (!ret) 1469 */
1391 goto more; 1470 if (!ret)
1471 continue;
1392 1472
1393 if (ret > 0) { 1473 if (ret > 0) {
1394 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1474 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1395 if (nr_plt > 0) 1475 if (nr_plt > 0)
1396 ret += nr_plt; 1476 ret += nr_plt;
1477 break;
1478 }
1397 } 1479 }
1398out: 1480
1399 free(name); 1481 free(name);
1400 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1482 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1401 return 0; 1483 return 0;
@@ -1494,6 +1576,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self,
1494 goto out; 1576 goto out;
1495 } 1577 }
1496 dso__set_long_name(map->dso, long_name); 1578 dso__set_long_name(map->dso, long_name);
1579 map->dso->lname_alloc = 1;
1497 dso__kernel_module_get_build_id(map->dso, ""); 1580 dso__kernel_module_get_build_id(map->dso, "");
1498 } 1581 }
1499 } 1582 }
@@ -1656,36 +1739,12 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1656{ 1739{
1657 int err = -1, fd; 1740 int err = -1, fd;
1658 1741
1659 if (self->has_build_id) {
1660 u8 build_id[BUILD_ID_SIZE];
1661
1662 if (filename__read_build_id(vmlinux, build_id,
1663 sizeof(build_id)) < 0) {
1664 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1665 return -1;
1666 }
1667 if (!dso__build_id_equal(self, build_id)) {
1668 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1669 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1670
1671 build_id__sprintf(self->build_id,
1672 sizeof(self->build_id),
1673 expected_build_id);
1674 build_id__sprintf(build_id, sizeof(build_id),
1675 vmlinux_build_id);
1676 pr_debug("build_id in %s is %s while expected is %s, "
1677 "ignoring it\n", vmlinux, vmlinux_build_id,
1678 expected_build_id);
1679 return -1;
1680 }
1681 }
1682
1683 fd = open(vmlinux, O_RDONLY); 1742 fd = open(vmlinux, O_RDONLY);
1684 if (fd < 0) 1743 if (fd < 0)
1685 return -1; 1744 return -1;
1686 1745
1687 dso__set_loaded(self, map->type); 1746 dso__set_loaded(self, map->type);
1688 err = dso__load_sym(self, map, vmlinux, fd, filter, 0); 1747 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
1689 close(fd); 1748 close(fd);
1690 1749
1691 if (err > 0) 1750 if (err > 0)
@@ -2048,6 +2107,36 @@ int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2048 return 0; 2107 return 0;
2049} 2108}
2050 2109
2110void machine__destroy_kernel_maps(struct machine *self)
2111{
2112 enum map_type type;
2113
2114 for (type = 0; type < MAP__NR_TYPES; ++type) {
2115 struct kmap *kmap;
2116
2117 if (self->vmlinux_maps[type] == NULL)
2118 continue;
2119
2120 kmap = map__kmap(self->vmlinux_maps[type]);
2121 map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2122 if (kmap->ref_reloc_sym) {
2123 /*
2124 * ref_reloc_sym is shared among all maps, so free just
2125 * on one of them.
2126 */
2127 if (type == MAP__FUNCTION) {
2128 free((char *)kmap->ref_reloc_sym->name);
2129 kmap->ref_reloc_sym->name = NULL;
2130 free(kmap->ref_reloc_sym);
2131 }
2132 kmap->ref_reloc_sym = NULL;
2133 }
2134
2135 map__delete(self->vmlinux_maps[type]);
2136 self->vmlinux_maps[type] = NULL;
2137 }
2138}
2139
2051int machine__create_kernel_maps(struct machine *self) 2140int machine__create_kernel_maps(struct machine *self)
2052{ 2141{
2053 struct dso *kernel = machine__create_kernel(self); 2142 struct dso *kernel = machine__create_kernel(self);
@@ -2189,6 +2278,15 @@ out_free_comm_list:
2189 return -1; 2278 return -1;
2190} 2279}
2191 2280
2281void symbol__exit(void)
2282{
2283 strlist__delete(symbol_conf.sym_list);
2284 strlist__delete(symbol_conf.dso_list);
2285 strlist__delete(symbol_conf.comm_list);
2286 vmlinux_path__exit();
2287 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2288}
2289
2192int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 2290int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
2193{ 2291{
2194 struct machine *machine = machines__findnew(self, pid); 2292 struct machine *machine = machines__findnew(self, pid);
@@ -2283,6 +2381,19 @@ failure:
2283 return ret; 2381 return ret;
2284} 2382}
2285 2383
2384void machines__destroy_guest_kernel_maps(struct rb_root *self)
2385{
2386 struct rb_node *next = rb_first(self);
2387
2388 while (next) {
2389 struct machine *pos = rb_entry(next, struct machine, rb_node);
2390
2391 next = rb_next(&pos->rb_node);
2392 rb_erase(&pos->rb_node, self);
2393 machine__delete(pos);
2394 }
2395}
2396
2286int machine__load_kallsyms(struct machine *self, const char *filename, 2397int machine__load_kallsyms(struct machine *self, const char *filename,
2287 enum map_type type, symbol_filter_t filter) 2398 enum map_type type, symbol_filter_t filter)
2288{ 2399{
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5e02d2c17154..906be20011d9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -9,8 +9,6 @@
9#include <linux/rbtree.h> 9#include <linux/rbtree.h>
10#include <stdio.h> 10#include <stdio.h>
11 11
12#define DEBUG_CACHE_DIR ".debug"
13
14#ifdef HAVE_CPLUS_DEMANGLE 12#ifdef HAVE_CPLUS_DEMANGLE
15extern char *cplus_demangle(const char *, int); 13extern char *cplus_demangle(const char *, int);
16 14
@@ -70,9 +68,9 @@ struct symbol_conf {
70 show_nr_samples, 68 show_nr_samples,
71 use_callchain, 69 use_callchain,
72 exclude_other, 70 exclude_other,
73 full_paths,
74 show_cpu_utilization; 71 show_cpu_utilization;
75 const char *vmlinux_name, 72 const char *vmlinux_name,
73 *source_prefix,
76 *field_sep; 74 *field_sep;
77 const char *default_guest_vmlinux_name, 75 const char *default_guest_vmlinux_name,
78 *default_guest_kallsyms, 76 *default_guest_kallsyms,
@@ -103,6 +101,8 @@ struct ref_reloc_sym {
103struct map_symbol { 101struct map_symbol {
104 struct map *map; 102 struct map *map;
105 struct symbol *sym; 103 struct symbol *sym;
104 bool unfolded;
105 bool has_children;
106}; 106};
107 107
108struct addr_location { 108struct addr_location {
@@ -112,7 +112,8 @@ struct addr_location {
112 u64 addr; 112 u64 addr;
113 char level; 113 char level;
114 bool filtered; 114 bool filtered;
115 unsigned int cpumode; 115 u8 cpumode;
116 s32 cpu;
116}; 117};
117 118
118enum dso_kernel_type { 119enum dso_kernel_type {
@@ -125,12 +126,14 @@ struct dso {
125 struct list_head node; 126 struct list_head node;
126 struct rb_root symbols[MAP__NR_TYPES]; 127 struct rb_root symbols[MAP__NR_TYPES];
127 struct rb_root symbol_names[MAP__NR_TYPES]; 128 struct rb_root symbol_names[MAP__NR_TYPES];
129 enum dso_kernel_type kernel;
128 u8 adjust_symbols:1; 130 u8 adjust_symbols:1;
129 u8 slen_calculated:1; 131 u8 slen_calculated:1;
130 u8 has_build_id:1; 132 u8 has_build_id:1;
131 enum dso_kernel_type kernel;
132 u8 hit:1; 133 u8 hit:1;
133 u8 annotate_warned:1; 134 u8 annotate_warned:1;
135 u8 sname_alloc:1;
136 u8 lname_alloc:1;
134 unsigned char origin; 137 unsigned char origin;
135 u8 sorted_by_name; 138 u8 sorted_by_name;
136 u8 loaded; 139 u8 loaded;
@@ -146,6 +149,8 @@ struct dso *dso__new(const char *name);
146struct dso *dso__new_kernel(const char *name); 149struct dso *dso__new_kernel(const char *name);
147void dso__delete(struct dso *self); 150void dso__delete(struct dso *self);
148 151
152int dso__name_len(const struct dso *self);
153
149bool dso__loaded(const struct dso *self, enum map_type type); 154bool dso__loaded(const struct dso *self, enum map_type type);
150bool dso__sorted_by_name(const struct dso *self, enum map_type type); 155bool dso__sorted_by_name(const struct dso *self, enum map_type type);
151 156
@@ -207,13 +212,16 @@ int kallsyms__parse(const char *filename, void *arg,
207 int (*process_symbol)(void *arg, const char *name, 212 int (*process_symbol)(void *arg, const char *name,
208 char type, u64 start)); 213 char type, u64 start));
209 214
215void machine__destroy_kernel_maps(struct machine *self);
210int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); 216int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
211int machine__create_kernel_maps(struct machine *self); 217int machine__create_kernel_maps(struct machine *self);
212 218
213int machines__create_kernel_maps(struct rb_root *self, pid_t pid); 219int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
214int machines__create_guest_kernel_maps(struct rb_root *self); 220int machines__create_guest_kernel_maps(struct rb_root *self);
221void machines__destroy_guest_kernel_maps(struct rb_root *self);
215 222
216int symbol__init(void); 223int symbol__init(void);
224void symbol__exit(void);
217bool symbol_type__is_a(char symbol_type, enum map_type map_type); 225bool symbol_type__is_a(char symbol_type, enum map_type map_type);
218 226
219size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp); 227size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 9a448b47400c..8c72d888e449 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -62,6 +62,13 @@ static struct thread *thread__new(pid_t pid)
62 return self; 62 return self;
63} 63}
64 64
65void thread__delete(struct thread *self)
66{
67 map_groups__exit(&self->mg);
68 free(self->comm);
69 free(self);
70}
71
65int thread__set_comm(struct thread *self, const char *comm) 72int thread__set_comm(struct thread *self, const char *comm)
66{ 73{
67 int err; 74 int err;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index ee6bbcf277ca..688500ff826f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -20,6 +20,8 @@ struct thread {
20 20
21struct perf_session; 21struct perf_session;
22 22
23void thread__delete(struct thread *self);
24
23int find_all_tid(int pid, pid_t ** all_tid); 25int find_all_tid(int pid, pid_t ** all_tid);
24int thread__set_comm(struct thread *self, const char *comm); 26int thread__set_comm(struct thread *self, const char *comm);
25int thread__comm_len(struct thread *self); 27int thread__comm_len(struct thread *self);
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4e8b6b0c551c..f380fed74359 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -89,6 +89,7 @@
89 89
90extern const char *graph_line; 90extern const char *graph_line;
91extern const char *graph_dotted_line; 91extern const char *graph_dotted_line;
92extern char buildid_dir[];
92 93
93/* On most systems <limits.h> would have given us this, but 94/* On most systems <limits.h> would have given us this, but
94 * not on some systems (e.g. GNU/Hurd). 95 * not on some systems (e.g. GNU/Hurd).
@@ -152,6 +153,8 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
152extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 153extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
153 154
154extern int prefixcmp(const char *str, const char *prefix); 155extern int prefixcmp(const char *str, const char *prefix);
156extern void set_buildid_dir(void);
157extern void disable_buildid_cache(void);
155 158
156static inline const char *skip_prefix(const char *str, const char *prefix) 159static inline const char *skip_prefix(const char *str, const char *prefix)
157{ 160{