aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN2
-rw-r--r--tools/perf/util/cache.h11
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/data_map.c222
-rw-r--r--tools/perf/util/data_map.h31
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h7
-rw-r--r--tools/perf/util/event.h30
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c74
-rw-r--r--tools/perf/util/header.h29
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c210
-rw-r--r--tools/perf/util/hist.h50
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h2
-rw-r--r--tools/perf/util/include/linux/bitops.h27
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h76
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/include/linux/types.h9
-rw-r--r--tools/perf/util/levenshtein.h6
-rw-r--r--tools/perf/util/map.c26
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c26
-rw-r--r--tools/perf/util/parse-events.h8
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c290
-rw-r--r--tools/perf/util/sort.h99
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c11
-rw-r--r--tools/perf/util/string.h7
-rw-r--r--tools/perf/util/strlist.h6
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c785
-rw-r--r--tools/perf/util/symbol.h34
-rw-r--r--tools/perf/util/thread.c167
-rw-r--r--tools/perf/util/thread.h31
-rw-r--r--tools/perf/util/trace-event-info.c6
-rw-r--r--tools/perf/util/trace-event-parse.c537
-rw-r--r--tools/perf/util/trace-event-read.c7
-rw-r--r--tools/perf/util/trace-event.h41
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/values.h6
56 files changed, 2433 insertions, 1156 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index c561d1538c03..54552a00a117 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -1,7 +1,7 @@
1#!/bin/sh 1#!/bin/sh
2 2
3GVF=PERF-VERSION-FILE 3GVF=PERF-VERSION-FILE
4DEF_VER=v0.0.1.PERF 4DEF_VER=v0.0.2.PERF
5 5
6LF=' 6LF='
7' 7'
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,10 +1,15 @@
1#ifndef CACHE_H 1#ifndef __PERF_CACHE_H
2#define CACHE_H 2#define __PERF_CACHE_H
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h" 6#include "../perf.h"
7 7
8#define CMD_EXEC_PATH "--exec-path"
9#define CMD_PERF_DIR "--perf-dir="
10#define CMD_WORK_TREE "--work-tree="
11#define CMD_DEBUGFS_DIR "--debugfs-dir="
12
8#define PERF_DIR_ENVIRONMENT "PERF_DIR" 13#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
117 122
118extern size_t strlcpy(char *dest, const char *src, size_t size); 123extern size_t strlcpy(char *dest, const char *src, size_t size);
119 124
120#endif /* CACHE_H */ 125#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
206 } 206 }
207 node->val_nr = chain->nr - start; 207 node->val_nr = chain->nr - start;
208 if (!node->val_nr) 208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n"); 209 pr_warning("Warning: empty node in callchain tree\n");
210} 210}
211 211
212static void 212static void
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
1#ifndef COLOR_H 1#ifndef __PERF_COLOR_H
2#define COLOR_H 2#define __PERF_COLOR_H
3 3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 5#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
41 41
42#endif /* COLOR_H */ 42#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
new file mode 100644
index 000000000000..18accb8fee4d
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,222 @@
1#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int
12process_event_stub(event_t *event __used,
13 unsigned long offset __used,
14 unsigned long head __used)
15{
16 return 0;
17}
18
19void register_perf_file_handler(struct perf_file_handler *handler)
20{
21 if (!handler->process_sample_event)
22 handler->process_sample_event = process_event_stub;
23 if (!handler->process_mmap_event)
24 handler->process_mmap_event = process_event_stub;
25 if (!handler->process_comm_event)
26 handler->process_comm_event = process_event_stub;
27 if (!handler->process_fork_event)
28 handler->process_fork_event = process_event_stub;
29 if (!handler->process_exit_event)
30 handler->process_exit_event = process_event_stub;
31 if (!handler->process_lost_event)
32 handler->process_lost_event = process_event_stub;
33 if (!handler->process_read_event)
34 handler->process_read_event = process_event_stub;
35 if (!handler->process_throttle_event)
36 handler->process_throttle_event = process_event_stub;
37 if (!handler->process_unthrottle_event)
38 handler->process_unthrottle_event = process_event_stub;
39
40 curr_handler = handler;
41}
42
43static int
44process_event(event_t *event, unsigned long offset, unsigned long head)
45{
46 trace_event(event);
47
48 switch (event->header.type) {
49 case PERF_RECORD_SAMPLE:
50 return curr_handler->process_sample_event(event, offset, head);
51 case PERF_RECORD_MMAP:
52 return curr_handler->process_mmap_event(event, offset, head);
53 case PERF_RECORD_COMM:
54 return curr_handler->process_comm_event(event, offset, head);
55 case PERF_RECORD_FORK:
56 return curr_handler->process_fork_event(event, offset, head);
57 case PERF_RECORD_EXIT:
58 return curr_handler->process_exit_event(event, offset, head);
59 case PERF_RECORD_LOST:
60 return curr_handler->process_lost_event(event, offset, head);
61 case PERF_RECORD_READ:
62 return curr_handler->process_read_event(event, offset, head);
63 case PERF_RECORD_THROTTLE:
64 return curr_handler->process_throttle_event(event, offset, head);
65 case PERF_RECORD_UNTHROTTLE:
66 return curr_handler->process_unthrottle_event(event, offset, head);
67 default:
68 curr_handler->total_unknown++;
69 return -1;
70 }
71}
72
73int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name,
75 int force,
76 int full_paths,
77 int *cwdlen,
78 char **cwd)
79{
80 int ret, rc = EXIT_FAILURE;
81 struct perf_header *header;
82 unsigned long head, shift;
83 unsigned long offset = 0;
84 struct stat input_stat;
85 size_t page_size;
86 u64 sample_type;
87 event_t *event;
88 uint32_t size;
89 int input;
90 char *buf;
91
92 if (!curr_handler)
93 die("Forgot to register perf file handler");
94
95 page_size = getpagesize();
96
97 input = open(input_name, O_RDONLY);
98 if (input < 0) {
99 fprintf(stderr, " failed to open file: %s", input_name);
100 if (!strcmp(input_name, "perf.data"))
101 fprintf(stderr, " (try 'perf record' first)");
102 fprintf(stderr, "\n");
103 exit(-1);
104 }
105
106 ret = fstat(input, &input_stat);
107 if (ret < 0) {
108 perror("failed to stat file");
109 exit(-1);
110 }
111
112 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
113 fprintf(stderr, "file: %s not owned by current user or root\n",
114 input_name);
115 exit(-1);
116 }
117
118 if (!input_stat.st_size) {
119 fprintf(stderr, "zero-sized file, nothing to do!\n");
120 exit(0);
121 }
122
123 *pheader = perf_header__read(input);
124 header = *pheader;
125 head = header->data_offset;
126
127 sample_type = perf_header__sample_type(header);
128
129 if (curr_handler->sample_type_check)
130 if (curr_handler->sample_type_check(sample_type) < 0)
131 exit(-1);
132
133 if (load_kernel(0, NULL) < 0) {
134 perror("failed to load kernel symbols");
135 return EXIT_FAILURE;
136 }
137
138 if (!full_paths) {
139 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
140 perror("failed to get the current directory");
141 return EXIT_FAILURE;
142 }
143 *cwd = __cwd;
144 *cwdlen = strlen(*cwd);
145 } else {
146 *cwd = NULL;
147 *cwdlen = 0;
148 }
149
150 shift = page_size * (head / page_size);
151 offset += shift;
152 head -= shift;
153
154remap:
155 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
156 MAP_SHARED, input, offset);
157 if (buf == MAP_FAILED) {
158 perror("failed to mmap file");
159 exit(-1);
160 }
161
162more:
163 event = (event_t *)(buf + head);
164
165 size = event->header.size;
166 if (!size)
167 size = 8;
168
169 if (head + event->header.size >= page_size * mmap_window) {
170 int munmap_ret;
171
172 shift = page_size * (head / page_size);
173
174 munmap_ret = munmap(buf, page_size * mmap_window);
175 assert(munmap_ret == 0);
176
177 offset += shift;
178 head -= shift;
179 goto remap;
180 }
181
182 size = event->header.size;
183
184 dump_printf("\n%p [%p]: event: %d\n",
185 (void *)(offset + head),
186 (void *)(long)event->header.size,
187 event->header.type);
188
189 if (!size || process_event(event, offset, head) < 0) {
190
191 dump_printf("%p [%p]: skipping unknown header type: %d\n",
192 (void *)(offset + head),
193 (void *)(long)(event->header.size),
194 event->header.type);
195
196 /*
197 * assume we lost track of the stream, check alignment, and
198 * increment a single u64 in the hope to catch on again 'soon'.
199 */
200
201 if (unlikely(head & 7))
202 head &= ~7ULL;
203
204 size = 8;
205 }
206
207 head += size;
208
209 if (offset + head >= header->data_offset + header->data_size)
210 goto done;
211
212 if (offset + head < (unsigned long)input_stat.st_size)
213 goto more;
214
215done:
216 rc = EXIT_SUCCESS;
217 close(input);
218
219 return rc;
220}
221
222
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644
index 000000000000..716d1053b074
--- /dev/null
+++ b/tools/perf/util/data_map.h
@@ -0,0 +1,31 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6
7typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long);
8
9struct perf_file_handler {
10 event_type_handler_t process_sample_event;
11 event_type_handler_t process_mmap_event;
12 event_type_handler_t process_comm_event;
13 event_type_handler_t process_fork_event;
14 event_type_handler_t process_exit_event;
15 event_type_handler_t process_lost_event;
16 event_type_handler_t process_read_event;
17 event_type_handler_t process_throttle_event;
18 event_type_handler_t process_unthrottle_event;
19 int (*sample_type_check)(u64 sample_type);
20 unsigned long total_unknown;
21};
22
23void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader,
25 const char *input_name,
26 int force,
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30
31#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..28d520d5a1fb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -13,12 +13,12 @@
13int verbose = 0; 13int verbose = 0;
14int dump_trace = 0; 14int dump_trace = 0;
15 15
16int eprintf(const char *fmt, ...) 16int eprintf(int level, const char *fmt, ...)
17{ 17{
18 va_list args; 18 va_list args;
19 int ret = 0; 19 int ret = 0;
20 20
21 if (verbose) { 21 if (verbose >= level) {
22 va_start(args, fmt); 22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 23 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 24 va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 437eea58ce40..e8b18a1f87a4 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,8 +1,13 @@
1/* For debugging general purposes */ 1/* For debugging general purposes */
2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H
2 4
3extern int verbose; 5extern int verbose;
4extern int dump_trace; 6extern int dump_trace;
5 7
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 8int eprintf(int level,
9 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event); 11void trace_event(event_t *event);
12
13#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..d972b4b0d38c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3
3#include "../perf.h" 4#include "../perf.h"
4#include "util.h" 5#include "util.h"
5#include <linux/list.h> 6#include <linux/list.h>
6 7#include <linux/rbtree.h>
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12 8
13/* 9/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -78,11 +74,15 @@ typedef union event_union {
78} event_t; 74} event_t;
79 75
80struct map { 76struct map {
81 struct list_head node; 77 union {
78 struct rb_node rb_node;
79 struct list_head node;
80 };
82 u64 start; 81 u64 start;
83 u64 end; 82 u64 end;
84 u64 pgoff; 83 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64); 84 u64 (*map_ip)(struct map *, u64);
85 u64 (*unmap_ip)(struct map *, u64);
86 struct dso *dso; 86 struct dso *dso;
87}; 87};
88 88
@@ -91,14 +91,24 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
91 return ip - map->start + map->pgoff; 91 return ip - map->start + map->pgoff;
92} 92}
93 93
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 94static inline u64 map__unmap_ip(struct map *map, u64 ip)
95{
96 return ip + map->start - map->pgoff;
97}
98
99static inline u64 identity__map_ip(struct map *map __used, u64 ip)
95{ 100{
96 return ip; 101 return ip;
97} 102}
98 103
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 104struct symbol;
105
106typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
107
108struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
109 unsigned int sym_priv_size, symbol_filter_t filter);
100struct map *map__clone(struct map *self); 110struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r); 111int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp); 112size_t map__fprintf(struct map *self, FILE *fp);
103 113
104#endif 114#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
1#ifndef PERF_EXEC_CMD_H 1#ifndef __PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H 2#define __PERF_EXEC_CMD_H
3 3
4extern void perf_set_argv_exec_path(const char *exec_path); 4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 11extern const char *system_path(const char *path);
12 12
13#endif /* PERF_EXEC_CMD_H */ 13#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..7d26659b806c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -5,6 +5,8 @@
5 5
6#include "util.h" 6#include "util.h"
7#include "header.h" 7#include "header.h"
8#include "../perf.h"
9#include "trace-event.h"
8 10
9/* 11/*
10 * Create new perf.data header attribute: 12 * Create new perf.data header attribute:
@@ -46,23 +48,17 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
46 */ 48 */
47struct perf_header *perf_header__new(void) 49struct perf_header *perf_header__new(void)
48{ 50{
49 struct perf_header *self = malloc(sizeof(*self)); 51 struct perf_header *self = calloc(sizeof(*self), 1);
50 52
51 if (!self) 53 if (!self)
52 die("nomem"); 54 die("nomem");
53 55
54 self->frozen = 0;
55
56 self->attrs = 0;
57 self->size = 1; 56 self->size = 1;
58 self->attr = malloc(sizeof(void *)); 57 self->attr = malloc(sizeof(void *));
59 58
60 if (!self->attr) 59 if (!self->attr)
61 die("nomem"); 60 die("nomem");
62 61
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self; 62 return self;
67} 63}
68 64
@@ -97,7 +93,7 @@ static struct perf_trace_event_type *events;
97void perf_header__push_event(u64 id, const char *name) 93void perf_header__push_event(u64 id, const char *name)
98{ 94{
99 if (strlen(name) > MAX_EVENT_NAME) 95 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 96 pr_warning("Event %s will be truncated\n", name);
101 97
102 if (!events) { 98 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 99 events = malloc(sizeof(struct perf_trace_event_type));
@@ -145,8 +141,14 @@ struct perf_file_header {
145 struct perf_file_section attrs; 141 struct perf_file_section attrs;
146 struct perf_file_section data; 142 struct perf_file_section data;
147 struct perf_file_section event_types; 143 struct perf_file_section event_types;
144 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
148}; 145};
149 146
147void perf_header__feat_trace_info(struct perf_header *header)
148{
149 set_bit(HEADER_TRACE_INFO, header->adds_features);
150}
151
150static void do_write(int fd, void *buf, size_t size) 152static void do_write(int fd, void *buf, size_t size)
151{ 153{
152 while (size) { 154 while (size) {
@@ -160,6 +162,32 @@ static void do_write(int fd, void *buf, size_t size)
160 } 162 }
161} 163}
162 164
165static void perf_header__adds_write(struct perf_header *self, int fd)
166{
167 struct perf_file_section trace_sec;
168 u64 cur_offset = lseek(fd, 0, SEEK_CUR);
169 unsigned long *feat_mask = self->adds_features;
170
171 if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
172 /* Write trace info */
173 trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR);
174 read_tracing_data(fd, attrs, nr_counters);
175 trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset;
176
177 /* Write trace info headers */
178 lseek(fd, cur_offset, SEEK_SET);
179 do_write(fd, &trace_sec, sizeof(trace_sec));
180
181 /*
182 * Update cur_offset. So that other (future)
183 * features can set their own infos in this place. But if we are
184 * the only feature, at least that seeks to the place the data
185 * should begin.
186 */
187 cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
188 }
189};
190
163void perf_header__write(struct perf_header *self, int fd) 191void perf_header__write(struct perf_header *self, int fd)
164{ 192{
165 struct perf_file_header f_header; 193 struct perf_file_header f_header;
@@ -198,6 +226,7 @@ void perf_header__write(struct perf_header *self, int fd)
198 if (events) 226 if (events)
199 do_write(fd, events, self->event_size); 227 do_write(fd, events, self->event_size);
200 228
229 perf_header__adds_write(self, fd);
201 230
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 231 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 232
@@ -219,6 +248,8 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 248 },
220 }; 249 };
221 250
251 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
252
222 lseek(fd, 0, SEEK_SET); 253 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 254 do_write(fd, &f_header, sizeof(f_header));
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 255 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
@@ -241,6 +272,20 @@ static void do_read(int fd, void *buf, size_t size)
241 } 272 }
242} 273}
243 274
275static void perf_header__adds_read(struct perf_header *self, int fd)
276{
277 const unsigned long *feat_mask = self->adds_features;
278
279 if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
280 struct perf_file_section trace_sec;
281
282 do_read(fd, &trace_sec, sizeof(trace_sec));
283 lseek(fd, trace_sec.offset, SEEK_SET);
284 trace_report(fd);
285 lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
286 }
287};
288
244struct perf_header *perf_header__read(int fd) 289struct perf_header *perf_header__read(int fd)
245{ 290{
246 struct perf_header *self = perf_header__new(); 291 struct perf_header *self = perf_header__new();
@@ -254,10 +299,16 @@ struct perf_header *perf_header__read(int fd)
254 do_read(fd, &f_header, sizeof(f_header)); 299 do_read(fd, &f_header, sizeof(f_header));
255 300
256 if (f_header.magic != PERF_MAGIC || 301 if (f_header.magic != PERF_MAGIC ||
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr)) 302 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format"); 303 die("incompatible file format");
260 304
305 if (f_header.size != sizeof(f_header)) {
306 /* Support the previous format */
307 if (f_header.size == offsetof(typeof(f_header), adds_features))
308 bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
309 else
310 die("incompatible file format");
311 }
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 312 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 313 lseek(fd, f_header.attrs.offset, SEEK_SET);
263 314
@@ -290,6 +341,11 @@ struct perf_header *perf_header__read(int fd)
290 do_read(fd, events, f_header.event_types.size); 341 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 342 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 343 }
344
345 memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features));
346
347 perf_header__adds_read(self, fd);
348
293 self->event_offset = f_header.event_types.offset; 349 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size; 350 self->event_size = f_header.event_types.size;
295 351
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..2ea9dfb1236a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,10 +1,12 @@
1#ifndef _PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define _PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include "types.h" 6#include "types.h"
7 7
8#include <linux/bitmap.h>
9
8struct perf_header_attr { 10struct perf_header_attr {
9 struct perf_event_attr attr; 11 struct perf_event_attr attr;
10 int ids, size; 12 int ids, size;
@@ -12,15 +14,20 @@ struct perf_header_attr {
12 off_t id_offset; 14 off_t id_offset;
13}; 15};
14 16
17#define HEADER_TRACE_INFO 1
18
19#define HEADER_FEAT_BITS 256
20
15struct perf_header { 21struct perf_header {
16 int frozen; 22 int frozen;
17 int attrs, size; 23 int attrs, size;
18 struct perf_header_attr **attr; 24 struct perf_header_attr **attr;
19 s64 attr_offset; 25 s64 attr_offset;
20 u64 data_offset; 26 u64 data_offset;
21 u64 data_size; 27 u64 data_size;
22 u64 event_offset; 28 u64 event_offset;
23 u64 event_size; 29 u64 event_size;
30 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
24}; 31};
25 32
26struct perf_header *perf_header__read(int fd); 33struct perf_header *perf_header__read(int fd);
@@ -40,8 +47,8 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
40u64 perf_header__sample_type(struct perf_header *header); 47u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 48struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 49perf_header__find_attr(u64 id, struct perf_header *header);
43 50void perf_header__feat_trace_info(struct perf_header *header);
44 51
45struct perf_header *perf_header__new(void); 52struct perf_header *perf_header__new(void);
46 53
47#endif /* _PERF_HEADER_H */ 54#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
1#ifndef HELP_H 1#ifndef __PERF_HELP_H
2#define HELP_H 2#define __PERF_HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 size_t alloc; 5 size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 27 struct cmdnames *other_cmds);
28 28
29#endif /* HELP_H */ 29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..7393a02fd8d4
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,210 @@
1#include "hist.h"
2
3struct rb_root hist;
4struct rb_root collapse_hists;
5struct rb_root output_hists;
6int callchain;
7
8struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5
11};
12
13unsigned long total;
14unsigned long total_mmap;
15unsigned long total_comm;
16unsigned long total_fork;
17unsigned long total_unknown;
18unsigned long total_lost;
19
20/*
21 * histogram, sorted on item, collects counts
22 */
23
24struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
25 struct symbol *sym,
26 struct symbol *sym_parent,
27 u64 ip, u64 count, char level, bool *hit)
28{
29 struct rb_node **p = &hist.rb_node;
30 struct rb_node *parent = NULL;
31 struct hist_entry *he;
32 struct hist_entry entry = {
33 .thread = thread,
34 .map = map,
35 .sym = sym,
36 .ip = ip,
37 .level = level,
38 .count = count,
39 .parent = sym_parent,
40 };
41 int cmp;
42
43 while (*p != NULL) {
44 parent = *p;
45 he = rb_entry(parent, struct hist_entry, rb_node);
46
47 cmp = hist_entry__cmp(&entry, he);
48
49 if (!cmp) {
50 *hit = true;
51 return he;
52 }
53
54 if (cmp < 0)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 he = malloc(sizeof(*he));
61 if (!he)
62 return NULL;
63 *he = entry;
64 rb_link_node(&he->rb_node, parent, p);
65 rb_insert_color(&he->rb_node, &hist);
66 *hit = false;
67 return he;
68}
69
70int64_t
71hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
72{
73 struct sort_entry *se;
74 int64_t cmp = 0;
75
76 list_for_each_entry(se, &hist_entry__sort_list, list) {
77 cmp = se->cmp(left, right);
78 if (cmp)
79 break;
80 }
81
82 return cmp;
83}
84
85int64_t
86hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
87{
88 struct sort_entry *se;
89 int64_t cmp = 0;
90
91 list_for_each_entry(se, &hist_entry__sort_list, list) {
92 int64_t (*f)(struct hist_entry *, struct hist_entry *);
93
94 f = se->collapse ?: se->cmp;
95
96 cmp = f(left, right);
97 if (cmp)
98 break;
99 }
100
101 return cmp;
102}
103
104void hist_entry__free(struct hist_entry *he)
105{
106 free(he);
107}
108
109/*
110 * collapse the histogram
111 */
112
113void collapse__insert_entry(struct hist_entry *he)
114{
115 struct rb_node **p = &collapse_hists.rb_node;
116 struct rb_node *parent = NULL;
117 struct hist_entry *iter;
118 int64_t cmp;
119
120 while (*p != NULL) {
121 parent = *p;
122 iter = rb_entry(parent, struct hist_entry, rb_node);
123
124 cmp = hist_entry__collapse(iter, he);
125
126 if (!cmp) {
127 iter->count += he->count;
128 hist_entry__free(he);
129 return;
130 }
131
132 if (cmp < 0)
133 p = &(*p)->rb_left;
134 else
135 p = &(*p)->rb_right;
136 }
137
138 rb_link_node(&he->rb_node, parent, p);
139 rb_insert_color(&he->rb_node, &collapse_hists);
140}
141
142void collapse__resort(void)
143{
144 struct rb_node *next;
145 struct hist_entry *n;
146
147 if (!sort__need_collapse)
148 return;
149
150 next = rb_first(&hist);
151 while (next) {
152 n = rb_entry(next, struct hist_entry, rb_node);
153 next = rb_next(&n->rb_node);
154
155 rb_erase(&n->rb_node, &hist);
156 collapse__insert_entry(n);
157 }
158}
159
160/*
161 * reverse the map, sort on count.
162 */
163
164void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
165{
166 struct rb_node **p = &output_hists.rb_node;
167 struct rb_node *parent = NULL;
168 struct hist_entry *iter;
169
170 if (callchain)
171 callchain_param.sort(&he->sorted_chain, &he->callchain,
172 min_callchain_hits, &callchain_param);
173
174 while (*p != NULL) {
175 parent = *p;
176 iter = rb_entry(parent, struct hist_entry, rb_node);
177
178 if (he->count > iter->count)
179 p = &(*p)->rb_left;
180 else
181 p = &(*p)->rb_right;
182 }
183
184 rb_link_node(&he->rb_node, parent, p);
185 rb_insert_color(&he->rb_node, &output_hists);
186}
187
188void output__resort(u64 total_samples)
189{
190 struct rb_node *next;
191 struct hist_entry *n;
192 struct rb_root *tree = &hist;
193 u64 min_callchain_hits;
194
195 min_callchain_hits =
196 total_samples * (callchain_param.min_percent / 100);
197
198 if (sort__need_collapse)
199 tree = &collapse_hists;
200
201 next = rb_first(tree);
202
203 while (next) {
204 n = rb_entry(next, struct hist_entry, rb_node);
205 next = rb_next(&n->rb_node);
206
207 rb_erase(&n->rb_node, tree);
208 output__insert_entry(n, min_callchain_hits);
209 }
210}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..ac2149c559b0
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,50 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38
39struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
40 struct symbol *sym, struct symbol *parent,
41 u64 ip, u64 count, char level, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49
50#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..821c1033bccf
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,2 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..ace57c36d1d0
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10static inline void set_bit(int nr, unsigned long *addr)
11{
12 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
13}
14
15static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
16{
17 return ((1UL << (nr % BITS_PER_LONG)) &
18 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
19}
20
21unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
22 long size, unsigned long offset);
23
24unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
25 long size, unsigned long offset);
26
27#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..bae5783282ef
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../../../../include/linux/ctype.h"
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..21c0274c02fa 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -1,6 +1,16 @@
1#ifndef PERF_LINUX_KERNEL_H_ 1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_ 2#define PERF_LINUX_KERNEL_H_
3 3
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8
9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
10
11#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
12#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
13
4#ifndef offsetof 14#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif 16#endif
@@ -26,4 +36,70 @@
26 _max1 > _max2 ? _max1 : _max2; }) 36 _max1 > _max2 ? _max1 : _max2; })
27#endif 37#endif
28 38
39#ifndef min
40#define min(x, y) ({ \
41 typeof(x) _min1 = (x); \
42 typeof(y) _min2 = (y); \
43 (void) (&_min1 == &_min2); \
44 _min1 < _min2 ? _min1 : _min2; })
45#endif
46
47#ifndef BUG_ON
48#define BUG_ON(cond) assert(!(cond))
49#endif
50
51/*
52 * Both need more care to handle endianness
53 * (Don't use bitmap_copy_le() for now)
54 */
55#define cpu_to_le64(x) (x)
56#define cpu_to_le32(x) (x)
57
58static inline int
59vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
60{
61 int i;
62 ssize_t ssize = size;
63
64 i = vsnprintf(buf, size, fmt, args);
65
66 return (i >= ssize) ? (ssize - 1) : i;
67}
68
69static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
70{
71 va_list args;
72 ssize_t ssize = size;
73 int i;
74
75 va_start(args, fmt);
76 i = vsnprintf(buf, size, fmt, args);
77 va_end(args);
78
79 return (i >= ssize) ? (ssize - 1) : i;
80}
81
82static inline unsigned long
83simple_strtoul(const char *nptr, char **endptr, int base)
84{
85 return strtoul(nptr, endptr, base);
86}
87
88#ifndef pr_fmt
89#define pr_fmt(fmt) fmt
90#endif
91
92#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
94#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
96#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
98#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104
29#endif 105#endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644
index 000000000000..3b2f5900276f
--- /dev/null
+++ b/tools/perf/util/include/linux/string.h
@@ -0,0 +1 @@
#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644
index 000000000000..196862a81a21
--- /dev/null
+++ b/tools/perf/util/include/linux/types.h
@@ -0,0 +1,9 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#define DECLARE_BITMAP(name,bits) \
7 unsigned long name[BITS_TO_LONGS(bits)]
8
9#endif
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
1#ifndef LEVENSHTEIN_H 1#ifndef __PERF_LEVENSHTEIN_H
2#define LEVENSHTEIN_H 2#define __PERF_LEVENSHTEIN_H
3 3
4int levenshtein(const char *string1, const char *string2, 4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty, 5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty); 6 int insertion_penalty, int deletion_penalty);
7 7
8#endif 8#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..c1c556825343 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h"
6 7
7static inline int is_anon_memory(const char *filename) 8static inline int is_anon_memory(const char *filename)
8{ 9{
@@ -19,7 +20,8 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 return n; 20 return n;
20} 21}
21 22
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) 23struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
24 unsigned int sym_priv_size, symbol_filter_t filter)
23{ 25{
24 struct map *self = malloc(sizeof(*self)); 26 struct map *self = malloc(sizeof(*self));
25 27
@@ -27,6 +29,7 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
27 const char *filename = event->filename; 29 const char *filename = event->filename;
28 char newfilename[PATH_MAX]; 30 char newfilename[PATH_MAX];
29 int anon; 31 int anon;
32 bool new_dso;
30 33
31 if (cwd) { 34 if (cwd) {
32 int n = strcommon(filename, cwd, cwdlen); 35 int n = strcommon(filename, cwd, cwdlen);
@@ -49,14 +52,29 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
49 self->end = event->start + event->len; 52 self->end = event->start + event->len;
50 self->pgoff = event->pgoff; 53 self->pgoff = event->pgoff;
51 54
52 self->dso = dsos__findnew(filename); 55 self->dso = dsos__findnew(filename, sym_priv_size, &new_dso);
53 if (self->dso == NULL) 56 if (self->dso == NULL)
54 goto out_delete; 57 goto out_delete;
55 58
59 if (new_dso) {
60 int nr = dso__load(self->dso, self, filter);
61
62 if (nr < 0)
63 pr_warning("Failed to open %s, continuing "
64 "without symbols\n",
65 self->dso->long_name);
66 else if (nr == 0)
67 pr_warning("No symbols found in %s, maybe "
68 "install a debug package?\n",
69 self->dso->long_name);
70 }
71
56 if (self->dso == vdso || anon) 72 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip; 73 self->map_ip = self->unmap_ip = identity__map_ip;
58 else 74 else {
59 self->map_ip = map__map_ip; 75 self->map_ip = map__map_ip;
76 self->unmap_ip = map__unmap_ip;
77 }
60 } 78 }
61 return self; 79 return self;
62out_delete: 80out_delete:
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..b097570e9623 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -8,9 +8,10 @@
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10 10
11int nr_counters; 11int nr_counters;
12 12
13struct perf_event_attr attrs[MAX_COUNTERS]; 13struct perf_event_attr attrs[MAX_COUNTERS];
14char *filters[MAX_COUNTERS];
14 15
15struct event_symbol { 16struct event_symbol {
16 u8 type; 17 u8 type;
@@ -708,7 +709,6 @@ static void store_event_type(const char *orgname)
708 perf_header__push_event(id, orgname); 709 perf_header__push_event(id, orgname);
709} 710}
710 711
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 712int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 713{
714 struct perf_event_attr attr; 714 struct perf_event_attr attr;
@@ -745,6 +745,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 745 return 0;
746} 746}
747 747
748int parse_filter(const struct option *opt __used, const char *str,
749 int unset __used)
750{
751 int i = nr_counters - 1;
752 int len = strlen(str);
753
754 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
755 fprintf(stderr,
756 "-F option should follow a -e tracepoint option\n");
757 return -1;
758 }
759
760 filters[i] = malloc(len + 1);
761 if (!filters[i]) {
762 fprintf(stderr, "not enough memory to hold filter string\n");
763 return -1;
764 }
765 strcpy(filters[i], str);
766
767 return 0;
768}
769
748static const char * const event_type_descriptors[] = { 770static const char * const event_type_descriptors[] = {
749 "", 771 "",
750 "Hardware event", 772 "Hardware event",
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
1#ifndef _PARSE_EVENTS_H 1#ifndef __PERF_PARSE_EVENTS_H
2#define _PARSE_EVENTS_H 2#define __PERF_PARSE_EVENTS_H
3/* 3/*
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
17extern int nr_counters; 17extern int nr_counters;
18 18
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
20extern char *filters[MAX_COUNTERS];
20 21
21extern const char *event_name(int ctr); 22extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config); 23extern const char *__event_name(int type, u64 config);
23 24
24extern int parse_events(const struct option *opt, const char *str, int unset); 25extern int parse_events(const struct option *opt, const char *str, int unset);
26extern int parse_filter(const struct option *opt, const char *str, int unset);
25 27
26#define EVENTS_HELP_MAX (128*1024) 28#define EVENTS_HELP_MAX (128*1024)
27 29
@@ -31,4 +33,4 @@ extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs); 33extern int valid_debugfs_mount(const char *debugfs);
32 34
33 35
34#endif /* _PARSE_EVENTS_H */ 36#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
1#ifndef PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4enum parse_opt_type { 4enum parse_opt_type {
5 /* special types */ 5 /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
174 174
175extern const char *parse_options_fix_filename(const char *prefix, const char *file); 175extern const char *parse_options_fix_filename(const char *prefix, const char *file);
176 176
177#endif 177#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
1#ifndef QUOTE_H 1#ifndef __PERF_QUOTE_H
2#define QUOTE_H 2#define __PERF_QUOTE_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <stdio.h> 5#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src); 65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src); 66extern void tcl_quote_print(FILE *stream, const char *src);
67 67
68#endif 68#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
1#ifndef RUN_COMMAND_H 1#ifndef __PERF_RUN_COMMAND_H
2#define RUN_COMMAND_H 2#define __PERF_RUN_COMMAND_H
3 3
4enum { 4enum {
5 ERR_RUN_COMMAND_FORK = 10000, 5 ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
85int start_async(struct async *async); 85int start_async(struct async *async);
86int finish_async(struct async *async); 86int finish_async(struct async *async);
87 87
88#endif 88#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..b490354d1b23
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,290 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
12
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;
18
19LIST_HEAD(hist_entry__sort_list);
20
21struct sort_entry sort_thread = {
22 .header = "Command: Pid",
23 .cmp = sort__thread_cmp,
24 .print = sort__thread_print,
25 .width = &threads__col_width,
26};
27
28struct sort_entry sort_comm = {
29 .header = "Command",
30 .cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse,
32 .print = sort__comm_print,
33 .width = &comms__col_width,
34};
35
36struct sort_entry sort_dso = {
37 .header = "Shared Object",
38 .cmp = sort__dso_cmp,
39 .print = sort__dso_print,
40 .width = &dsos__col_width,
41};
42
43struct sort_entry sort_sym = {
44 .header = "Symbol",
45 .cmp = sort__sym_cmp,
46 .print = sort__sym_print,
47};
48
49struct sort_entry sort_parent = {
50 .header = "Parent symbol",
51 .cmp = sort__parent_cmp,
52 .print = sort__parent_print,
53 .width = &parent_symbol__col_width,
54};
55
56struct sort_dimension {
57 const char *name;
58 struct sort_entry *entry;
59 int taken;
60};
61
62static struct sort_dimension sort_dimensions[] = {
63 { .name = "pid", .entry = &sort_thread, },
64 { .name = "comm", .entry = &sort_comm, },
65 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, },
68};
69
70int64_t cmp_null(void *l, void *r)
71{
72 if (!l && !r)
73 return 0;
74 else if (!l)
75 return -1;
76 else
77 return 1;
78}
79
80/* --sort pid */
81
82int64_t
83sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
84{
85 return right->thread->pid - left->thread->pid;
86}
87
88int repsep_fprintf(FILE *fp, const char *fmt, ...)
89{
90 int n;
91 va_list ap;
92
93 va_start(ap, fmt);
94 if (!field_sep)
95 n = vfprintf(fp, fmt, ap);
96 else {
97 char *bf = NULL;
98 n = vasprintf(&bf, fmt, ap);
99 if (n > 0) {
100 char *sep = bf;
101
102 while (1) {
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 }
109 fputs(bf, fp);
110 free(bf);
111 }
112 va_end(ap);
113 return n;
114}
115
116size_t
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
118{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6,
120 self->thread->comm ?: "", self->thread->pid);
121}
122
123size_t
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
125{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
127}
128
129/* --sort dso */
130
131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL;
136 const char *dso_name_l, *dso_name_r;
137
138 if (!dso_l || !dso_r)
139 return cmp_null(dso_l, dso_r);
140
141 if (verbose) {
142 dso_name_l = dso_l->long_name;
143 dso_name_r = dso_r->long_name;
144 } else {
145 dso_name_l = dso_l->short_name;
146 dso_name_r = dso_r->short_name;
147 }
148
149 return strcmp(dso_name_l, dso_name_r);
150}
151
152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{
155 if (self->map && self->map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name :
157 self->map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 }
160
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
162}
163
164/* --sort symbol */
165
166int64_t
167sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{
169 u64 ip_l, ip_r;
170
171 if (left->sym == right->sym)
172 return 0;
173
174 ip_l = left->sym ? left->sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180
181size_t
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{
184 size_t ret = 0;
185
186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 }
190
191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name);
194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196
197 return ret;
198}
199
200/* --sort comm */
201
202int64_t
203sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
204{
205 return right->thread->pid - left->thread->pid;
206}
207
208int64_t
209sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
210{
211 char *comm_l = left->thread->comm;
212 char *comm_r = right->thread->comm;
213
214 if (!comm_l || !comm_r)
215 return cmp_null(comm_l, comm_r);
216
217 return strcmp(comm_l, comm_r);
218}
219
220/* --sort parent */
221
222int64_t
223sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
224{
225 struct symbol *sym_l = left->parent;
226 struct symbol *sym_r = right->parent;
227
228 if (!sym_l || !sym_r)
229 return cmp_null(sym_l, sym_r);
230
231 return strcmp(sym_l->name, sym_r->name);
232}
233
234size_t
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
236{
237 return repsep_fprintf(fp, "%-*s", width,
238 self->parent ? self->parent->name : "[other]");
239}
240
241int sort_dimension__add(const char *tok)
242{
243 unsigned int i;
244
245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
246 struct sort_dimension *sd = &sort_dimensions[i];
247
248 if (sd->taken)
249 continue;
250
251 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue;
253
254 if (sd->entry->collapse)
255 sort__need_collapse = 1;
256
257 if (sd->entry == &sort_parent) {
258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
259 if (ret) {
260 char err[BUFSIZ];
261
262 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s",
264 parent_pattern, err);
265 exit(-1);
266 }
267 sort__has_parent = 1;
268 }
269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
284 sd->taken = 1;
285
286 return 0;
287 }
288
289 return -ESRCH;
290}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..333e664ff45f
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,99 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
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;
43
44struct hist_entry {
45 struct rb_node rb_node;
46 u64 count;
47 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip;
51 char level;
52 struct symbol *parent;
53 struct callchain_node callchain;
54 struct rb_root sorted_chain;
55};
56
57enum sort_type {
58 SORT_PID,
59 SORT_COMM,
60 SORT_DSO,
61 SORT_SYM,
62 SORT_PARENT
63};
64
65/*
66 * configurable sorting bits
67 */
68
69struct sort_entry {
70 struct list_head list;
71
72 const char *header;
73
74 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
75 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
76 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
77 unsigned int *width;
78 bool elide;
79};
80
81extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list;
83
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
87extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
88extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
89extern int64_t cmp_null(void *, void *);
90extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
91extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
92extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
93extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
94extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *);
98
99#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..04743d3e9039 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,3 +1,4 @@
1#include <string.h>
1#include "string.h" 2#include "string.h"
2 3
3static int hex(char ch) 4static int hex(char ch)
@@ -32,3 +33,13 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..2c84bf65ba0f 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,12 @@
1#ifndef _PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include "types.h" 4#include "types.h"
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to);
7 8
8#define _STR(x) #x 9#define _STR(x) #x
9#define STR(x) _STR(x) 10#define STR(x) _STR(x)
10 11
11#endif 12#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..cb4659306d7b 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
36} 36}
37 37
38int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */ 39#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 856655d8b0b8..b3637db025a2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -103,7 +103,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 106 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n"); 108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n"); 109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 47ea0609a760..8f0208ce237a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2,14 +2,14 @@
2#include "../perf.h" 2#include "../perf.h"
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5#include "thread.h"
5 6
6#include "debug.h" 7#include "debug.h"
7 8
8#include <libelf.h> 9#include <libelf.h>
9#include <gelf.h> 10#include <gelf.h>
10#include <elf.h> 11#include <elf.h>
11 12#include <sys/utsname.h>
12const char *sym_hist_filter;
13 13
14enum dso_origin { 14enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 15 DSO__ORIG_KERNEL = 0,
@@ -18,12 +18,65 @@ enum dso_origin {
18 DSO__ORIG_UBUNTU, 18 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 19 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 20 DSO__ORIG_DSO,
21 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 22 DSO__ORIG_NOT_FOUND,
22}; 23};
23 24
24static struct symbol *symbol__new(u64 start, u64 len, 25static void dsos__add(struct dso *dso);
25 const char *name, unsigned int priv_size, 26static struct dso *dsos__find(const char *name);
26 u64 obj_start, int v) 27static struct map *map__new2(u64 start, struct dso *dso);
28static void kernel_maps__insert(struct map *map);
29
30static struct rb_root kernel_maps;
31
32static void dso__fixup_sym_end(struct dso *self)
33{
34 struct rb_node *nd, *prevnd = rb_first(&self->syms);
35 struct symbol *curr, *prev;
36
37 if (prevnd == NULL)
38 return;
39
40 curr = rb_entry(prevnd, struct symbol, rb_node);
41
42 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
43 prev = curr;
44 curr = rb_entry(nd, struct symbol, rb_node);
45
46 if (prev->end == prev->start)
47 prev->end = curr->start - 1;
48 }
49
50 /* Last entry */
51 if (curr->end == curr->start)
52 curr->end = roundup(curr->start, 4096);
53}
54
55static void kernel_maps__fixup_end(void)
56{
57 struct map *prev, *curr;
58 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
59
60 if (prevnd == NULL)
61 return;
62
63 curr = rb_entry(prevnd, struct map, rb_node);
64
65 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
66 prev = curr;
67 curr = rb_entry(nd, struct map, rb_node);
68 prev->end = curr->start - 1;
69 }
70
71 nd = rb_last(&curr->dso->syms);
72 if (nd) {
73 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
74 curr->end = sym->end;
75 }
76}
77
78static struct symbol *symbol__new(u64 start, u64 len, const char *name,
79 unsigned int priv_size)
27{ 80{
28 size_t namelen = strlen(name) + 1; 81 size_t namelen = strlen(name) + 1;
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 82 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -31,23 +84,15 @@ static struct symbol *symbol__new(u64 start, u64 len,
31 if (!self) 84 if (!self)
32 return NULL; 85 return NULL;
33 86
34 if (v >= 2)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
37
38 self->obj_start= obj_start;
39 self->hist = NULL;
40 self->hist_sum = 0;
41
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
43 self->hist = calloc(sizeof(u64), len);
44
45 if (priv_size) { 87 if (priv_size) {
46 memset(self, 0, priv_size); 88 memset(self, 0, priv_size);
47 self = ((void *)self) + priv_size; 89 self = ((void *)self) + priv_size;
48 } 90 }
49 self->start = start; 91 self->start = start;
50 self->end = len ? start + len - 1 : start; 92 self->end = len ? start + len - 1 : start;
93
94 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
95
51 memcpy(self->name, name, namelen); 96 memcpy(self->name, name, namelen);
52 97
53 return self; 98 return self;
@@ -60,12 +105,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
60 105
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 106static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 107{
63 if (!self->module) 108 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 109 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
69} 110}
70 111
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 112struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -74,6 +115,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
74 115
75 if (self != NULL) { 116 if (self != NULL) {
76 strcpy(self->name, name); 117 strcpy(self->name, name);
118 self->long_name = self->name;
119 self->short_name = self->name;
77 self->syms = RB_ROOT; 120 self->syms = RB_ROOT;
78 self->sym_priv_size = sym_priv_size; 121 self->sym_priv_size = sym_priv_size;
79 self->find_symbol = dso__find_symbol; 122 self->find_symbol = dso__find_symbol;
@@ -100,6 +143,8 @@ static void dso__delete_symbols(struct dso *self)
100void dso__delete(struct dso *self) 143void dso__delete(struct dso *self)
101{ 144{
102 dso__delete_symbols(self); 145 dso__delete_symbols(self);
146 if (self->long_name != self->name)
147 free(self->long_name);
103 free(self); 148 free(self);
104} 149}
105 150
@@ -147,7 +192,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
147 192
148size_t dso__fprintf(struct dso *self, FILE *fp) 193size_t dso__fprintf(struct dso *self, FILE *fp)
149{ 194{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 195 size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
151 196
152 struct rb_node *nd; 197 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 198 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,13 +203,16 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 203 return ret;
159} 204}
160 205
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 206/*
207 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
208 * so that we can in the next step set the symbol ->end address and then
209 * call kernel_maps__split_kallsyms.
210 */
211static int kernel_maps__load_all_kallsyms(void)
162{ 212{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 213 char *line = NULL;
165 size_t n; 214 size_t n;
166 FILE *file = fopen("/proc/kallsyms", "r"); 215 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 216
169 if (file == NULL) 217 if (file == NULL)
170 goto out_failure; 218 goto out_failure;
@@ -174,6 +222,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 222 struct symbol *sym;
175 int line_len, len; 223 int line_len, len;
176 char symbol_type; 224 char symbol_type;
225 char *symbol_name;
177 226
178 line_len = getline(&line, &n, file); 227 line_len = getline(&line, &n, file);
179 if (line_len < 0) 228 if (line_len < 0)
@@ -196,44 +245,24 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
196 */ 245 */
197 if (symbol_type != 'T' && symbol_type != 'W') 246 if (symbol_type != 'T' && symbol_type != 'W')
198 continue; 247 continue;
248
249 symbol_name = line + len + 2;
199 /* 250 /*
200 * Well fix up the end later, when we have all sorted. 251 * Will fix up the end later, when we have all symbols sorted.
201 */ 252 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 253 sym = symbol__new(start, 0, symbol_name,
203 self->sym_priv_size, 0, v); 254 kernel_map->dso->sym_priv_size);
204 255
205 if (sym == NULL) 256 if (sym == NULL)
206 goto out_delete_line; 257 goto out_delete_line;
207 258
208 if (filter && filter(self, sym)) 259 dso__insert_symbol(kernel_map->dso, sym);
209 symbol__delete(sym, self->sym_priv_size);
210 else {
211 dso__insert_symbol(self, sym);
212 count++;
213 }
214 }
215
216 /*
217 * Now that we have all sorted out, just set the ->end of all
218 * symbols
219 */
220 prevnd = rb_first(&self->syms);
221
222 if (prevnd == NULL)
223 goto out_delete_line;
224
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
227 *curr = rb_entry(nd, struct symbol, rb_node);
228
229 prev->end = curr->start - 1;
230 prevnd = nd;
231 } 260 }
232 261
233 free(line); 262 free(line);
234 fclose(file); 263 fclose(file);
235 264
236 return count; 265 return 0;
237 266
238out_delete_line: 267out_delete_line:
239 free(line); 268 free(line);
@@ -241,14 +270,124 @@ out_failure:
241 return -1; 270 return -1;
242} 271}
243 272
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 273/*
274 * Split the symbols into maps, making sure there are no overlaps, i.e. the
275 * kernel range is broken in several maps, named [kernel].N, as we don't have
276 * the original ELF section names vmlinux have.
277 */
278static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
279{
280 struct map *map = kernel_map;
281 struct symbol *pos;
282 int count = 0;
283 struct rb_node *next = rb_first(&kernel_map->dso->syms);
284 int kernel_range = 0;
285
286 while (next) {
287 char *module;
288
289 pos = rb_entry(next, struct symbol, rb_node);
290 next = rb_next(&pos->rb_node);
291
292 module = strchr(pos->name, '\t');
293 if (module) {
294 if (!use_modules)
295 goto delete_symbol;
296
297 *module++ = '\0';
298
299 if (strcmp(map->dso->name, module)) {
300 map = kernel_maps__find_by_dso_name(module);
301 if (!map) {
302 pr_err("/proc/{kallsyms,modules} "
303 "inconsistency!\n");
304 return -1;
305 }
306 }
307 /*
308 * So that we look just like we get from .ko files,
309 * i.e. not prelinked, relative to map->start.
310 */
311 pos->start = map->map_ip(map, pos->start);
312 pos->end = map->map_ip(map, pos->end);
313 } else if (map != kernel_map) {
314 char dso_name[PATH_MAX];
315 struct dso *dso;
316
317 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
318 kernel_range++);
319
320 dso = dso__new(dso_name,
321 kernel_map->dso->sym_priv_size);
322 if (dso == NULL)
323 return -1;
324
325 map = map__new2(pos->start, dso);
326 if (map == NULL) {
327 dso__delete(dso);
328 return -1;
329 }
330
331 map->map_ip = map->unmap_ip = identity__map_ip;
332 kernel_maps__insert(map);
333 ++kernel_range;
334 }
335
336 if (filter && filter(map, pos)) {
337delete_symbol:
338 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
339 symbol__delete(pos, kernel_map->dso->sym_priv_size);
340 } else {
341 if (map != kernel_map) {
342 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
343 dso__insert_symbol(map->dso, pos);
344 }
345 count++;
346 }
347 }
348
349 return count;
350}
351
352
353static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules)
354{
355 if (kernel_maps__load_all_kallsyms())
356 return -1;
357
358 dso__fixup_sym_end(kernel_map->dso);
359
360 return kernel_maps__split_kallsyms(filter, use_modules);
361}
362
363static size_t kernel_maps__fprintf(FILE *fp)
364{
365 size_t printed = fprintf(fp, "Kernel maps:\n");
366 struct rb_node *nd;
367
368 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
369 struct map *pos = rb_entry(nd, struct map, rb_node);
370
371 printed += fprintf(fp, "Map:");
372 printed += map__fprintf(pos, fp);
373 if (verbose > 1) {
374 printed += dso__fprintf(pos->dso, fp);
375 printed += fprintf(fp, "--\n");
376 }
377 }
378
379 return printed + fprintf(fp, "END kernel maps\n");
380}
381
382static int dso__load_perf_map(struct dso *self, struct map *map,
383 symbol_filter_t filter)
245{ 384{
246 char *line = NULL; 385 char *line = NULL;
247 size_t n; 386 size_t n;
248 FILE *file; 387 FILE *file;
249 int nr_syms = 0; 388 int nr_syms = 0;
250 389
251 file = fopen(self->name, "r"); 390 file = fopen(self->long_name, "r");
252 if (file == NULL) 391 if (file == NULL)
253 goto out_failure; 392 goto out_failure;
254 393
@@ -279,12 +418,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
279 continue; 418 continue;
280 419
281 sym = symbol__new(start, size, line + len, 420 sym = symbol__new(start, size, line + len,
282 self->sym_priv_size, start, v); 421 self->sym_priv_size);
283 422
284 if (sym == NULL) 423 if (sym == NULL)
285 goto out_delete_line; 424 goto out_delete_line;
286 425
287 if (filter && filter(self, sym)) 426 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 427 symbol__delete(sym, self->sym_priv_size);
289 else { 428 else {
290 dso__insert_symbol(self, sym); 429 dso__insert_symbol(self, sym);
@@ -393,7 +532,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
393 * And always look at the original dso, not at debuginfo packages, that 532 * And always look at the original dso, not at debuginfo packages, that
394 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 533 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 534 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 535static int dso__synthesize_plt_symbols(struct dso *self)
397{ 536{
398 uint32_t nr_rel_entries, idx; 537 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 538 GElf_Sym sym;
@@ -409,7 +548,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 548 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 549 int nr = 0, symidx, fd, err = 0;
411 550
412 fd = open(self->name, O_RDONLY); 551 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 552 if (fd < 0)
414 goto out; 553 goto out;
415 554
@@ -477,7 +616,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 616 "%s@plt", elf_sym__name(&sym, symstrs));
478 617
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 618 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 619 sympltname, self->sym_priv_size);
481 if (!f) 620 if (!f)
482 goto out_elf_end; 621 goto out_elf_end;
483 622
@@ -495,7 +634,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 634 "%s@plt", elf_sym__name(&sym, symstrs));
496 635
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 636 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 637 sympltname, self->sym_priv_size);
499 if (!f) 638 if (!f)
500 goto out_elf_end; 639 goto out_elf_end;
501 640
@@ -513,14 +652,18 @@ out_close:
513 if (err == 0) 652 if (err == 0)
514 return nr; 653 return nr;
515out: 654out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 655 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 656 __func__, self->long_name);
518 return 0; 657 return 0;
519} 658}
520 659
521static int dso__load_sym(struct dso *self, int fd, const char *name, 660static int dso__load_sym(struct dso *self, struct map *map, const char *name,
522 symbol_filter_t filter, int v, struct module *mod) 661 int fd, symbol_filter_t filter, int kernel,
662 int kmodule)
523{ 663{
664 struct map *curr_map = map;
665 struct dso *curr_dso = self;
666 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 667 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 668 uint32_t nr_syms;
526 int err = -1; 669 int err = -1;
@@ -531,19 +674,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 674 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 675 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 676 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 677 int nr = 0;
535 678
536 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 680 if (elf == NULL) {
538 if (v) 681 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
539 fprintf(stderr, "%s: cannot read %s ELF file.\n",
540 __func__, name);
541 goto out_close; 682 goto out_close;
542 } 683 }
543 684
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 685 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 686 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 687 goto out_elf_end;
548 } 688 }
549 689
@@ -587,9 +727,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 727 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 728 struct symbol *f;
589 const char *elf_name; 729 const char *elf_name;
590 char *demangled; 730 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 731 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 732 const char *section_name;
595 733
@@ -605,52 +743,85 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 743 if (is_label && !elf_sec__is_text(&shdr, secstrs))
606 continue; 744 continue;
607 745
746 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 747 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 748
611 if (self->adjust_symbols) { 749 if (kernel || kmodule) {
612 if (v >= 2) 750 char dso_name[PATH_MAX];
613 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615 751
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 752 if (strcmp(section_name,
617 } 753 curr_dso->short_name + dso_name_len) == 0)
754 goto new_symbol;
618 755
619 if (mod) { 756 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 757 curr_map = map;
621 if (section) 758 curr_dso = self;
622 sym.st_value += section->vma; 759 goto new_symbol;
623 else {
624 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
625 mod->name, section_name);
626 goto out_elf_end;
627 } 760 }
761
762 snprintf(dso_name, sizeof(dso_name),
763 "%s%s", self->short_name, section_name);
764
765 curr_map = kernel_maps__find_by_dso_name(dso_name);
766 if (curr_map == NULL) {
767 u64 start = sym.st_value;
768
769 if (kmodule)
770 start += map->start + shdr.sh_offset;
771
772 curr_dso = dso__new(dso_name, self->sym_priv_size);
773 if (curr_dso == NULL)
774 goto out_elf_end;
775 curr_map = map__new2(start, curr_dso);
776 if (curr_map == NULL) {
777 dso__delete(curr_dso);
778 goto out_elf_end;
779 }
780 curr_map->map_ip = identity__map_ip;
781 curr_map->unmap_ip = identity__map_ip;
782 curr_dso->origin = DSO__ORIG_KERNEL;
783 kernel_maps__insert(curr_map);
784 dsos__add(curr_dso);
785 } else
786 curr_dso = curr_map->dso;
787
788 goto new_symbol;
789 }
790
791 if (curr_dso->adjust_symbols) {
792 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
793 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
794 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
795 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 796 }
629 /* 797 /*
630 * We need to figure out if the object was created from C++ sources 798 * We need to figure out if the object was created from C++ sources
631 * DWARF DW_compile_unit has this, but we don't always have access 799 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 800 * to it...
633 */ 801 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 802 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 803 if (demangled != NULL)
637 elf_name = demangled; 804 elf_name = demangled;
638 805new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 806 f = symbol__new(sym.st_value, sym.st_size, elf_name,
640 self->sym_priv_size, obj_start, v); 807 curr_dso->sym_priv_size);
641 free(demangled); 808 free(demangled);
642 if (!f) 809 if (!f)
643 goto out_elf_end; 810 goto out_elf_end;
644 811
645 if (filter && filter(self, f)) 812 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 813 symbol__delete(f, curr_dso->sym_priv_size);
647 else { 814 else {
648 f->module = mod; 815 dso__insert_symbol(curr_dso, f);
649 dso__insert_symbol(self, f);
650 nr++; 816 nr++;
651 } 817 }
652 } 818 }
653 819
820 /*
821 * For misannotated, zeroed, ASM function sizes.
822 */
823 if (nr > 0)
824 dso__fixup_sym_end(self);
654 err = nr; 825 err = nr;
655out_elf_end: 826out_elf_end:
656 elf_end(elf); 827 elf_end(elf);
@@ -660,7 +831,7 @@ out_close:
660 831
661#define BUILD_ID_SIZE 128 832#define BUILD_ID_SIZE 128
662 833
663static char *dso__read_build_id(struct dso *self, int v) 834static char *dso__read_build_id(struct dso *self)
664{ 835{
665 int i; 836 int i;
666 GElf_Ehdr ehdr; 837 GElf_Ehdr ehdr;
@@ -670,22 +841,20 @@ static char *dso__read_build_id(struct dso *self, int v)
670 char *build_id = NULL, *bid; 841 char *build_id = NULL, *bid;
671 unsigned char *raw; 842 unsigned char *raw;
672 Elf *elf; 843 Elf *elf;
673 int fd = open(self->name, O_RDONLY); 844 int fd = open(self->long_name, O_RDONLY);
674 845
675 if (fd < 0) 846 if (fd < 0)
676 goto out; 847 goto out;
677 848
678 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 849 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 850 if (elf == NULL) {
680 if (v) 851 pr_err("%s: cannot read %s ELF file.\n", __func__,
681 fprintf(stderr, "%s: cannot read %s ELF file.\n", 852 self->long_name);
682 __func__, self->name);
683 goto out_close; 853 goto out_close;
684 } 854 }
685 855
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 856 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 857 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 858 goto out_elf_end;
690 } 859 }
691 860
@@ -707,8 +876,7 @@ static char *dso__read_build_id(struct dso *self, int v)
707 ++raw; 876 ++raw;
708 bid += 2; 877 bid += 2;
709 } 878 }
710 if (v >= 2) 879 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 880out_elf_end:
713 elf_end(elf); 881 elf_end(elf);
714out_close: 882out_close:
@@ -726,6 +894,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 894 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 895 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 896 [DSO__ORIG_DSO] = 'd',
897 [DSO__ORIG_KMODULE] = 'K',
729 }; 898 };
730 899
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 900 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,7 +902,7 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 902 return origin[self->origin];
734} 903}
735 904
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 905int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
737{ 906{
738 int size = PATH_MAX; 907 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 908 char *name = malloc(size), *build_id = NULL;
@@ -746,7 +915,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
746 self->adjust_symbols = 0; 915 self->adjust_symbols = 0;
747 916
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 917 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 918 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 919 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 920 DSO__ORIG_NOT_FOUND;
752 return ret; 921 return ret;
@@ -759,13 +928,15 @@ more:
759 self->origin++; 928 self->origin++;
760 switch (self->origin) { 929 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 930 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 931 snprintf(name, size, "/usr/lib/debug%s.debug",
932 self->long_name);
763 break; 933 break;
764 case DSO__ORIG_UBUNTU: 934 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 935 snprintf(name, size, "/usr/lib/debug%s",
936 self->long_name);
766 break; 937 break;
767 case DSO__ORIG_BUILDID: 938 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 939 build_id = dso__read_build_id(self);
769 if (build_id != NULL) { 940 if (build_id != NULL) {
770 snprintf(name, size, 941 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 942 "/usr/lib/debug/.build-id/%.2s/%s.debug",
@@ -776,7 +947,7 @@ more:
776 self->origin++; 947 self->origin++;
777 /* Fall thru */ 948 /* Fall thru */
778 case DSO__ORIG_DSO: 949 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 950 snprintf(name, size, "%s", self->long_name);
780 break; 951 break;
781 952
782 default: 953 default:
@@ -786,7 +957,7 @@ more:
786 fd = open(name, O_RDONLY); 957 fd = open(name, O_RDONLY);
787 } while (fd < 0); 958 } while (fd < 0);
788 959
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 960 ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
790 close(fd); 961 close(fd);
791 962
792 /* 963 /*
@@ -796,7 +967,7 @@ more:
796 goto more; 967 goto more;
797 968
798 if (ret > 0) { 969 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 970 int nr_plt = dso__synthesize_plt_symbols(self);
800 if (nr_plt > 0) 971 if (nr_plt > 0)
801 ret += nr_plt; 972 ret += nr_plt;
802 } 973 }
@@ -807,137 +978,321 @@ out:
807 return ret; 978 return ret;
808} 979}
809 980
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 981struct map *kernel_map;
811 symbol_filter_t filter, int v) 982
983static void kernel_maps__insert(struct map *map)
812{ 984{
813 struct module *mod = mod_dso__find_module(mods, name); 985 maps__insert(&kernel_maps, map);
814 int err = 0, fd; 986}
815 987
816 if (mod == NULL || !mod->active) 988struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
817 return err; 989{
990 struct map *map = maps__find(&kernel_maps, ip);
818 991
819 fd = open(mod->path, O_RDONLY); 992 if (mapp)
993 *mapp = map;
820 994
821 if (fd < 0) 995 if (map) {
996 ip = map->map_ip(map, ip);
997 return map->dso->find_symbol(map->dso, ip);
998 }
999
1000 return NULL;
1001}
1002
1003struct map *kernel_maps__find_by_dso_name(const char *name)
1004{
1005 struct rb_node *nd;
1006
1007 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1008 struct map *map = rb_entry(nd, struct map, rb_node);
1009
1010 if (map->dso && strcmp(map->dso->name, name) == 0)
1011 return map;
1012 }
1013
1014 return NULL;
1015}
1016
1017static int dso__load_module_sym(struct dso *self, struct map *map,
1018 symbol_filter_t filter)
1019{
1020 int err = 0, fd = open(self->long_name, O_RDONLY);
1021
1022 if (fd < 0) {
1023 pr_err("%s: cannot open %s\n", __func__, self->long_name);
822 return err; 1024 return err;
1025 }
823 1026
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1027 err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1);
825 close(fd); 1028 close(fd);
826 1029
827 return err; 1030 return err;
828} 1031}
829 1032
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1033static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
831{ 1034{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1035 struct dirent *dent;
833 struct module *pos; 1036 int nr_symbols = 0, err;
834 struct rb_node *next; 1037 DIR *dir = opendir(dirname);
835 int err, count = 0;
836 1038
837 err = mod_dso__load_modules(mods); 1039 if (!dir) {
1040 pr_err("%s: cannot open %s dir\n", __func__, dirname);
1041 return -1;
1042 }
838 1043
839 if (err <= 0) 1044 while ((dent = readdir(dir)) != NULL) {
840 return err; 1045 char path[PATH_MAX];
1046
1047 if (dent->d_type == DT_DIR) {
1048 if (!strcmp(dent->d_name, ".") ||
1049 !strcmp(dent->d_name, ".."))
1050 continue;
1051
1052 snprintf(path, sizeof(path), "%s/%s",
1053 dirname, dent->d_name);
1054 err = dsos__load_modules_sym_dir(path, filter);
1055 if (err < 0)
1056 goto failure;
1057 } else {
1058 char *dot = strrchr(dent->d_name, '.'),
1059 dso_name[PATH_MAX];
1060 struct map *map;
1061 struct rb_node *last;
1062
1063 if (dot == NULL || strcmp(dot, ".ko"))
1064 continue;
1065 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1066 (int)(dot - dent->d_name), dent->d_name);
1067
1068 strxfrchar(dso_name, '-', '_');
1069 map = kernel_maps__find_by_dso_name(dso_name);
1070 if (map == NULL)
1071 continue;
1072
1073 snprintf(path, sizeof(path), "%s/%s",
1074 dirname, dent->d_name);
1075
1076 map->dso->long_name = strdup(path);
1077 if (map->dso->long_name == NULL)
1078 goto failure;
1079
1080 err = dso__load_module_sym(map->dso, map, filter);
1081 if (err < 0)
1082 goto failure;
1083 last = rb_last(&map->dso->syms);
1084 if (last) {
1085 struct symbol *sym;
1086 /*
1087 * We do this here as well, even having the
1088 * symbol size found in the symtab because
1089 * misannotated ASM symbols may have the size
1090 * set to zero.
1091 */
1092 dso__fixup_sym_end(map->dso);
1093
1094 sym = rb_entry(last, struct symbol, rb_node);
1095 map->end = map->start + sym->end;
1096 }
1097 }
1098 nr_symbols += err;
1099 }
841 1100
842 /* 1101 return nr_symbols;
843 * Iterate over modules, and load active symbols. 1102failure:
844 */ 1103 closedir(dir);
845 next = rb_first(&mods->mods); 1104 return -1;
846 while (next) { 1105}
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849 1106
850 if (err < 0) 1107static int dsos__load_modules_sym(symbol_filter_t filter)
851 break; 1108{
1109 struct utsname uts;
1110 char modules_path[PATH_MAX];
852 1111
853 next = rb_next(&pos->rb_node); 1112 if (uname(&uts) < 0)
854 count += err; 1113 return -1;
855 }
856 1114
857 if (err < 0) { 1115 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
858 mod_dso__delete_modules(mods); 1116 uts.release);
859 mod_dso__delete_self(mods);
860 return err;
861 }
862 1117
863 return count; 1118 return dsos__load_modules_sym_dir(modules_path, filter);
864} 1119}
865 1120
866static inline void dso__fill_symbol_holes(struct dso *self) 1121/*
1122 * Constructor variant for modules (where we know from /proc/modules where
1123 * they are loaded) and for vmlinux, where only after we load all the
1124 * symbols we'll know where it starts and ends.
1125 */
1126static struct map *map__new2(u64 start, struct dso *dso)
867{ 1127{
868 struct symbol *prev = NULL; 1128 struct map *self = malloc(sizeof(*self));
869 struct rb_node *nd;
870 1129
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1130 if (self != NULL) {
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1131 self->start = start;
1132 /*
1133 * Will be filled after we load all the symbols
1134 */
1135 self->end = 0;
873 1136
874 if (prev) { 1137 self->pgoff = 0;
875 u64 hole = 0; 1138 self->dso = dso;
876 int alias = pos->start == prev->start; 1139 self->map_ip = map__map_ip;
1140 self->unmap_ip = map__unmap_ip;
1141 RB_CLEAR_NODE(&self->rb_node);
1142 }
1143 return self;
1144}
877 1145
878 if (!alias) 1146static int dsos__load_modules(unsigned int sym_priv_size)
879 hole = prev->start - pos->end - 1; 1147{
1148 char *line = NULL;
1149 size_t n;
1150 FILE *file = fopen("/proc/modules", "r");
1151 struct map *map;
880 1152
881 if (hole || alias) { 1153 if (file == NULL)
882 if (alias) 1154 return -1;
883 pos->end = prev->end; 1155
884 else if (hole) 1156 while (!feof(file)) {
885 pos->end = prev->start - 1; 1157 char name[PATH_MAX];
886 } 1158 u64 start;
1159 struct dso *dso;
1160 char *sep;
1161 int line_len;
1162
1163 line_len = getline(&line, &n, file);
1164 if (line_len < 0)
1165 break;
1166
1167 if (!line)
1168 goto out_failure;
1169
1170 line[--line_len] = '\0'; /* \n */
1171
1172 sep = strrchr(line, 'x');
1173 if (sep == NULL)
1174 continue;
1175
1176 hex2u64(sep + 1, &start);
1177
1178 sep = strchr(line, ' ');
1179 if (sep == NULL)
1180 continue;
1181
1182 *sep = '\0';
1183
1184 snprintf(name, sizeof(name), "[%s]", line);
1185 dso = dso__new(name, sym_priv_size);
1186
1187 if (dso == NULL)
1188 goto out_delete_line;
1189
1190 map = map__new2(start, dso);
1191 if (map == NULL) {
1192 dso__delete(dso);
1193 goto out_delete_line;
887 } 1194 }
888 prev = pos; 1195
1196 dso->origin = DSO__ORIG_KMODULE;
1197 kernel_maps__insert(map);
1198 dsos__add(dso);
889 } 1199 }
1200
1201 free(line);
1202 fclose(file);
1203
1204 return 0;
1205
1206out_delete_line:
1207 free(line);
1208out_failure:
1209 return -1;
890} 1210}
891 1211
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1212static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1213 const char *vmlinux, symbol_filter_t filter)
894{ 1214{
895 int err, fd = open(vmlinux, O_RDONLY); 1215 int err, fd = open(vmlinux, O_RDONLY);
896 1216
897 if (fd < 0) 1217 if (fd < 0)
898 return -1; 1218 return -1;
899 1219
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1220 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
901
902 if (err > 0)
903 dso__fill_symbol_holes(self);
904 1221
905 close(fd); 1222 close(fd);
906 1223
907 return err; 1224 return err;
908} 1225}
909 1226
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1227int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
911 symbol_filter_t filter, int v, int use_modules) 1228 symbol_filter_t filter, int use_modules)
912{ 1229{
913 int err = -1; 1230 int err = -1;
1231 struct dso *dso = dso__new(vmlinux, sym_priv_size);
1232
1233 if (dso == NULL)
1234 return -1;
1235
1236 dso->short_name = "[kernel]";
1237 kernel_map = map__new2(0, dso);
1238 if (kernel_map == NULL)
1239 goto out_delete_dso;
1240
1241 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
1242
1243 if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
1244 pr_warning("Failed to load list of modules in use! "
1245 "Continuing...\n");
1246 use_modules = 0;
1247 }
914 1248
915 if (vmlinux) { 1249 if (vmlinux) {
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1250 err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter);
917 if (err > 0 && use_modules) { 1251 if (err > 0 && use_modules) {
918 int syms = dso__load_modules(self, filter, v); 1252 int syms = dsos__load_modules_sym(filter);
919 1253
920 if (syms < 0) { 1254 if (syms < 0)
921 fprintf(stderr, "dso__load_modules failed!\n"); 1255 pr_warning("Failed to read module symbols!"
922 return syms; 1256 " Continuing...\n");
923 } 1257 else
924 err += syms; 1258 err += syms;
925 } 1259 }
926 } 1260 }
927 1261
928 if (err <= 0) 1262 if (err <= 0)
929 err = dso__load_kallsyms(self, filter, v); 1263 err = kernel_maps__load_kallsyms(filter, use_modules);
1264
1265 if (err > 0) {
1266 struct rb_node *node = rb_first(&dso->syms);
1267 struct symbol *sym = rb_entry(node, struct symbol, rb_node);
1268
1269 kernel_map->start = sym->start;
1270 node = rb_last(&dso->syms);
1271 sym = rb_entry(node, struct symbol, rb_node);
1272 kernel_map->end = sym->end;
1273
1274 dso->origin = DSO__ORIG_KERNEL;
1275 kernel_maps__insert(kernel_map);
1276 /*
1277 * Now that we have all sorted out, just set the ->end of all
1278 * maps:
1279 */
1280 kernel_maps__fixup_end();
1281 dsos__add(dso);
930 1282
931 if (err > 0) 1283 if (verbose)
932 self->origin = DSO__ORIG_KERNEL; 1284 kernel_maps__fprintf(stderr);
1285 }
933 1286
934 return err; 1287 return err;
1288
1289out_delete_dso:
1290 dso__delete(dso);
1291 return -1;
935} 1292}
936 1293
937LIST_HEAD(dsos); 1294LIST_HEAD(dsos);
938struct dso *kernel_dso;
939struct dso *vdso; 1295struct dso *vdso;
940struct dso *hypervisor_dso;
941 1296
942const char *vmlinux_name = "vmlinux"; 1297const char *vmlinux_name = "vmlinux";
943int modules; 1298int modules;
@@ -957,33 +1312,21 @@ static struct dso *dsos__find(const char *name)
957 return NULL; 1312 return NULL;
958} 1313}
959 1314
960struct dso *dsos__findnew(const char *name) 1315struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
1316 bool *is_new)
961{ 1317{
962 struct dso *dso = dsos__find(name); 1318 struct dso *dso = dsos__find(name);
963 int nr;
964 1319
965 if (dso) 1320 if (!dso) {
966 return dso; 1321 dso = dso__new(name, sym_priv_size);
967 1322 if (dso) {
968 dso = dso__new(name, 0); 1323 dsos__add(dso);
969 if (!dso) 1324 *is_new = true;
970 goto out_delete_dso; 1325 }
971 1326 } else
972 nr = dso__load(dso, NULL, verbose); 1327 *is_new = false;
973 if (nr < 0) {
974 eprintf("Failed to open: %s\n", name);
975 goto out_delete_dso;
976 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1328
982 return dso; 1329 return dso;
983
984out_delete_dso:
985 dso__delete(dso);
986 return NULL;
987} 1330}
988 1331
989void dsos__fprintf(FILE *fp) 1332void dsos__fprintf(FILE *fp)
@@ -994,43 +1337,21 @@ void dsos__fprintf(FILE *fp)
994 dso__fprintf(pos, fp); 1337 dso__fprintf(pos, fp);
995} 1338}
996 1339
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1340int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter)
998{
999 return dso__find_symbol(dso, ip);
1000}
1001
1002int load_kernel(void)
1003{ 1341{
1004 int err; 1342 if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter,
1005 1343 modules) <= 0)
1006 kernel_dso = dso__new("[kernel]", 0);
1007 if (!kernel_dso)
1008 return -1; 1344 return -1;
1009 1345
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1011 if (err <= 0) {
1012 dso__delete(kernel_dso);
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016
1017 vdso = dso__new("[vdso]", 0); 1346 vdso = dso__new("[vdso]", 0);
1018 if (!vdso) 1347 if (!vdso)
1019 return -1; 1348 return -1;
1020 1349
1021 vdso->find_symbol = vdso__find_symbol;
1022
1023 dsos__add(vdso); 1350 dsos__add(vdso);
1024 1351
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1352 return 0;
1026 if (!hypervisor_dso)
1027 return -1;
1028 dsos__add(hypervisor_dso);
1029
1030 return err;
1031} 1353}
1032 1354
1033
1034void symbol__init(void) 1355void symbol__init(void)
1035{ 1356{
1036 elf_version(EV_CURRENT); 1357 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6e8490716408..77b7b3e42417 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,11 +1,11 @@
1#ifndef _PERF_SYMBOL_ 1#ifndef __PERF_SYMBOL
2#define _PERF_SYMBOL_ 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h>
5#include "types.h" 6#include "types.h"
6#include <linux/list.h> 7#include <linux/list.h>
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h" 9#include "event.h"
10 10
11#ifdef HAVE_CPLUS_DEMANGLE 11#ifdef HAVE_CPLUS_DEMANGLE
@@ -36,11 +36,6 @@ struct symbol {
36 struct rb_node rb_node; 36 struct rb_node rb_node;
37 u64 start; 37 u64 start;
38 u64 end; 38 u64 end;
39 u64 obj_start;
40 u64 hist_sum;
41 u64 *hist;
42 struct module *module;
43 void *priv;
44 char name[0]; 39 char name[0];
45}; 40};
46 41
@@ -52,13 +47,11 @@ struct dso {
52 unsigned char adjust_symbols; 47 unsigned char adjust_symbols;
53 unsigned char slen_calculated; 48 unsigned char slen_calculated;
54 unsigned char origin; 49 unsigned char origin;
50 const char *short_name;
51 char *long_name;
55 char name[0]; 52 char name[0];
56}; 53};
57 54
58extern const char *sym_hist_filter;
59
60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
61
62struct dso *dso__new(const char *name, unsigned int sym_priv_size); 55struct dso *dso__new(const char *name, unsigned int sym_priv_size);
63void dso__delete(struct dso *self); 56void dso__delete(struct dso *self);
64 57
@@ -69,24 +62,23 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
69 62
70struct symbol *dso__find_symbol(struct dso *self, u64 ip); 63struct symbol *dso__find_symbol(struct dso *self, u64 ip);
71 64
72int dso__load_kernel(struct dso *self, const char *vmlinux, 65int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
73 symbol_filter_t filter, int verbose, int modules); 66 symbol_filter_t filter, int modules);
74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); 67struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
75int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 68 bool *is_new);
76struct dso *dsos__findnew(const char *name); 69int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
77void dsos__fprintf(FILE *fp); 70void dsos__fprintf(FILE *fp);
78 71
79size_t dso__fprintf(struct dso *self, FILE *fp); 72size_t dso__fprintf(struct dso *self, FILE *fp);
80char dso__symtab_origin(const struct dso *self); 73char dso__symtab_origin(const struct dso *self);
81 74
82int load_kernel(void); 75int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter);
83 76
84void symbol__init(void); 77void symbol__init(void);
85 78
86extern struct list_head dsos; 79extern struct list_head dsos;
87extern struct dso *kernel_dso; 80extern struct map *kernel_map;
88extern struct dso *vdso; 81extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name; 82extern const char *vmlinux_name;
91extern int modules; 83extern int modules;
92#endif /* _PERF_SYMBOL_ */ 84#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..0f6d78c9863a 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,6 +6,9 @@
6#include "util.h" 6#include "util.h"
7#include "debug.h" 7#include "debug.h"
8 8
9static struct rb_root threads;
10static struct thread *last_match;
11
9static struct thread *thread__new(pid_t pid) 12static struct thread *thread__new(pid_t pid)
10{ 13{
11 struct thread *self = calloc(1, sizeof(*self)); 14 struct thread *self = calloc(1, sizeof(*self));
@@ -15,7 +18,8 @@ static struct thread *thread__new(pid_t pid)
15 self->comm = malloc(32); 18 self->comm = malloc(32);
16 if (self->comm) 19 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 20 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps); 21 self->maps = RB_ROOT;
22 INIT_LIST_HEAD(&self->removed_maps);
19 } 23 }
20 24
21 return self; 25 return self;
@@ -29,21 +33,40 @@ int thread__set_comm(struct thread *self, const char *comm)
29 return self->comm ? 0 : -ENOMEM; 33 return self->comm ? 0 : -ENOMEM;
30} 34}
31 35
36int thread__comm_len(struct thread *self)
37{
38 if (!self->comm_len) {
39 if (!self->comm)
40 return 0;
41 self->comm_len = strlen(self->comm);
42 }
43
44 return self->comm_len;
45}
46
32static size_t thread__fprintf(struct thread *self, FILE *fp) 47static size_t thread__fprintf(struct thread *self, FILE *fp)
33{ 48{
49 struct rb_node *nd;
34 struct map *pos; 50 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 51 size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
52 self->pid, self->comm);
36 53
37 list_for_each_entry(pos, &self->maps, node) 54 for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
55 pos = rb_entry(nd, struct map, rb_node);
56 ret += map__fprintf(pos, fp);
57 }
58
59 ret = fprintf(fp, "Removed maps:\n");
60
61 list_for_each_entry(pos, &self->removed_maps, node)
38 ret += map__fprintf(pos, fp); 62 ret += map__fprintf(pos, fp);
39 63
40 return ret; 64 return ret;
41} 65}
42 66
43struct thread * 67struct thread *threads__findnew(pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 68{
46 struct rb_node **p = &threads->rb_node; 69 struct rb_node **p = &threads.rb_node;
47 struct rb_node *parent = NULL; 70 struct rb_node *parent = NULL;
48 struct thread *th; 71 struct thread *th;
49 72
@@ -52,15 +75,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
52 * so most of the time we dont have to look up 75 * so most of the time we dont have to look up
53 * the full rbtree: 76 * the full rbtree:
54 */ 77 */
55 if (*last_match && (*last_match)->pid == pid) 78 if (last_match && last_match->pid == pid)
56 return *last_match; 79 return last_match;
57 80
58 while (*p != NULL) { 81 while (*p != NULL) {
59 parent = *p; 82 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 83 th = rb_entry(parent, struct thread, rb_node);
61 84
62 if (th->pid == pid) { 85 if (th->pid == pid) {
63 *last_match = th; 86 last_match = th;
64 return th; 87 return th;
65 } 88 }
66 89
@@ -73,17 +96,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 96 th = thread__new(pid);
74 if (th != NULL) { 97 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 98 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 99 rb_insert_color(&th->rb_node, &threads);
77 *last_match = th; 100 last_match = th;
78 } 101 }
79 102
80 return th; 103 return th;
81} 104}
82 105
83struct thread * 106struct thread *register_idle_thread(void)
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{ 107{
86 struct thread *thread = threads__findnew(0, threads, last_match); 108 struct thread *thread = threads__findnew(0);
87 109
88 if (!thread || thread__set_comm(thread, "swapper")) { 110 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n"); 111 fprintf(stderr, "problem inserting idle task.\n");
@@ -93,42 +115,82 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
93 return thread; 115 return thread;
94} 116}
95 117
96void thread__insert_map(struct thread *self, struct map *map) 118static void thread__remove_overlappings(struct thread *self, struct map *map)
97{ 119{
98 struct map *pos, *tmp; 120 struct rb_node *next = rb_first(&self->maps);
99 121
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 122 while (next) {
101 if (map__overlap(pos, map)) { 123 struct map *pos = rb_entry(next, struct map, rb_node);
102 if (verbose >= 2) { 124 next = rb_next(&pos->rb_node);
103 printf("overlapping maps:\n"); 125
104 map__fprintf(map, stdout); 126 if (!map__overlap(pos, map))
105 map__fprintf(pos, stdout); 127 continue;
106 } 128
107 129 if (verbose >= 2) {
108 if (map->start <= pos->start && map->end > pos->start) 130 fputs("overlapping maps:\n", stderr);
109 pos->start = map->end; 131 map__fprintf(map, stderr);
110 132 map__fprintf(pos, stderr);
111 if (map->end >= pos->end && map->start < pos->end)
112 pos->end = map->start;
113
114 if (verbose >= 2) {
115 printf("after collision:\n");
116 map__fprintf(pos, stdout);
117 }
118
119 if (pos->start >= pos->end) {
120 list_del_init(&pos->node);
121 free(pos);
122 }
123 } 133 }
134
135 rb_erase(&pos->rb_node, &self->maps);
136 /*
137 * We may have references to this map, for instance in some
138 * hist_entry instances, so just move them to a separate
139 * list.
140 */
141 list_add_tail(&pos->node, &self->removed_maps);
142 }
143}
144
145void maps__insert(struct rb_root *maps, struct map *map)
146{
147 struct rb_node **p = &maps->rb_node;
148 struct rb_node *parent = NULL;
149 const u64 ip = map->start;
150 struct map *m;
151
152 while (*p != NULL) {
153 parent = *p;
154 m = rb_entry(parent, struct map, rb_node);
155 if (ip < m->start)
156 p = &(*p)->rb_left;
157 else
158 p = &(*p)->rb_right;
124 } 159 }
125 160
126 list_add_tail(&map->node, &self->maps); 161 rb_link_node(&map->rb_node, parent, p);
162 rb_insert_color(&map->rb_node, maps);
163}
164
165struct map *maps__find(struct rb_root *maps, u64 ip)
166{
167 struct rb_node **p = &maps->rb_node;
168 struct rb_node *parent = NULL;
169 struct map *m;
170
171 while (*p != NULL) {
172 parent = *p;
173 m = rb_entry(parent, struct map, rb_node);
174 if (ip < m->start)
175 p = &(*p)->rb_left;
176 else if (ip > m->end)
177 p = &(*p)->rb_right;
178 else
179 return m;
180 }
181
182 return NULL;
183}
184
185void thread__insert_map(struct thread *self, struct map *map)
186{
187 thread__remove_overlappings(self, map);
188 maps__insert(&self->maps, map);
127} 189}
128 190
129int thread__fork(struct thread *self, struct thread *parent) 191int thread__fork(struct thread *self, struct thread *parent)
130{ 192{
131 struct map *map; 193 struct rb_node *nd;
132 194
133 if (self->comm) 195 if (self->comm)
134 free(self->comm); 196 free(self->comm);
@@ -136,7 +198,8 @@ int thread__fork(struct thread *self, struct thread *parent)
136 if (!self->comm) 198 if (!self->comm)
137 return -ENOMEM; 199 return -ENOMEM;
138 200
139 list_for_each_entry(map, &parent->maps, node) { 201 for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
202 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 203 struct map *new = map__clone(map);
141 if (!new) 204 if (!new)
142 return -ENOMEM; 205 return -ENOMEM;
@@ -146,26 +209,12 @@ int thread__fork(struct thread *self, struct thread *parent)
146 return 0; 209 return 0;
147} 210}
148 211
149struct map *thread__find_map(struct thread *self, u64 ip) 212size_t threads__fprintf(FILE *fp)
150{
151 struct map *pos;
152
153 if (self == NULL)
154 return NULL;
155
156 list_for_each_entry(pos, &self->maps, node)
157 if (ip >= pos->start && ip <= pos->end)
158 return pos;
159
160 return NULL;
161}
162
163size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164{ 213{
165 size_t ret = 0; 214 size_t ret = 0;
166 struct rb_node *nd; 215 struct rb_node *nd;
167 216
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 217 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 218 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 219
171 ret += thread__fprintf(pos, fp); 220 ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..53addd77ce8f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,37 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
6struct thread { 8struct thread {
7 struct rb_node rb_node; 9 struct rb_node rb_node;
8 struct list_head maps; 10 struct rb_root maps;
11 struct list_head removed_maps;
9 pid_t pid; 12 pid_t pid;
10 char shortname[3]; 13 char shortname[3];
11 char *comm; 14 char *comm;
15 int comm_len;
12}; 16};
13 17
14int thread__set_comm(struct thread *self, const char *comm); 18int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 19int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 20struct thread *threads__findnew(pid_t pid);
17struct thread * 21struct thread *register_idle_thread(void);
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 22void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 23int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 24size_t threads__fprintf(FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 25
26void maps__insert(struct rb_root *maps, struct map *map);
27struct map *maps__find(struct rb_root *maps, u64 ip);
28
29struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
30struct map *kernel_maps__find_by_dso_name(const char *name);
31
32static inline struct map *thread__find_map(struct thread *self, u64 ip)
33{
34 return self ? maps__find(&self->maps, ip) : NULL;
35}
36
37#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..831052d4b4fb 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -496,14 +496,12 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
496 496
497 return path.next; 497 return path.next;
498} 498}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events) 499void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 500{
501 char buf[BUFSIZ]; 501 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 502 struct tracepoint_path *tps;
503 503
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 504 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 505
508 buf[0] = 23; 506 buf[0] = 23;
509 buf[1] = 8; 507 buf[1] = 8;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..eae560503086 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,6 +40,8 @@ int header_page_size_size;
40int header_page_data_offset; 40int header_page_data_offset;
41int header_page_data_size; 41int header_page_data_size;
42 42
43int latency_format;
44
43static char *input_buf; 45static char *input_buf;
44static unsigned long long input_buf_ptr; 46static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz; 47static unsigned long long input_buf_siz;
@@ -284,18 +286,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
284 char *line; 286 char *line;
285 char *next = NULL; 287 char *next = NULL;
286 char *addr_str; 288 char *addr_str;
287 int ret;
288 int i; 289 int i;
289 290
290 line = strtok_r(file, "\n", &next); 291 line = strtok_r(file, "\n", &next);
291 while (line) { 292 while (line) {
293 addr_str = strsep(&line, ":");
294 if (!line) {
295 warning("error parsing print strings");
296 break;
297 }
292 item = malloc_or_die(sizeof(*item)); 298 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16); 299 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str); 300 /* fmt still has a space, skip it */
298 301 item->printk = strdup(line+1);
299 item->next = list; 302 item->next = list;
300 list = item; 303 list = item;
301 line = strtok_r(NULL, "\n", &next); 304 line = strtok_r(NULL, "\n", &next);
@@ -522,7 +525,10 @@ static enum event_type __read_token(char **tok)
522 last_ch = ch; 525 last_ch = ch;
523 ch = __read_char(); 526 ch = __read_char();
524 buf[i++] = ch; 527 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\'); 528 /* the '\' '\' will cancel itself */
529 if (ch == '\\' && last_ch == '\\')
530 last_ch = 0;
531 } while (ch != quote_ch || last_ch == '\\');
526 /* remove the last quote */ 532 /* remove the last quote */
527 i--; 533 i--;
528 goto out; 534 goto out;
@@ -610,7 +616,7 @@ static enum event_type read_token_item(char **tok)
610static int test_type(enum event_type type, enum event_type expect) 616static int test_type(enum event_type type, enum event_type expect)
611{ 617{
612 if (type != expect) { 618 if (type != expect) {
613 die("Error: expected type %d but read %d", 619 warning("Error: expected type %d but read %d",
614 expect, type); 620 expect, type);
615 return -1; 621 return -1;
616 } 622 }
@@ -621,13 +627,13 @@ static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, const char *expect_tok) 627 enum event_type expect, const char *expect_tok)
622{ 628{
623 if (type != expect) { 629 if (type != expect) {
624 die("Error: expected type %d but read %d", 630 warning("Error: expected type %d but read %d",
625 expect, type); 631 expect, type);
626 return -1; 632 return -1;
627 } 633 }
628 634
629 if (strcmp(token, expect_tok) != 0) { 635 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'", 636 warning("Error: expected '%s' but read '%s'",
631 expect_tok, token); 637 expect_tok, token);
632 return -1; 638 return -1;
633 } 639 }
@@ -665,7 +671,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
665 671
666 free_token(token); 672 free_token(token);
667 673
668 return 0; 674 return ret;
669} 675}
670 676
671static int read_expected(enum event_type expect, const char *str) 677static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +688,10 @@ static char *event_read_name(void)
682{ 688{
683 char *token; 689 char *token;
684 690
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0) 691 if (read_expected(EVENT_ITEM, "name") < 0)
686 return NULL; 692 return NULL;
687 693
688 if (read_expected(EVENT_OP, (char *)":") < 0) 694 if (read_expected(EVENT_OP, ":") < 0)
689 return NULL; 695 return NULL;
690 696
691 if (read_expect_type(EVENT_ITEM, &token) < 0) 697 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +709,10 @@ static int event_read_id(void)
703 char *token; 709 char *token;
704 int id; 710 int id;
705 711
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) 712 if (read_expected_item(EVENT_ITEM, "ID") < 0)
707 return -1; 713 return -1;
708 714
709 if (read_expected(EVENT_OP, (char *)":") < 0) 715 if (read_expected(EVENT_OP, ":") < 0)
710 return -1; 716 return -1;
711 717
712 if (read_expect_type(EVENT_ITEM, &token) < 0) 718 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +727,24 @@ static int event_read_id(void)
721 return -1; 727 return -1;
722} 728}
723 729
730static int field_is_string(struct format_field *field)
731{
732 if ((field->flags & FIELD_IS_ARRAY) &&
733 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
734 !strstr(field->type, "s8")))
735 return 1;
736
737 return 0;
738}
739
740static int field_is_dynamic(struct format_field *field)
741{
742 if (!strcmp(field->type, "__data_loc"))
743 return 1;
744
745 return 0;
746}
747
724static int event_read_fields(struct event *event, struct format_field **fields) 748static int event_read_fields(struct event *event, struct format_field **fields)
725{ 749{
726 struct format_field *field = NULL; 750 struct format_field *field = NULL;
@@ -738,7 +762,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
738 762
739 count++; 763 count++;
740 764
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) 765 if (test_type_token(type, token, EVENT_ITEM, "field"))
742 goto fail; 766 goto fail;
743 free_token(token); 767 free_token(token);
744 768
@@ -753,7 +777,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
753 type = read_token(&token); 777 type = read_token(&token);
754 } 778 }
755 779
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) 780 if (test_type_token(type, token, EVENT_OP, ":") < 0)
757 return -1; 781 return -1;
758 782
759 if (read_expect_type(EVENT_ITEM, &token) < 0) 783 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +889,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
865 free(brackets); 889 free(brackets);
866 } 890 }
867 891
868 if (test_type_token(type, token, EVENT_OP, (char *)";")) 892 if (field_is_string(field)) {
893 field->flags |= FIELD_IS_STRING;
894 if (field_is_dynamic(field))
895 field->flags |= FIELD_IS_DYNAMIC;
896 }
897
898 if (test_type_token(type, token, EVENT_OP, ";"))
869 goto fail; 899 goto fail;
870 free_token(token); 900 free_token(token);
871 901
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 902 if (read_expected(EVENT_ITEM, "offset") < 0)
873 goto fail_expect; 903 goto fail_expect;
874 904
875 if (read_expected(EVENT_OP, (char *)":") < 0) 905 if (read_expected(EVENT_OP, ":") < 0)
876 goto fail_expect; 906 goto fail_expect;
877 907
878 if (read_expect_type(EVENT_ITEM, &token)) 908 if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +910,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
880 field->offset = strtoul(token, NULL, 0); 910 field->offset = strtoul(token, NULL, 0);
881 free_token(token); 911 free_token(token);
882 912
883 if (read_expected(EVENT_OP, (char *)";") < 0) 913 if (read_expected(EVENT_OP, ";") < 0)
884 goto fail_expect; 914 goto fail_expect;
885 915
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 916 if (read_expected(EVENT_ITEM, "size") < 0)
887 goto fail_expect; 917 goto fail_expect;
888 918
889 if (read_expected(EVENT_OP, (char *)":") < 0) 919 if (read_expected(EVENT_OP, ":") < 0)
890 goto fail_expect; 920 goto fail_expect;
891 921
892 if (read_expect_type(EVENT_ITEM, &token)) 922 if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +924,33 @@ static int event_read_fields(struct event *event, struct format_field **fields)
894 field->size = strtoul(token, NULL, 0); 924 field->size = strtoul(token, NULL, 0);
895 free_token(token); 925 free_token(token);
896 926
897 if (read_expected(EVENT_OP, (char *)";") < 0) 927 if (read_expected(EVENT_OP, ";") < 0)
898 goto fail_expect; 928 goto fail_expect;
899 929
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 930 type = read_token(&token);
901 goto fail; 931 if (type != EVENT_NEWLINE) {
932 /* newer versions of the kernel have a "signed" type */
933 if (test_type_token(type, token, EVENT_ITEM, "signed"))
934 goto fail;
935
936 free_token(token);
937
938 if (read_expected(EVENT_OP, ":") < 0)
939 goto fail_expect;
940
941 if (read_expect_type(EVENT_ITEM, &token))
942 goto fail;
943
944 /* add signed type */
945
946 free_token(token);
947 if (read_expected(EVENT_OP, ";") < 0)
948 goto fail_expect;
949
950 if (read_expect_type(EVENT_NEWLINE, &token))
951 goto fail;
952 }
953
902 free_token(token); 954 free_token(token);
903 955
904 *fields = field; 956 *fields = field;
@@ -921,10 +973,10 @@ static int event_read_format(struct event *event)
921 char *token; 973 char *token;
922 int ret; 974 int ret;
923 975
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) 976 if (read_expected_item(EVENT_ITEM, "format") < 0)
925 return -1; 977 return -1;
926 978
927 if (read_expected(EVENT_OP, (char *)":") < 0) 979 if (read_expected(EVENT_OP, ":") < 0)
928 return -1; 980 return -1;
929 981
930 if (read_expect_type(EVENT_NEWLINE, &token)) 982 if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1036,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
984 1036
985 *tok = NULL; 1037 *tok = NULL;
986 type = process_arg(event, left, &token); 1038 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":")) 1039 if (test_type_token(type, token, EVENT_OP, ":"))
988 goto out_free; 1040 goto out_free;
989 1041
990 arg->op.op = token; 1042 arg->op.op = token;
@@ -1004,6 +1056,35 @@ out_free:
1004 return EVENT_ERROR; 1056 return EVENT_ERROR;
1005} 1057}
1006 1058
1059static enum event_type
1060process_array(struct event *event, struct print_arg *top, char **tok)
1061{
1062 struct print_arg *arg;
1063 enum event_type type;
1064 char *token = NULL;
1065
1066 arg = malloc_or_die(sizeof(*arg));
1067 memset(arg, 0, sizeof(*arg));
1068
1069 *tok = NULL;
1070 type = process_arg(event, arg, &token);
1071 if (test_type_token(type, token, EVENT_OP, "]"))
1072 goto out_free;
1073
1074 top->op.right = arg;
1075
1076 free_token(token);
1077 type = read_token_item(&token);
1078 *tok = token;
1079
1080 return type;
1081
1082out_free:
1083 free_token(*tok);
1084 free_arg(arg);
1085 return EVENT_ERROR;
1086}
1087
1007static int get_op_prio(char *op) 1088static int get_op_prio(char *op)
1008{ 1089{
1009 if (!op[1]) { 1090 if (!op[1]) {
@@ -1128,6 +1209,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1128 strcmp(token, "*") == 0 || 1209 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 || 1210 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 || 1211 strcmp(token, "/") == 0 ||
1212 strcmp(token, "<") == 0 ||
1213 strcmp(token, ">") == 0 ||
1131 strcmp(token, "==") == 0 || 1214 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) { 1215 strcmp(token, "!=") == 0) {
1133 1216
@@ -1144,17 +1227,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1144 1227
1145 right = malloc_or_die(sizeof(*right)); 1228 right = malloc_or_die(sizeof(*right));
1146 1229
1147 type = process_arg(event, right, tok); 1230 type = read_token_item(&token);
1231 *tok = token;
1232
1233 /* could just be a type pointer */
1234 if ((strcmp(arg->op.op, "*") == 0) &&
1235 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1236 if (left->type != PRINT_ATOM)
1237 die("bad pointer type");
1238 left->atom.atom = realloc(left->atom.atom,
1239 sizeof(left->atom.atom) + 3);
1240 strcat(left->atom.atom, " *");
1241 *arg = *left;
1242 free(arg);
1243
1244 return type;
1245 }
1246
1247 type = process_arg_token(event, right, tok, type);
1148 1248
1149 arg->op.right = right; 1249 arg->op.right = right;
1150 1250
1251 } else if (strcmp(token, "[") == 0) {
1252
1253 left = malloc_or_die(sizeof(*left));
1254 *left = *arg;
1255
1256 arg->type = PRINT_OP;
1257 arg->op.op = token;
1258 arg->op.left = left;
1259
1260 arg->op.prio = 0;
1261 type = process_array(event, arg, tok);
1262
1151 } else { 1263 } else {
1152 die("unknown op '%s'", token); 1264 warning("unknown op '%s'", token);
1265 event->flags |= EVENT_FL_FAILED;
1153 /* the arg is now the left side */ 1266 /* the arg is now the left side */
1154 return EVENT_NONE; 1267 return EVENT_NONE;
1155 } 1268 }
1156 1269
1157
1158 if (type == EVENT_OP) { 1270 if (type == EVENT_OP) {
1159 int prio; 1271 int prio;
1160 1272
@@ -1178,7 +1290,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1178 char *field; 1290 char *field;
1179 char *token; 1291 char *token;
1180 1292
1181 if (read_expected(EVENT_OP, (char *)"->") < 0) 1293 if (read_expected(EVENT_OP, "->") < 0)
1182 return EVENT_ERROR; 1294 return EVENT_ERROR;
1183 1295
1184 if (read_expect_type(EVENT_ITEM, &token) < 0) 1296 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1338,14 +1450,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1338 do { 1450 do {
1339 free_token(token); 1451 free_token(token);
1340 type = read_token_item(&token); 1452 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{")) 1453 if (test_type_token(type, token, EVENT_OP, "{"))
1342 break; 1454 break;
1343 1455
1344 arg = malloc_or_die(sizeof(*arg)); 1456 arg = malloc_or_die(sizeof(*arg));
1345 1457
1346 free_token(token); 1458 free_token(token);
1347 type = process_arg(event, arg, &token); 1459 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1460 if (test_type_token(type, token, EVENT_DELIM, ","))
1349 goto out_free; 1461 goto out_free;
1350 1462
1351 field = malloc_or_die(sizeof(*field)); 1463 field = malloc_or_die(sizeof(*field));
@@ -1356,7 +1468,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1356 1468
1357 free_token(token); 1469 free_token(token);
1358 type = process_arg(event, arg, &token); 1470 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}")) 1471 if (test_type_token(type, token, EVENT_OP, "}"))
1360 goto out_free; 1472 goto out_free;
1361 1473
1362 value = arg_eval(arg); 1474 value = arg_eval(arg);
@@ -1391,13 +1503,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1391 memset(arg, 0, sizeof(*arg)); 1503 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS; 1504 arg->type = PRINT_FLAGS;
1393 1505
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1506 if (read_expected_item(EVENT_DELIM, "(") < 0)
1395 return EVENT_ERROR; 1507 return EVENT_ERROR;
1396 1508
1397 field = malloc_or_die(sizeof(*field)); 1509 field = malloc_or_die(sizeof(*field));
1398 1510
1399 type = process_arg(event, field, &token); 1511 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1512 if (test_type_token(type, token, EVENT_DELIM, ","))
1401 goto out_free; 1513 goto out_free;
1402 1514
1403 arg->flags.field = field; 1515 arg->flags.field = field;
@@ -1408,11 +1520,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1408 type = read_token_item(&token); 1520 type = read_token_item(&token);
1409 } 1521 }
1410 1522
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1523 if (test_type_token(type, token, EVENT_DELIM, ","))
1412 goto out_free; 1524 goto out_free;
1413 1525
1414 type = process_fields(event, &arg->flags.flags, &token); 1526 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1527 if (test_type_token(type, token, EVENT_DELIM, ")"))
1416 goto out_free; 1528 goto out_free;
1417 1529
1418 free_token(token); 1530 free_token(token);
@@ -1434,19 +1546,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
1434 memset(arg, 0, sizeof(*arg)); 1546 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL; 1547 arg->type = PRINT_SYMBOL;
1436 1548
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1549 if (read_expected_item(EVENT_DELIM, "(") < 0)
1438 return EVENT_ERROR; 1550 return EVENT_ERROR;
1439 1551
1440 field = malloc_or_die(sizeof(*field)); 1552 field = malloc_or_die(sizeof(*field));
1441 1553
1442 type = process_arg(event, field, &token); 1554 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1555 if (test_type_token(type, token, EVENT_DELIM, ","))
1444 goto out_free; 1556 goto out_free;
1445 1557
1446 arg->symbol.field = field; 1558 arg->symbol.field = field;
1447 1559
1448 type = process_fields(event, &arg->symbol.symbols, &token); 1560 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1561 if (test_type_token(type, token, EVENT_DELIM, ")"))
1450 goto out_free; 1562 goto out_free;
1451 1563
1452 free_token(token); 1564 free_token(token);
@@ -1463,7 +1575,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{ 1575{
1464 struct print_arg *item_arg; 1576 struct print_arg *item_arg;
1465 enum event_type type; 1577 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token; 1578 char *token;
1468 1579
1469 type = process_arg(event, arg, &token); 1580 type = process_arg(event, arg, &token);
@@ -1471,28 +1582,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1471 if (type == EVENT_ERROR) 1582 if (type == EVENT_ERROR)
1472 return EVENT_ERROR; 1583 return EVENT_ERROR;
1473 1584
1474 if (type == EVENT_OP) { 1585 if (type == EVENT_OP)
1475 /* handle the ptr casts */ 1586 type = process_op(event, arg, &token);
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489 1587
1490 if (type == EVENT_ERROR) 1588 if (type == EVENT_ERROR)
1491 return EVENT_ERROR; 1589 return EVENT_ERROR;
1492 }
1493 }
1494 1590
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { 1591 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1496 free_token(token); 1592 free_token(token);
1497 return EVENT_ERROR; 1593 return EVENT_ERROR;
1498 } 1594 }
@@ -1516,13 +1612,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1516 item_arg = malloc_or_die(sizeof(*item_arg)); 1612 item_arg = malloc_or_die(sizeof(*item_arg));
1517 1613
1518 arg->type = PRINT_TYPE; 1614 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom; 1615 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg; 1616 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type); 1617 type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1629,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1540 enum event_type type; 1629 enum event_type type;
1541 char *token; 1630 char *token;
1542 1631
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0) 1632 if (read_expected(EVENT_DELIM, "(") < 0)
1544 return EVENT_ERROR; 1633 return EVENT_ERROR;
1545 1634
1546 if (read_expect_type(EVENT_ITEM, &token) < 0) 1635 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1639,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1550 arg->string.string = token; 1639 arg->string.string = token;
1551 arg->string.offset = -1; 1640 arg->string.offset = -1;
1552 1641
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0) 1642 if (read_expected(EVENT_DELIM, ")") < 0)
1554 return EVENT_ERROR; 1643 return EVENT_ERROR;
1555 1644
1556 type = read_token(&token); 1645 type = read_token(&token);
@@ -1637,12 +1726,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
1637 1726
1638static int event_read_print_args(struct event *event, struct print_arg **list) 1727static int event_read_print_args(struct event *event, struct print_arg **list)
1639{ 1728{
1640 enum event_type type; 1729 enum event_type type = EVENT_ERROR;
1641 struct print_arg *arg; 1730 struct print_arg *arg;
1642 char *token; 1731 char *token;
1643 int args = 0; 1732 int args = 0;
1644 1733
1645 do { 1734 do {
1735 if (type == EVENT_NEWLINE) {
1736 free_token(token);
1737 type = read_token_item(&token);
1738 continue;
1739 }
1740
1646 arg = malloc_or_die(sizeof(*arg)); 1741 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg)); 1742 memset(arg, 0, sizeof(*arg));
1648 1743
@@ -1683,18 +1778,19 @@ static int event_read_print(struct event *event)
1683 char *token; 1778 char *token;
1684 int ret; 1779 int ret;
1685 1780
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) 1781 if (read_expected_item(EVENT_ITEM, "print") < 0)
1687 return -1; 1782 return -1;
1688 1783
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) 1784 if (read_expected(EVENT_ITEM, "fmt") < 0)
1690 return -1; 1785 return -1;
1691 1786
1692 if (read_expected(EVENT_OP, (char *)":") < 0) 1787 if (read_expected(EVENT_OP, ":") < 0)
1693 return -1; 1788 return -1;
1694 1789
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0) 1790 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail; 1791 goto fail;
1697 1792
1793 concat:
1698 event->print_fmt.format = token; 1794 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL; 1795 event->print_fmt.args = NULL;
1700 1796
@@ -1704,7 +1800,22 @@ static int event_read_print(struct event *event)
1704 if (type == EVENT_NONE) 1800 if (type == EVENT_NONE)
1705 return 0; 1801 return 0;
1706 1802
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1803 /* Handle concatination of print lines */
1804 if (type == EVENT_DQUOTE) {
1805 char *cat;
1806
1807 cat = malloc_or_die(strlen(event->print_fmt.format) +
1808 strlen(token) + 1);
1809 strcpy(cat, event->print_fmt.format);
1810 strcat(cat, token);
1811 free_token(token);
1812 free_token(event->print_fmt.format);
1813 event->print_fmt.format = NULL;
1814 token = cat;
1815 goto concat;
1816 }
1817
1818 if (test_type_token(type, token, EVENT_DELIM, ","))
1708 goto fail; 1819 goto fail;
1709 1820
1710 free_token(token); 1821 free_token(token);
@@ -1713,7 +1824,7 @@ static int event_read_print(struct event *event)
1713 if (ret < 0) 1824 if (ret < 0)
1714 return -1; 1825 return -1;
1715 1826
1716 return 0; 1827 return ret;
1717 1828
1718 fail: 1829 fail:
1719 free_token(token); 1830 free_token(token);
@@ -1822,37 +1933,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1822 return 0; 1933 return 0;
1823} 1934}
1824 1935
1825int trace_parse_common_type(void *data) 1936static int __parse_common(void *data, int *size, int *offset,
1937 const char *name)
1826{ 1938{
1827 static int type_offset;
1828 static int type_size;
1829 int ret; 1939 int ret;
1830 1940
1831 if (!type_size) { 1941 if (!*size) {
1832 ret = get_common_info("common_type", 1942 ret = get_common_info(name, offset, size);
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0) 1943 if (ret < 0)
1836 return ret; 1944 return ret;
1837 } 1945 }
1838 return read_size(data + type_offset, type_size); 1946 return read_size(data + *offset, *size);
1947}
1948
1949int trace_parse_common_type(void *data)
1950{
1951 static int type_offset;
1952 static int type_size;
1953
1954 return __parse_common(data, &type_size, &type_offset,
1955 "common_type");
1839} 1956}
1840 1957
1841static int parse_common_pid(void *data) 1958static int parse_common_pid(void *data)
1842{ 1959{
1843 static int pid_offset; 1960 static int pid_offset;
1844 static int pid_size; 1961 static int pid_size;
1962
1963 return __parse_common(data, &pid_size, &pid_offset,
1964 "common_pid");
1965}
1966
1967static int parse_common_pc(void *data)
1968{
1969 static int pc_offset;
1970 static int pc_size;
1971
1972 return __parse_common(data, &pc_size, &pc_offset,
1973 "common_preempt_count");
1974}
1975
1976static int parse_common_flags(void *data)
1977{
1978 static int flags_offset;
1979 static int flags_size;
1980
1981 return __parse_common(data, &flags_size, &flags_offset,
1982 "common_flags");
1983}
1984
1985static int parse_common_lock_depth(void *data)
1986{
1987 static int ld_offset;
1988 static int ld_size;
1845 int ret; 1989 int ret;
1846 1990
1847 if (!pid_size) { 1991 ret = __parse_common(data, &ld_size, &ld_offset,
1848 ret = get_common_info("common_pid", 1992 "common_lock_depth");
1849 &pid_offset, 1993 if (ret < 0)
1850 &pid_size); 1994 return -1;
1851 if (ret < 0)
1852 return ret;
1853 }
1854 1995
1855 return read_size(data + pid_offset, pid_size); 1996 return ret;
1856} 1997}
1857 1998
1858struct event *trace_find_event(int id) 1999struct event *trace_find_event(int id)
@@ -1871,6 +2012,7 @@ static unsigned long long eval_num_arg(void *data, int size,
1871{ 2012{
1872 unsigned long long val = 0; 2013 unsigned long long val = 0;
1873 unsigned long long left, right; 2014 unsigned long long left, right;
2015 struct print_arg *larg;
1874 2016
1875 switch (arg->type) { 2017 switch (arg->type) {
1876 case PRINT_NULL: 2018 case PRINT_NULL:
@@ -1897,6 +2039,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1897 return 0; 2039 return 0;
1898 break; 2040 break;
1899 case PRINT_OP: 2041 case PRINT_OP:
2042 if (strcmp(arg->op.op, "[") == 0) {
2043 /*
2044 * Arrays are special, since we don't want
2045 * to read the arg as is.
2046 */
2047 if (arg->op.left->type != PRINT_FIELD)
2048 goto default_op; /* oops, all bets off */
2049 larg = arg->op.left;
2050 if (!larg->field.field) {
2051 larg->field.field =
2052 find_any_field(event, larg->field.name);
2053 if (!larg->field.field)
2054 die("field %s not found", larg->field.name);
2055 }
2056 right = eval_num_arg(data, size, event, arg->op.right);
2057 val = read_size(data + larg->field.field->offset +
2058 right * long_size, long_size);
2059 break;
2060 }
2061 default_op:
1900 left = eval_num_arg(data, size, event, arg->op.left); 2062 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right); 2063 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) { 2064 switch (arg->op.op[0]) {
@@ -1947,6 +2109,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1947 die("unknown op '%s'", arg->op.op); 2109 die("unknown op '%s'", arg->op.op);
1948 val = left == right; 2110 val = left == right;
1949 break; 2111 break;
2112 case '-':
2113 val = left - right;
2114 break;
2115 case '+':
2116 val = left + right;
2117 break;
1950 default: 2118 default:
1951 die("unknown op '%s'", arg->op.op); 2119 die("unknown op '%s'", arg->op.op);
1952 } 2120 }
@@ -2145,8 +2313,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2145 case 'u': 2313 case 'u':
2146 case 'x': 2314 case 'x':
2147 case 'i': 2315 case 'i':
2148 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2316 /* the pointers are always 4 bytes aligned */
2149 ~(long_size - 1)); 2317 bptr = (void *)(((unsigned long)bptr + 3) &
2318 ~3);
2150 switch (ls) { 2319 switch (ls) {
2151 case 0: 2320 case 0:
2152 case 1: 2321 case 1:
@@ -2270,7 +2439,27 @@ static void pretty_print(void *data, int size, struct event *event)
2270 2439
2271 for (; *ptr; ptr++) { 2440 for (; *ptr; ptr++) {
2272 ls = 0; 2441 ls = 0;
2273 if (*ptr == '%') { 2442 if (*ptr == '\\') {
2443 ptr++;
2444 switch (*ptr) {
2445 case 'n':
2446 printf("\n");
2447 break;
2448 case 't':
2449 printf("\t");
2450 break;
2451 case 'r':
2452 printf("\r");
2453 break;
2454 case '\\':
2455 printf("\\");
2456 break;
2457 default:
2458 printf("%c", *ptr);
2459 break;
2460 }
2461
2462 } else if (*ptr == '%') {
2274 saveptr = ptr; 2463 saveptr = ptr;
2275 show_func = 0; 2464 show_func = 0;
2276 cont_process: 2465 cont_process:
@@ -2377,6 +2566,41 @@ static inline int log10_cpu(int nb)
2377 return 1; 2566 return 1;
2378} 2567}
2379 2568
2569static void print_lat_fmt(void *data, int size __unused)
2570{
2571 unsigned int lat_flags;
2572 unsigned int pc;
2573 int lock_depth;
2574 int hardirq;
2575 int softirq;
2576
2577 lat_flags = parse_common_flags(data);
2578 pc = parse_common_pc(data);
2579 lock_depth = parse_common_lock_depth(data);
2580
2581 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2582 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2583
2584 printf("%c%c%c",
2585 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2586 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2587 'X' : '.',
2588 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2589 'N' : '.',
2590 (hardirq && softirq) ? 'H' :
2591 hardirq ? 'h' : softirq ? 's' : '.');
2592
2593 if (pc)
2594 printf("%x", pc);
2595 else
2596 printf(".");
2597
2598 if (lock_depth < 0)
2599 printf(".");
2600 else
2601 printf("%d", lock_depth);
2602}
2603
2380/* taken from Linux, written by Frederic Weisbecker */ 2604/* taken from Linux, written by Frederic Weisbecker */
2381static void print_graph_cpu(int cpu) 2605static void print_graph_cpu(int cpu)
2382{ 2606{
@@ -2620,6 +2844,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2620 2844
2621 printf(" | "); 2845 printf(" | ");
2622 2846
2847 if (latency_format) {
2848 print_lat_fmt(data, size);
2849 printf(" | ");
2850 }
2851
2623 field = find_field(event, "func"); 2852 field = find_field(event, "func");
2624 if (!field) 2853 if (!field)
2625 die("function entry does not have func field"); 2854 die("function entry does not have func field");
@@ -2663,6 +2892,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2663 2892
2664 printf(" | "); 2893 printf(" | ");
2665 2894
2895 if (latency_format) {
2896 print_lat_fmt(data, size);
2897 printf(" | ");
2898 }
2899
2666 field = find_field(event, "rettime"); 2900 field = find_field(event, "rettime");
2667 if (!field) 2901 if (!field)
2668 die("can't find rettime in return graph"); 2902 die("can't find rettime in return graph");
@@ -2724,7 +2958,7 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2724 2958
2725 event = trace_find_event(type); 2959 event = trace_find_event(type);
2726 if (!event) { 2960 if (!event) {
2727 printf("ug! no event found for type %d\n", type); 2961 warning("ug! no event found for type %d", type);
2728 return; 2962 return;
2729 } 2963 }
2730 2964
@@ -2734,9 +2968,20 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2734 return pretty_print_func_graph(data, size, event, cpu, 2968 return pretty_print_func_graph(data, size, event, cpu,
2735 pid, comm, secs, usecs); 2969 pid, comm, secs, usecs);
2736 2970
2737 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 2971 if (latency_format) {
2738 comm, pid, cpu, 2972 printf("%8.8s-%-5d %3d",
2739 secs, nsecs, event->name); 2973 comm, pid, cpu);
2974 print_lat_fmt(data, size);
2975 } else
2976 printf("%16s-%-5d [%03d]", comm, pid, cpu);
2977
2978 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
2979
2980 if (event->flags & EVENT_FL_FAILED) {
2981 printf("EVENT '%s' FAILED TO PARSE\n",
2982 event->name);
2983 return;
2984 }
2740 2985
2741 pretty_print(data, size, event); 2986 pretty_print(data, size, event);
2742 printf("\n"); 2987 printf("\n");
@@ -2807,46 +3052,71 @@ static void print_args(struct print_arg *args)
2807 } 3052 }
2808} 3053}
2809 3054
2810static void parse_header_field(char *type, 3055static void parse_header_field(const char *field,
2811 int *offset, int *size) 3056 int *offset, int *size)
2812{ 3057{
2813 char *token; 3058 char *token;
3059 int type;
2814 3060
2815 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3061 if (read_expected(EVENT_ITEM, "field") < 0)
2816 return; 3062 return;
2817 if (read_expected(EVENT_OP, (char *)":") < 0) 3063 if (read_expected(EVENT_OP, ":") < 0)
2818 return; 3064 return;
3065
2819 /* type */ 3066 /* type */
2820 if (read_expect_type(EVENT_ITEM, &token) < 0) 3067 if (read_expect_type(EVENT_ITEM, &token) < 0)
2821 return; 3068 goto fail;
2822 free_token(token); 3069 free_token(token);
2823 3070
2824 if (read_expected(EVENT_ITEM, type) < 0) 3071 if (read_expected(EVENT_ITEM, field) < 0)
2825 return; 3072 return;
2826 if (read_expected(EVENT_OP, (char *)";") < 0) 3073 if (read_expected(EVENT_OP, ";") < 0)
2827 return; 3074 return;
2828 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3075 if (read_expected(EVENT_ITEM, "offset") < 0)
2829 return; 3076 return;
2830 if (read_expected(EVENT_OP, (char *)":") < 0) 3077 if (read_expected(EVENT_OP, ":") < 0)
2831 return; 3078 return;
2832 if (read_expect_type(EVENT_ITEM, &token) < 0) 3079 if (read_expect_type(EVENT_ITEM, &token) < 0)
2833 return; 3080 goto fail;
2834 *offset = atoi(token); 3081 *offset = atoi(token);
2835 free_token(token); 3082 free_token(token);
2836 if (read_expected(EVENT_OP, (char *)";") < 0) 3083 if (read_expected(EVENT_OP, ";") < 0)
2837 return; 3084 return;
2838 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3085 if (read_expected(EVENT_ITEM, "size") < 0)
2839 return; 3086 return;
2840 if (read_expected(EVENT_OP, (char *)":") < 0) 3087 if (read_expected(EVENT_OP, ":") < 0)
2841 return; 3088 return;
2842 if (read_expect_type(EVENT_ITEM, &token) < 0) 3089 if (read_expect_type(EVENT_ITEM, &token) < 0)
2843 return; 3090 goto fail;
2844 *size = atoi(token); 3091 *size = atoi(token);
2845 free_token(token); 3092 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 3093 if (read_expected(EVENT_OP, ";") < 0)
2847 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 return; 3094 return;
3095 type = read_token(&token);
3096 if (type != EVENT_NEWLINE) {
3097 /* newer versions of the kernel have a "signed" type */
3098 if (type != EVENT_ITEM)
3099 goto fail;
3100
3101 if (strcmp(token, "signed") != 0)
3102 goto fail;
3103
3104 free_token(token);
3105
3106 if (read_expected(EVENT_OP, ":") < 0)
3107 return;
3108
3109 if (read_expect_type(EVENT_ITEM, &token))
3110 goto fail;
3111
3112 free_token(token);
3113 if (read_expected(EVENT_OP, ";") < 0)
3114 return;
3115
3116 if (read_expect_type(EVENT_NEWLINE, &token))
3117 goto fail;
3118 }
3119 fail:
2850 free_token(token); 3120 free_token(token);
2851} 3121}
2852 3122
@@ -2854,11 +3124,11 @@ int parse_header_page(char *buf, unsigned long size)
2854{ 3124{
2855 init_input_buf(buf, size); 3125 init_input_buf(buf, size);
2856 3126
2857 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3127 parse_header_field("timestamp", &header_page_ts_offset,
2858 &header_page_ts_size); 3128 &header_page_ts_size);
2859 parse_header_field((char *)"commit", &header_page_size_offset, 3129 parse_header_field("commit", &header_page_size_offset,
2860 &header_page_size_size); 3130 &header_page_size_size);
2861 parse_header_field((char *)"data", &header_page_data_offset, 3131 parse_header_field("data", &header_page_data_offset,
2862 &header_page_data_size); 3132 &header_page_data_size);
2863 3133
2864 return 0; 3134 return 0;
@@ -2909,6 +3179,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2909 if (ret < 0) 3179 if (ret < 0)
2910 die("failed to read ftrace event print fmt"); 3180 die("failed to read ftrace event print fmt");
2911 3181
3182 /* New ftrace handles args */
3183 if (ret > 0)
3184 return 0;
2912 /* 3185 /*
2913 * The arguments for ftrace files are parsed by the fields. 3186 * The arguments for ftrace files are parsed by the fields.
2914 * Set up the fields as their arguments. 3187 * Set up the fields as their arguments.
@@ -2926,7 +3199,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 3199 return 0;
2927} 3200}
2928 3201
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 3202int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 3203{
2931 struct event *event; 3204 struct event *event;
2932 int ret; 3205 int ret;
@@ -2946,12 +3219,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2946 die("failed to read event id"); 3219 die("failed to read event id");
2947 3220
2948 ret = event_read_format(event); 3221 ret = event_read_format(event);
2949 if (ret < 0) 3222 if (ret < 0) {
2950 die("failed to read event format"); 3223 warning("failed to read event format for %s", event->name);
3224 goto event_failed;
3225 }
2951 3226
2952 ret = event_read_print(event); 3227 ret = event_read_print(event);
2953 if (ret < 0) 3228 if (ret < 0) {
2954 die("failed to read event print fmt"); 3229 warning("failed to read event print fmt for %s", event->name);
3230 goto event_failed;
3231 }
3232
3233 event->system = strdup(sys);
2955 3234
2956#define PRINT_ARGS 0 3235#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3236 if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3238,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2959 3238
2960 add_event(event); 3239 add_event(event);
2961 return 0; 3240 return 0;
3241
3242 event_failed:
3243 event->flags |= EVENT_FL_FAILED;
3244 /* still add it even if it failed */
3245 add_event(event);
3246 return -1;
2962} 3247}
2963 3248
2964void parse_set_info(int nr_cpus, int long_sz) 3249void parse_set_info(int nr_cpus, int long_sz)
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..44292e06cca4 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -458,9 +458,8 @@ struct record *trace_read_data(int cpu)
458 return data; 458 return data;
459} 459}
460 460
461void trace_report(void) 461void trace_report(int fd)
462{ 462{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ]; 463 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 464 char test[] = { 23, 8, 68 };
466 char *version; 465 char *version;
@@ -468,9 +467,7 @@ void trace_report(void)
468 int show_funcs = 0; 467 int show_funcs = 0;
469 int show_printk = 0; 468 int show_printk = 0;
470 469
471 input_fd = open(input_file, O_RDONLY); 470 input_fd = fd;
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474 471
475 read_or_die(buf, 3); 472 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0) 473 if (memcmp(buf, test, 3) != 0)
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..f6637c2fa1fe 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
1#ifndef _TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include "parse-events.h" 4#include "parse-events.h"
5 5
@@ -26,6 +26,9 @@ enum {
26enum format_flags { 26enum format_flags {
27 FIELD_IS_ARRAY = 1, 27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2, 28 FIELD_IS_POINTER = 2,
29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16,
29}; 32};
30 33
31struct format_field { 34struct format_field {
@@ -132,15 +135,18 @@ struct event {
132 int flags; 135 int flags;
133 struct format format; 136 struct format format;
134 struct print_fmt print_fmt; 137 struct print_fmt print_fmt;
138 char *system;
135}; 139};
136 140
137enum { 141enum {
138 EVENT_FL_ISFTRACE = 1, 142 EVENT_FL_ISFTRACE = 0x01,
139 EVENT_FL_ISPRINT = 2, 143 EVENT_FL_ISPRINT = 0x02,
140 EVENT_FL_ISBPRINT = 4, 144 EVENT_FL_ISBPRINT = 0x04,
141 EVENT_FL_ISFUNC = 8, 145 EVENT_FL_ISFUNC = 0x08,
142 EVENT_FL_ISFUNCENT = 16, 146 EVENT_FL_ISFUNCENT = 0x10,
143 EVENT_FL_ISFUNCRET = 32, 147 EVENT_FL_ISFUNCRET = 0x20,
148
149 EVENT_FL_FAILED = 0x80000000
144}; 150};
145 151
146struct record { 152struct record {
@@ -154,7 +160,7 @@ struct record *trace_read_data(int cpu);
154 160
155void parse_set_info(int nr_cpus, int long_sz); 161void parse_set_info(int nr_cpus, int long_sz);
156 162
157void trace_report(void); 163void trace_report(int fd);
158 164
159void *malloc_or_die(unsigned int size); 165void *malloc_or_die(unsigned int size);
160 166
@@ -166,7 +172,7 @@ void print_funcs(void);
166void print_printk(void); 172void print_printk(void);
167 173
168int parse_ftrace_file(char *buf, unsigned long size); 174int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system); 175int parse_event_file(char *buf, unsigned long size, char *sys);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs, 176void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm); 177 char *comm);
172 178
@@ -233,6 +239,8 @@ extern int header_page_size_size;
233extern int header_page_data_offset; 239extern int header_page_data_offset;
234extern int header_page_data_size; 240extern int header_page_data_size;
235 241
242extern int latency_format;
243
236int parse_header_page(char *buf, unsigned long size); 244int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data); 245int trace_parse_common_type(void *data);
238struct event *trace_find_event(int id); 246struct event *trace_find_event(int id);
@@ -240,6 +248,15 @@ unsigned long long
240raw_field_value(struct event *event, const char *name, void *data); 248raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data); 249void *raw_field_ptr(struct event *event, const char *name, void *data);
242 250
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 251void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
252
253/* taken from kernel/trace/trace.h */
254enum trace_flag_type {
255 TRACE_FLAG_IRQS_OFF = 0x01,
256 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
257 TRACE_FLAG_NEED_RESCHED = 0x04,
258 TRACE_FLAG_HARDIRQ = 0x08,
259 TRACE_FLAG_SOFTIRQ = 0x10,
260};
244 261
245#endif /* _TRACE_EVENTS_H */ 262#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define _PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4/* 4/*
5 * We define u64 as unsigned long long for every architecture 5 * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
14typedef unsigned char u8; 14typedef unsigned char u8;
15typedef signed char s8; 15typedef signed char s8;
16 16
17#endif /* _PERF_TYPES_H */ 17#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define _PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
24void perf_read_values_display(FILE *fp, struct perf_read_values *values, 24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw); 25 int raw);
26 26
27#endif /* _PERF_VALUES_H */ 27#endif /* __PERF_VALUES_H */