aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2009-12-23 13:00:05 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-23 13:00:05 -0500
commit193cb93e5a5f32c0520eed17e87135d20594d1e1 (patch)
tree3b5584f4e5e73f5f01807e5176cbe29e1db69868 /tools/perf/util
parent23e707dd9b0b26215d801c59e87feed1c218a0f9 (diff)
parentf42ecb2808db5386f983d593a7c08d3ea3b94a27 (diff)
Merge branch 'master' of /home/gregkh/linux/git/torvalds-2.6
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/data_map.c167
-rw-r--r--tools/perf/util/data_map.h32
-rw-r--r--tools/perf/util/event.c214
-rw-r--r--tools/perf/util/event.h64
-rw-r--r--tools/perf/util/header.c39
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c518
-rw-r--r--tools/perf/util/hist.h55
-rw-r--r--tools/perf/util/map.c93
-rw-r--r--tools/perf/util/parse-events.c17
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/probe-event.c299
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c6
-rw-r--r--tools/perf/util/probe-finder.h58
-rw-r--r--tools/perf/util/session.c150
-rw-r--r--tools/perf/util/session.h61
-rw-r--r--tools/perf/util/sort.c26
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/string.c25
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h41
-rw-r--r--tools/perf/util/symbol.c355
-rw-r--r--tools/perf/util/symbol.h45
-rw-r--r--tools/perf/util/thread.c100
-rw-r--r--tools/perf/util/thread.h50
-rw-r--r--tools/perf/util/trace-event-parse.c4
-rw-r--r--tools/perf/util/trace-event-perl.c107
-rw-r--r--tools/perf/util/trace-event-perl.h4
-rw-r--r--tools/perf/util/trace-event-read.c3
-rw-r--r--tools/perf/util/trace-event.h2
32 files changed, 1956 insertions, 618 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index ca0bedf637c2..b557b836de3d 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -1,20 +1,17 @@
1#include "data_map.h"
2#include "symbol.h" 1#include "symbol.h"
3#include "util.h" 2#include "util.h"
4#include "debug.h" 3#include "debug.h"
4#include "thread.h"
5#include "session.h"
5 6
6 7static int process_event_stub(event_t *event __used,
7static struct perf_file_handler *curr_handler; 8 struct perf_session *session __used)
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{ 9{
13 dump_printf(": unhandled!\n"); 10 dump_printf(": unhandled!\n");
14 return 0; 11 return 0;
15} 12}
16 13
17void register_perf_file_handler(struct perf_file_handler *handler) 14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
18{ 15{
19 if (!handler->process_sample_event) 16 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub; 17 handler->process_sample_event = process_event_stub;
@@ -34,8 +31,6 @@ void register_perf_file_handler(struct perf_file_handler *handler)
34 handler->process_throttle_event = process_event_stub; 31 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event) 32 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub; 33 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39} 34}
40 35
41static const char *event__name[] = { 36static const char *event__name[] = {
@@ -61,8 +56,9 @@ void event__print_totals(void)
61 event__name[i], event__total[i]); 56 event__name[i], event__total[i]);
62} 57}
63 58
64static int 59static int process_event(event_t *event, struct perf_session *session,
65process_event(event_t *event, unsigned long offset, unsigned long head) 60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
66{ 62{
67 trace_event(event); 63 trace_event(event);
68 64
@@ -77,34 +73,34 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
77 73
78 switch (event->header.type) { 74 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE: 75 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event); 76 return ops->process_sample_event(event, session);
81 case PERF_RECORD_MMAP: 77 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event); 78 return ops->process_mmap_event(event, session);
83 case PERF_RECORD_COMM: 79 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event); 80 return ops->process_comm_event(event, session);
85 case PERF_RECORD_FORK: 81 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event); 82 return ops->process_fork_event(event, session);
87 case PERF_RECORD_EXIT: 83 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event); 84 return ops->process_exit_event(event, session);
89 case PERF_RECORD_LOST: 85 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event); 86 return ops->process_lost_event(event, session);
91 case PERF_RECORD_READ: 87 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event); 88 return ops->process_read_event(event, session);
93 case PERF_RECORD_THROTTLE: 89 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event); 90 return ops->process_throttle_event(event, session);
95 case PERF_RECORD_UNTHROTTLE: 91 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event); 92 return ops->process_unthrottle_event(event, session);
97 default: 93 default:
98 curr_handler->total_unknown++; 94 ops->total_unknown++;
99 return -1; 95 return -1;
100 } 96 }
101} 97}
102 98
103int perf_header__read_build_ids(int input, off_t offset, off_t size) 99int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{ 100{
105 struct build_id_event bev; 101 struct build_id_event bev;
106 char filename[PATH_MAX]; 102 char filename[PATH_MAX];
107 off_t limit = offset + size; 103 u64 limit = offset + size;
108 int err = -1; 104 int err = -1;
109 105
110 while (offset < limit) { 106 while (offset < limit) {
@@ -129,88 +125,58 @@ out:
129 return err; 125 return err;
130} 126}
131 127
132int mmap_dispatch_perf_file(struct perf_header **pheader, 128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
133 const char *input_name, 129{
134 int force, 130 struct thread *thread = perf_session__findnew(self, 0);
135 int full_paths, 131
136 int *cwdlen, 132 if (!thread || thread__set_comm(thread, "swapper")) {
137 char **cwd) 133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
138{ 142{
139 int err; 143 int err;
140 struct perf_header *header;
141 unsigned long head, shift; 144 unsigned long head, shift;
142 unsigned long offset = 0; 145 unsigned long offset = 0;
143 struct stat input_stat;
144 size_t page_size; 146 size_t page_size;
145 u64 sample_type;
146 event_t *event; 147 event_t *event;
147 uint32_t size; 148 uint32_t size;
148 int input;
149 char *buf; 149 char *buf;
150 150
151 if (curr_handler == NULL) { 151 if (perf_session__register_idle_thread(self) == NULL)
152 pr_debug("Forgot to register perf file handler\n"); 152 return -ENOMEM;
153 return -EINVAL;
154 }
155
156 page_size = getpagesize();
157
158 input = open(input_name, O_RDONLY);
159 if (input < 0) {
160 pr_err("Failed to open file: %s", input_name);
161 if (!strcmp(input_name, "perf.data"))
162 pr_err(" (try 'perf record' first)");
163 pr_err("\n");
164 return -errno;
165 }
166
167 if (fstat(input, &input_stat) < 0) {
168 pr_err("failed to stat file");
169 err = -errno;
170 goto out_close;
171 }
172
173 err = -EACCES;
174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175 pr_err("file: %s not owned by current user or root\n",
176 input_name);
177 goto out_close;
178 }
179
180 if (input_stat.st_size == 0) {
181 pr_info("zero-sized file, nothing to do!\n");
182 goto done;
183 }
184 153
185 err = -ENOMEM; 154 perf_event_ops__fill_defaults(ops);
186 header = perf_header__new();
187 if (header == NULL)
188 goto out_close;
189 155
190 err = perf_header__read(header, input); 156 page_size = getpagesize();
191 if (err < 0)
192 goto out_delete;
193 *pheader = header;
194 head = header->data_offset;
195 157
196 sample_type = perf_header__sample_type(header); 158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
197 160
198 err = -EINVAL; 161 err = -EINVAL;
199 if (curr_handler->sample_type_check && 162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
200 curr_handler->sample_type_check(sample_type) < 0) 163 goto out_err;
201 goto out_delete;
202 164
203 if (!full_paths) { 165 if (!ops->full_paths) {
204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 166 char bf[PATH_MAX];
205 pr_err("failed to get the current directory\n"); 167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
206 err = -errno; 169 err = -errno;
207 goto out_delete; 170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
208 } 178 }
209 *cwd = __cwd; 179 self->cwdlen = strlen(self->cwd);
210 *cwdlen = strlen(*cwd);
211 } else {
212 *cwd = NULL;
213 *cwdlen = 0;
214 } 180 }
215 181
216 shift = page_size * (head / page_size); 182 shift = page_size * (head / page_size);
@@ -218,12 +184,12 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
218 head -= shift; 184 head -= shift;
219 185
220remap: 186remap:
221 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
222 MAP_SHARED, input, offset); 188 MAP_SHARED, self->fd, offset);
223 if (buf == MAP_FAILED) { 189 if (buf == MAP_FAILED) {
224 pr_err("failed to mmap file\n"); 190 pr_err("failed to mmap file\n");
225 err = -errno; 191 err = -errno;
226 goto out_delete; 192 goto out_err;
227 } 193 }
228 194
229more: 195more:
@@ -233,12 +199,12 @@ more:
233 if (!size) 199 if (!size)
234 size = 8; 200 size = 8;
235 201
236 if (head + event->header.size >= page_size * mmap_window) { 202 if (head + event->header.size >= page_size * self->mmap_window) {
237 int munmap_ret; 203 int munmap_ret;
238 204
239 shift = page_size * (head / page_size); 205 shift = page_size * (head / page_size);
240 206
241 munmap_ret = munmap(buf, page_size * mmap_window); 207 munmap_ret = munmap(buf, page_size * self->mmap_window);
242 assert(munmap_ret == 0); 208 assert(munmap_ret == 0);
243 209
244 offset += shift; 210 offset += shift;
@@ -253,7 +219,7 @@ more:
253 (void *)(long)event->header.size, 219 (void *)(long)event->header.size,
254 event->header.type); 220 event->header.type);
255 221
256 if (!size || process_event(event, offset, head) < 0) { 222 if (!size || process_event(event, self, ops, offset, head) < 0) {
257 223
258 dump_printf("%p [%p]: skipping unknown header type: %d\n", 224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
259 (void *)(offset + head), 225 (void *)(offset + head),
@@ -273,19 +239,14 @@ more:
273 239
274 head += size; 240 head += size;
275 241
276 if (offset + head >= header->data_offset + header->data_size) 242 if (offset + head >= self->header.data_offset + self->header.data_size)
277 goto done; 243 goto done;
278 244
279 if (offset + head < (unsigned long)input_stat.st_size) 245 if (offset + head < self->size)
280 goto more; 246 goto more;
281 247
282done: 248done:
283 err = 0; 249 err = 0;
284out_close: 250out_err:
285 close(input);
286
287 return err; 251 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
291} 252}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
deleted file mode 100644
index 3180ff7e3633..000000000000
--- a/tools/perf/util/data_map.h
+++ /dev/null
@@ -1,32 +0,0 @@
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 *);
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);
30int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
31
32#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 414b89d1bde9..bb0fd6da2d56 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,11 +1,16 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h"
4#include "string.h" 6#include "string.h"
7#include "strlist.h"
5#include "thread.h" 8#include "thread.h"
6 9
7static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event)) 11 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
9{ 14{
10 event_t ev; 15 event_t ev;
11 char filename[PATH_MAX]; 16 char filename[PATH_MAX];
@@ -54,7 +59,7 @@ out_race:
54 if (!full) { 59 if (!full) {
55 ev.comm.tid = pid; 60 ev.comm.tid = pid;
56 61
57 process(&ev); 62 process(&ev, session);
58 goto out_fclose; 63 goto out_fclose;
59 } 64 }
60 65
@@ -72,7 +77,7 @@ out_race:
72 77
73 ev.comm.tid = pid; 78 ev.comm.tid = pid;
74 79
75 process(&ev); 80 process(&ev, session);
76 } 81 }
77 closedir(tasks); 82 closedir(tasks);
78 83
@@ -86,7 +91,9 @@ out_failure:
86} 91}
87 92
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event)) 94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
90{ 97{
91 char filename[PATH_MAX]; 98 char filename[PATH_MAX];
92 FILE *fp; 99 FILE *fp;
@@ -141,7 +148,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
141 ev.mmap.pid = tgid; 148 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid; 149 ev.mmap.tid = pid;
143 150
144 process(&ev); 151 process(&ev, session);
145 } 152 }
146 } 153 }
147 154
@@ -149,15 +156,20 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
149 return 0; 156 return 0;
150} 157}
151 158
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) 159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
153{ 163{
154 pid_t tgid = event__synthesize_comm(pid, 1, process); 164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
155 if (tgid == -1) 165 if (tgid == -1)
156 return -1; 166 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process); 167 return event__synthesize_mmap_events(pid, tgid, process, session);
158} 168}
159 169
160void event__synthesize_threads(int (*process)(event_t *event)) 170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
161{ 173{
162 DIR *proc; 174 DIR *proc;
163 struct dirent dirent, *next; 175 struct dirent dirent, *next;
@@ -171,24 +183,47 @@ void event__synthesize_threads(int (*process)(event_t *event))
171 if (*end) /* only interested in proper numerical dirents */ 183 if (*end) /* only interested in proper numerical dirents */
172 continue; 184 continue;
173 185
174 event__synthesize_thread(pid, process); 186 event__synthesize_thread(pid, process, session);
175 } 187 }
176 188
177 closedir(proc); 189 closedir(proc);
178} 190}
179 191
180char *event__cwd; 192static void thread__comm_adjust(struct thread *self)
181int event__cwdlen; 193{
194 char *comm = self->comm;
195
196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
200
201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
209{
210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
182 214
183struct events_stats event__stats; 215 thread__comm_adjust(self);
184 216
185int event__process_comm(event_t *self) 217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
186{ 221{
187 struct thread *thread = threads__findnew(self->comm.pid); 222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
188 223
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 225
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1; 228 return -1;
194 } 229 }
@@ -196,18 +231,18 @@ int event__process_comm(event_t *self)
196 return 0; 231 return 0;
197} 232}
198 233
199int event__process_lost(event_t *self) 234int event__process_lost(event_t *self, struct perf_session *session)
200{ 235{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost; 237 session->events_stats.lost += self->lost.lost;
203 return 0; 238 return 0;
204} 239}
205 240
206int event__process_mmap(event_t *self) 241int event__process_mmap(event_t *self, struct perf_session *session)
207{ 242{
208 struct thread *thread = threads__findnew(self->mmap.pid); 243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 event__cwd, event__cwdlen); 245 session->cwd, session->cwdlen);
211 246
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 self->mmap.pid, self->mmap.tid, 248 self->mmap.pid, self->mmap.tid,
@@ -224,10 +259,10 @@ int event__process_mmap(event_t *self)
224 return 0; 259 return 0;
225} 260}
226 261
227int event__process_task(event_t *self) 262int event__process_task(event_t *self, struct perf_session *session)
228{ 263{
229 struct thread *thread = threads__findnew(self->fork.pid); 264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid); 265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
231 266
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid); 268 self->fork.ppid, self->fork.ptid);
@@ -249,18 +284,20 @@ int event__process_task(event_t *self)
249 return 0; 284 return 0;
250} 285}
251 286
252void thread__find_addr_location(struct thread *self, u8 cpumode, 287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
253 enum map_type type, u64 addr, 289 enum map_type type, u64 addr,
254 struct addr_location *al, 290 struct addr_location *al,
255 symbol_filter_t filter) 291 symbol_filter_t filter)
256{ 292{
257 struct thread *thread = al->thread = self; 293 struct map_groups *mg = &self->mg;
258 294
295 al->thread = self;
259 al->addr = addr; 296 al->addr = addr;
260 297
261 if (cpumode & PERF_RECORD_MISC_KERNEL) { 298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
262 al->level = 'k'; 299 al->level = 'k';
263 thread = kthread; 300 mg = &session->kmaps;
264 } else if (cpumode & PERF_RECORD_MISC_USER) 301 } else if (cpumode & PERF_RECORD_MISC_USER)
265 al->level = '.'; 302 al->level = '.';
266 else { 303 else {
@@ -270,7 +307,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
270 return; 307 return;
271 } 308 }
272try_again: 309try_again:
273 al->map = thread__find_map(thread, type, al->addr); 310 al->map = map_groups__find(mg, type, al->addr);
274 if (al->map == NULL) { 311 if (al->map == NULL) {
275 /* 312 /*
276 * If this is outside of all known maps, and is a negative 313 * If this is outside of all known maps, and is a negative
@@ -281,32 +318,139 @@ try_again:
281 * "[vdso]" dso, but for now lets use the old trick of looking 318 * "[vdso]" dso, but for now lets use the old trick of looking
282 * in the whole kernel symbol list. 319 * in the whole kernel symbol list.
283 */ 320 */
284 if ((long long)al->addr < 0 && thread != kthread) { 321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
285 thread = kthread; 322 mg = &session->kmaps;
286 goto try_again; 323 goto try_again;
287 } 324 }
288 al->sym = NULL; 325 al->sym = NULL;
289 } else { 326 } else {
290 al->addr = al->map->map_ip(al->map, al->addr); 327 al->addr = al->map->map_ip(al->map, al->addr);
291 al->sym = map__find_symbol(al->map, al->addr, filter); 328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
292 } 329 }
293} 330}
294 331
295int event__preprocess_sample(const event_t *self, struct addr_location *al, 332static void dso__calc_col_width(struct dso *self)
296 symbol_filter_t filter) 333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
297{ 347{
298 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
299 struct thread *thread = threads__findnew(self->ip.pid); 349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
300 350
301 if (thread == NULL) 351 if (thread == NULL)
302 return -1; 352 return -1;
303 353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
304 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
305 359
306 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
307 self->ip.ip, al, filter); 361 self->ip.ip, al, filter);
308 dump_printf(" ...... dso: %s\n", 362 dump_printf(" ...... dso: %s\n",
309 al->map ? al->map->dso->long_name : 363 al->map ? al->map->dso->long_name :
310 al->level == 'H' ? "[hypervisor]" : "<not found>"); 364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
388 return 0;
389}
390
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
392{
393 u64 *array = event->sample.array;
394
395 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip;
397 array++;
398 }
399
400 if (type & PERF_SAMPLE_TID) {
401 u32 *p = (u32 *)array;
402 data->pid = p[0];
403 data->tid = p[1];
404 array++;
405 }
406
407 if (type & PERF_SAMPLE_TIME) {
408 data->time = *array;
409 array++;
410 }
411
412 if (type & PERF_SAMPLE_ADDR) {
413 data->addr = *array;
414 array++;
415 }
416
417 if (type & PERF_SAMPLE_ID) {
418 data->id = *array;
419 array++;
420 }
421
422 if (type & PERF_SAMPLE_STREAM_ID) {
423 data->stream_id = *array;
424 array++;
425 }
426
427 if (type & PERF_SAMPLE_CPU) {
428 u32 *p = (u32 *)array;
429 data->cpu = *p;
430 array++;
431 }
432
433 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array;
435 array++;
436 }
437
438 if (type & PERF_SAMPLE_READ) {
439 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
440 return -1;
441 }
442
443 if (type & PERF_SAMPLE_CALLCHAIN) {
444 data->callchain = (struct ip_callchain *)array;
445 array += 1 + data->callchain->nr;
446 }
447
448 if (type & PERF_SAMPLE_RAW) {
449 u32 *p = (u32 *)array;
450 data->raw_size = *p;
451 p++;
452 data->raw_data = p;
453 }
454
311 return 0; 455 return 0;
312} 456}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a4cc8105cf67..690a96d0467c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,11 +56,25 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59struct sample_event{ 59struct sample_event {
60 struct perf_event_header header; 60 struct perf_event_header header;
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64struct sample_data {
65 u64 ip;
66 u32 pid, tid;
67 u64 time;
68 u64 addr;
69 u64 id;
70 u64 stream_id;
71 u32 cpu;
72 u64 period;
73 struct ip_callchain *callchain;
74 u32 raw_size;
75 void *raw_data;
76};
77
64#define BUILD_ID_SIZE 20 78#define BUILD_ID_SIZE 20
65 79
66struct build_id_event { 80struct build_id_event {
@@ -81,18 +95,19 @@ typedef union event_union {
81} event_t; 95} event_t;
82 96
83struct events_stats { 97struct events_stats {
84 unsigned long total; 98 u64 total;
85 unsigned long lost; 99 u64 lost;
86}; 100};
87 101
88void event__print_totals(void); 102void event__print_totals(void);
89 103
90enum map_type { 104enum map_type {
91 MAP__FUNCTION = 0, 105 MAP__FUNCTION = 0,
92 106 MAP__VARIABLE,
93 MAP__NR_TYPES,
94}; 107};
95 108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
96struct map { 111struct map {
97 union { 112 union {
98 struct rb_node rb_node; 113 struct rb_node rb_node;
@@ -134,26 +149,35 @@ void map__delete(struct map *self);
134struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
135int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
136size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
137struct symbol *map__find_symbol(struct map *self, u64 addr, 152
138 symbol_filter_t filter); 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
139void map__fixup_start(struct map *self); 162void map__fixup_start(struct map *self);
140void map__fixup_end(struct map *self); 163void map__fixup_end(struct map *self);
141 164
142int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 165int event__synthesize_thread(pid_t pid,
143void event__synthesize_threads(int (*process)(event_t *event)); 166 int (*process)(event_t *event,
144 167 struct perf_session *session),
145extern char *event__cwd; 168 struct perf_session *session);
146extern int event__cwdlen; 169void event__synthesize_threads(int (*process)(event_t *event,
147extern struct events_stats event__stats; 170 struct perf_session *session),
148extern unsigned long event__total[PERF_RECORD_MAX]; 171 struct perf_session *session);
149 172
150int event__process_comm(event_t *self); 173int event__process_comm(event_t *self, struct perf_session *session);
151int event__process_lost(event_t *self); 174int event__process_lost(event_t *self, struct perf_session *session);
152int event__process_mmap(event_t *self); 175int event__process_mmap(event_t *self, struct perf_session *session);
153int event__process_task(event_t *self); 176int event__process_task(event_t *self, struct perf_session *session);
154 177
155struct addr_location; 178struct addr_location;
156int event__preprocess_sample(const event_t *self, struct addr_location *al, 179int event__preprocess_sample(const event_t *self, struct perf_session *session,
157 symbol_filter_t filter); 180 struct addr_location *al, symbol_filter_t filter);
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
158 182
159#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4805e6dfd23c..8a0bca55106f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,8 +8,8 @@
8#include "header.h" 8#include "header.h"
9#include "../perf.h" 9#include "../perf.h"
10#include "trace-event.h" 10#include "trace-event.h"
11#include "session.h"
11#include "symbol.h" 12#include "symbol.h"
12#include "data_map.h"
13#include "debug.h" 13#include "debug.h"
14 14
15/* 15/*
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
58 return 0; 58 return 0;
59} 59}
60 60
61/* 61int perf_header__init(struct perf_header *self)
62 * Create new perf.data header:
63 */
64struct perf_header *perf_header__new(void)
65{ 62{
66 struct perf_header *self = zalloc(sizeof(*self)); 63 self->size = 1;
67 64 self->attr = malloc(sizeof(void *));
68 if (self != NULL) { 65 return self->attr == NULL ? -ENOMEM : 0;
69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
71
72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
77
78 return self;
79} 66}
80 67
81void perf_header__delete(struct perf_header *self) 68void perf_header__exit(struct perf_header *self)
82{ 69{
83 int i; 70 int i;
84
85 for (i = 0; i < self->attrs; ++i) 71 for (i = 0; i < self->attrs; ++i)
86 perf_header_attr__delete(self->attr[i]); 72 perf_header_attr__delete(self->attr[i]);
87
88 free(self->attr); 73 free(self->attr);
89 free(self);
90} 74}
91 75
92int perf_header__add_attr(struct perf_header *self, 76int perf_header__add_attr(struct perf_header *self,
@@ -187,7 +171,9 @@ static int do_write(int fd, const void *buf, size_t size)
187 171
188static int __dsos__write_buildid_table(struct list_head *head, int fd) 172static int __dsos__write_buildid_table(struct list_head *head, int fd)
189{ 173{
174#define NAME_ALIGN 64
190 struct dso *pos; 175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN];
191 177
192 list_for_each_entry(pos, head, node) { 178 list_for_each_entry(pos, head, node) {
193 int err; 179 int err;
@@ -197,14 +183,17 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
197 if (!pos->has_build_id) 183 if (!pos->has_build_id)
198 continue; 184 continue;
199 len = pos->long_name_len + 1; 185 len = pos->long_name_len + 1;
200 len = ALIGN(len, 64); 186 len = ALIGN(len, NAME_ALIGN);
201 memset(&b, 0, sizeof(b)); 187 memset(&b, 0, sizeof(b));
202 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
203 b.header.size = sizeof(b) + len; 189 b.header.size = sizeof(b) + len;
204 err = do_write(fd, &b, sizeof(b)); 190 err = do_write(fd, &b, sizeof(b));
205 if (err < 0) 191 if (err < 0)
206 return err; 192 return err;
207 err = do_write(fd, pos->long_name, len); 193 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
194 if (err < 0)
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
208 if (err < 0) 197 if (err < 0)
209 return err; 198 return err;
210 } 199 }
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d1dbe2b79c42..d118d05d3abe 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -55,8 +55,8 @@ struct perf_header {
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 56};
57 57
58struct perf_header *perf_header__new(void); 58int perf_header__init(struct perf_header *self);
59void perf_header__delete(struct perf_header *self); 59void perf_header__exit(struct perf_header *self);
60 60
61int perf_header__read(struct perf_header *self, int fd); 61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0ebf6ee16caa..e8daf5ca6fd2 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,9 +1,7 @@
1#include "hist.h" 1#include "hist.h"
2 2#include "session.h"
3struct rb_root hist; 3#include "sort.h"
4struct rb_root collapse_hists; 4#include <math.h>
5struct rb_root output_hists;
6int callchain;
7 5
8struct callchain_param callchain_param = { 6struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 7 .mode = CHAIN_GRAPH_REL,
@@ -14,11 +12,12 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
15 */ 13 */
16 14
17struct hist_entry *__hist_entry__add(struct addr_location *al, 15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
18 struct symbol *sym_parent, 16 struct addr_location *al,
19 u64 count, bool *hit) 17 struct symbol *sym_parent,
18 u64 count, bool *hit)
20{ 19{
21 struct rb_node **p = &hist.rb_node; 20 struct rb_node **p = &self->hists.rb_node;
22 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
23 struct hist_entry *he; 22 struct hist_entry *he;
24 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -54,7 +53,7 @@ struct hist_entry *__hist_entry__add(struct addr_location *al,
54 return NULL; 53 return NULL;
55 *he = entry; 54 *he = entry;
56 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist); 56 rb_insert_color(&he->rb_node, &self->hists);
58 *hit = false; 57 *hit = false;
59 return he; 58 return he;
60} 59}
@@ -102,9 +101,9 @@ void hist_entry__free(struct hist_entry *he)
102 * collapse the histogram 101 * collapse the histogram
103 */ 102 */
104 103
105void collapse__insert_entry(struct hist_entry *he) 104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
106{ 105{
107 struct rb_node **p = &collapse_hists.rb_node; 106 struct rb_node **p = &root->rb_node;
108 struct rb_node *parent = NULL; 107 struct rb_node *parent = NULL;
109 struct hist_entry *iter; 108 struct hist_entry *iter;
110 int64_t cmp; 109 int64_t cmp;
@@ -128,38 +127,45 @@ void collapse__insert_entry(struct hist_entry *he)
128 } 127 }
129 128
130 rb_link_node(&he->rb_node, parent, p); 129 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists); 130 rb_insert_color(&he->rb_node, root);
132} 131}
133 132
134void collapse__resort(void) 133void perf_session__collapse_resort(struct perf_session *self)
135{ 134{
135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
137 struct hist_entry *n; 137 struct hist_entry *n;
138 138
139 if (!sort__need_collapse) 139 if (!sort__need_collapse)
140 return; 140 return;
141 141
142 next = rb_first(&hist); 142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
143 while (next) { 145 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
146 148
147 rb_erase(&n->rb_node, &hist); 149 rb_erase(&n->rb_node, &self->hists);
148 collapse__insert_entry(n); 150 collapse__insert_entry(&tmp, n);
149 } 151 }
152
153 self->hists = tmp;
150} 154}
151 155
152/* 156/*
153 * reverse the map, sort on count. 157 * reverse the map, sort on count.
154 */ 158 */
155 159
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) 160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
157{ 163{
158 struct rb_node **p = &output_hists.rb_node; 164 struct rb_node **p = &root->rb_node;
159 struct rb_node *parent = NULL; 165 struct rb_node *parent = NULL;
160 struct hist_entry *iter; 166 struct hist_entry *iter;
161 167
162 if (callchain) 168 if (symbol_conf.use_callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain, 169 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param); 170 min_callchain_hits, &callchain_param);
165 171
@@ -174,29 +180,483 @@ void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
174 } 180 }
175 181
176 rb_link_node(&he->rb_node, parent, p); 182 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists); 183 rb_insert_color(&he->rb_node, root);
178} 184}
179 185
180void output__resort(u64 total_samples) 186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
181{ 187{
188 struct rb_root tmp;
182 struct rb_node *next; 189 struct rb_node *next;
183 struct hist_entry *n; 190 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits; 191 u64 min_callchain_hits;
186 192
187 min_callchain_hits = 193 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
189 195
190 if (sort__need_collapse) 196 tmp = RB_ROOT;
191 tree = &collapse_hists; 197 next = rb_first(&self->hists);
192
193 next = rb_first(tree);
194 198
195 while (next) { 199 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
198 202
199 rb_erase(&n->rb_node, tree); 203 rb_erase(&n->rb_node, &self->hists);
200 output__insert_entry(n, min_callchain_hits); 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line seperator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session->events_stats.total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
201 } 657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
202} 662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3020db0c9292..e5f99b24048b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -1,50 +1,27 @@
1#ifndef __PERF_HIST_H 1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3#include "../builtin.h"
4 3
5#include "util.h" 4#include <linux/types.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" 5#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 6
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; 7extern 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 8
39struct hist_entry *__hist_entry__add(struct addr_location *al, 9struct perf_session;
40 struct symbol *parent, 10struct hist_entry;
41 u64 count, bool *hit); 11struct addr_location;
12struct symbol;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 20void 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 21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
50#endif /* __PERF_HIST_H */ 27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 69f94fe9db20..c4d55a0da2ea 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,43 +104,70 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107struct symbol *map__find_symbol(struct map *self, u64 addr, 107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter) 108 symbol_filter_t filter)
109{ 109{
110 if (!dso__loaded(self->dso, self->type)) { 110 const char *name = self->dso->long_name;
111 int nr = dso__load(self->dso, self, filter); 111 int nr;
112 112
113 if (nr < 0) { 113 if (dso__loaded(self->dso, self->type))
114 if (self->dso->has_build_id) { 114 return 0;
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 115
116 116 nr = dso__load(self->dso, self, session, filter);
117 build_id__sprintf(self->dso->build_id, 117 if (nr < 0) {
118 sizeof(self->dso->build_id), 118 if (self->dso->has_build_id) {
119 sbuild_id); 119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
120 pr_warning("%s with build id %s not found", 120
121 self->dso->long_name, sbuild_id); 121 build_id__sprintf(self->dso->build_id,
122 } else 122 sizeof(self->dso->build_id),
123 pr_warning("Failed to open %s", 123 sbuild_id);
124 self->dso->long_name); 124 pr_warning("%s with build id %s not found",
125 pr_warning(", continuing without symbols\n"); 125 name, sbuild_id);
126 return NULL; 126 } else
127 } else if (nr == 0) { 127 pr_warning("Failed to open %s", name);
128 const char *name = self->dso->long_name; 128
129 const size_t len = strlen(name); 129 pr_warning(", continuing without symbols\n");
130 const size_t real_len = len - sizeof(DSO__DELETED); 130 return -1;
131 131 } else if (nr == 0) {
132 if (len > sizeof(DSO__DELETED) && 132 const size_t len = strlen(name);
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 133 const size_t real_len = len - sizeof(DSO__DELETED);
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n", 134
135 (int)real_len, name); 135 if (len > sizeof(DSO__DELETED) &&
136 } else { 136 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name); 137 pr_warning("%.*s was updated, restart the long "
138 } 138 "running apps that use it!\n",
139 return NULL; 139 (int)real_len, name);
140 } else {
141 pr_warning("no symbols found in %s, maybe install "
142 "a debug package?\n", name);
140 } 143 }
144
145 return -1;
141 } 146 }
142 147
143 return self->dso->find_symbol(self->dso, self->type, addr); 148 return 0;
149}
150
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
152 u64 addr, symbol_filter_t filter)
153{
154 if (map__load(self, session, filter) < 0)
155 return NULL;
156
157 return dso__find_symbol(self->dso, self->type, addr);
158}
159
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter)
163{
164 if (map__load(self, session, filter) < 0)
165 return NULL;
166
167 if (!dso__sorted_by_name(self->dso, self->type))
168 dso__sort_by_name(self->dso, self->type);
169
170 return dso__find_symbol_by_name(self->dso, self->type, name);
144} 171}
145 172
146struct map *map__clone(struct map *self) 173struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9e5dbd66d34d..e5bc0fb016b2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
197 if (id == config) { 197 if (id == config) {
198 closedir(evt_dir); 198 closedir(evt_dir);
199 closedir(sys_dir); 199 closedir(sys_dir);
200 path = zalloc(sizeof(path)); 200 path = zalloc(sizeof(*path));
201 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
202 if (!path->system) { 202 if (!path->system) {
203 free(path); 203 free(path);
@@ -467,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
467 while ((evt_ent = readdir(evt_dir))) { 467 while ((evt_ent = readdir(evt_dir))) {
468 char event_opt[MAX_EVOPT_LEN + 1]; 468 char event_opt[MAX_EVOPT_LEN + 1];
469 int len; 469 int len;
470 unsigned int rem = MAX_EVOPT_LEN;
471 470
472 if (!strcmp(evt_ent->d_name, ".") 471 if (!strcmp(evt_ent->d_name, ".")
473 || !strcmp(evt_ent->d_name, "..") 472 || !strcmp(evt_ent->d_name, "..")
@@ -475,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
475 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
476 continue; 475 continue;
477 476
478 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
479 evt_ent->d_name); 478 evt_ent->d_name, flags ? ":" : "",
479 flags ?: "");
480 if (len < 0) 480 if (len < 0)
481 return EVT_FAILED; 481 return EVT_FAILED;
482 482
483 rem -= len;
484 if (flags) {
485 if (rem < strlen(flags) + 1)
486 return EVT_FAILED;
487
488 strcat(event_opt, ":");
489 strcat(event_opt, flags);
490 }
491
492 if (parse_events(NULL, event_opt, 0)) 483 if (parse_events(NULL, event_opt, 0))
493 return EVT_FAILED; 484 return EVT_FAILED;
494 } 485 }
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 6d8af48c925e..efebd5b476b3 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr,
430 pos = fprintf(stderr, " "); 430 pos = fprintf(stderr, " ");
431 if (opts->short_name) 431 if (opts->short_name)
432 pos += fprintf(stderr, "-%c", opts->short_name); 432 pos += fprintf(stderr, "-%c", opts->short_name);
433 else
434 pos += fprintf(stderr, " ");
435
433 if (opts->long_name && opts->short_name) 436 if (opts->long_name && opts->short_name)
434 pos += fprintf(stderr, ", "); 437 pos += fprintf(stderr, ", ");
435 if (opts->long_name) 438 if (opts->long_name)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index cd7fbda5e2a5..29465d440043 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -48,6 +48,9 @@
48 48
49/* If there is no space to write, returns -E2BIG. */ 49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...) 50static int e_snprintf(char *str, size_t size, const char *format, ...)
51 __attribute__((format(printf, 3, 4)));
52
53static int e_snprintf(char *str, size_t size, const char *format, ...)
51{ 54{
52 int ret; 55 int ret;
53 va_list ap; 56 va_list ap;
@@ -59,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
59 return ret; 62 return ret;
60} 63}
61 64
65/* Check the name is good for event/group */
66static bool check_event_name(const char *name)
67{
68 if (!isalpha(*name) && *name != '_')
69 return false;
70 while (*++name != '\0') {
71 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
72 return false;
73 }
74 return true;
75}
76
62/* Parse probepoint definition. */ 77/* Parse probepoint definition. */
63static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
64{ 79{
@@ -66,10 +81,26 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
66 char c, nc = 0; 81 char c, nc = 0;
67 /* 82 /*
68 * <Syntax> 83 * <Syntax>
69 * perf probe SRC:LN 84 * perf probe [EVENT=]SRC:LN
70 * perf probe FUNC[+OFFS|%return][@SRC] 85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
71 */ 88 */
72 89
90 ptr = strchr(arg, '=');
91 if (ptr) { /* Event name */
92 *ptr = '\0';
93 tmp = ptr + 1;
94 ptr = strchr(arg, ':');
95 if (ptr) /* Group name is not supported yet. */
96 semantic_error("Group name is not supported yet.");
97 if (!check_event_name(arg))
98 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg);
100 pp->event = strdup(arg);
101 arg = tmp;
102 }
103
73 ptr = strpbrk(arg, ":+@%"); 104 ptr = strpbrk(arg, ":+@%");
74 if (ptr) { 105 if (ptr) {
75 nc = *ptr; 106 nc = *ptr;
@@ -147,10 +178,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
147} 178}
148 179
149/* Parse perf-probe event definition */ 180/* Parse perf-probe event definition */
150int parse_perf_probe_event(const char *str, struct probe_point *pp) 181void parse_perf_probe_event(const char *str, struct probe_point *pp,
182 bool *need_dwarf)
151{ 183{
152 char **argv; 184 char **argv;
153 int argc, i, need_dwarf = 0; 185 int argc, i;
186
187 *need_dwarf = false;
154 188
155 argv = argv_split(str, &argc); 189 argv = argv_split(str, &argc);
156 if (!argv) 190 if (!argv)
@@ -161,7 +195,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
161 /* Parse probe point */ 195 /* Parse probe point */
162 parse_perf_probe_probepoint(argv[0], pp); 196 parse_perf_probe_probepoint(argv[0], pp);
163 if (pp->file || pp->line) 197 if (pp->file || pp->line)
164 need_dwarf = 1; 198 *need_dwarf = true;
165 199
166 /* Copy arguments and ensure return probe has no C argument */ 200 /* Copy arguments and ensure return probe has no C argument */
167 pp->nr_args = argc - 1; 201 pp->nr_args = argc - 1;
@@ -174,17 +208,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
174 if (pp->retprobe) 208 if (pp->retprobe)
175 semantic_error("You can't specify local" 209 semantic_error("You can't specify local"
176 " variable for kretprobe"); 210 " variable for kretprobe");
177 need_dwarf = 1; 211 *need_dwarf = true;
178 } 212 }
179 } 213 }
180 214
181 argv_free(argv); 215 argv_free(argv);
182 return need_dwarf;
183} 216}
184 217
185/* Parse kprobe_events event into struct probe_point */ 218/* Parse kprobe_events event into struct probe_point */
186void parse_trace_kprobe_event(const char *str, char **group, char **event, 219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
187 struct probe_point *pp)
188{ 220{
189 char pr; 221 char pr;
190 char *p; 222 char *p;
@@ -200,18 +232,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
200 232
201 /* Scan event and group name. */ 233 /* Scan event and group name. */
202 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
203 &pr, (float *)(void *)group, (float *)(void *)event); 235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
204 if (ret != 3) 237 if (ret != 3)
205 semantic_error("Failed to parse event name: %s", argv[0]); 238 semantic_error("Failed to parse event name: %s", argv[0]);
206 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr); 239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
207
208 if (!pp)
209 goto end;
210 240
211 pp->retprobe = (pr == 'r'); 241 pp->retprobe = (pr == 'r');
212 242
213 /* Scan function name and offset */ 243 /* Scan function name and offset */
214 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); 244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
245 &pp->offset);
215 if (ret == 1) 246 if (ret == 1)
216 pp->offset = 0; 247 pp->offset = 0;
217 248
@@ -230,15 +261,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
230 die("Failed to copy argument."); 261 die("Failed to copy argument.");
231 } 262 }
232 263
233end:
234 argv_free(argv); 264 argv_free(argv);
235} 265}
236 266
237int synthesize_perf_probe_event(struct probe_point *pp) 267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
238{ 269{
239 char *buf; 270 char *buf;
240 char offs[64] = "", line[64] = ""; 271 char offs[64] = "", line[64] = "";
241 int i, len, ret; 272 int ret;
242 273
243 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
244 if (!buf) 275 if (!buf)
@@ -258,11 +289,25 @@ int synthesize_perf_probe_event(struct probe_point *pp)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line); 290 offs, pp->retprobe ? "%return" : "", line);
260 else 291 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); 292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
262 if (ret <= 0) 293 if (ret <= 0) {
263 goto error; 294error:
264 len = ret; 295 free(pp->probes[0]);
296 pp->probes[0] = NULL;
297 }
298 return ret;
299}
300
301int synthesize_perf_probe_event(struct probe_point *pp)
302{
303 char *buf;
304 int i, len, ret;
305
306 len = synthesize_perf_probe_point(pp);
307 if (len < 0)
308 return 0;
265 309
310 buf = pp->probes[0];
266 for (i = 0; i < pp->nr_args; i++) { 311 for (i = 0; i < pp->nr_args; i++) {
267 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
268 pp->args[i]); 313 pp->args[i]);
@@ -275,6 +320,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
275 return pp->found; 320 return pp->found;
276error: 321error:
277 free(pp->probes[0]); 322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
278 324
279 return ret; 325 return ret;
280} 326}
@@ -304,6 +350,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
304 return pp->found; 350 return pp->found;
305error: 351error:
306 free(pp->probes[0]); 352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
307 354
308 return ret; 355 return ret;
309} 356}
@@ -363,6 +410,10 @@ static void clear_probe_point(struct probe_point *pp)
363{ 410{
364 int i; 411 int i;
365 412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
366 if (pp->function) 417 if (pp->function)
367 free(pp->function); 418 free(pp->function);
368 if (pp->file) 419 if (pp->file)
@@ -373,15 +424,33 @@ static void clear_probe_point(struct probe_point *pp)
373 free(pp->args); 424 free(pp->args);
374 for (i = 0; i < pp->found; i++) 425 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]); 426 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp)); 427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place,
432 struct probe_point *pp)
433{
434 int i, ret;
435 char buf[128];
436
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
440 printf(" %-40s (on %s", buf, place);
441
442 if (pp->nr_args > 0) {
443 printf(" with");
444 for (i = 0; i < pp->nr_args; i++)
445 printf(" %s", pp->args[i]);
446 }
447 printf(")\n");
377} 448}
378 449
379/* List up current perf-probe events */ 450/* List up current perf-probe events */
380void show_perf_probe_events(void) 451void show_perf_probe_events(void)
381{ 452{
382 unsigned int i;
383 int fd; 453 int fd;
384 char *group, *event;
385 struct probe_point pp; 454 struct probe_point pp;
386 struct strlist *rawlist; 455 struct strlist *rawlist;
387 struct str_node *ent; 456 struct str_node *ent;
@@ -390,13 +459,12 @@ void show_perf_probe_events(void)
390 rawlist = get_trace_kprobe_event_rawlist(fd); 459 rawlist = get_trace_kprobe_event_rawlist(fd);
391 close(fd); 460 close(fd);
392 461
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 462 strlist__for_each(ent, rawlist) {
394 ent = strlist__entry(rawlist, i); 463 parse_trace_kprobe_event(ent->s, &pp);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp); 464 /* Synthesize only event probe point */
396 synthesize_perf_probe_event(&pp); 465 synthesize_perf_probe_point(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); 466 /* Show an event */
398 free(group); 467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
399 free(event);
400 clear_probe_point(&pp); 468 clear_probe_point(&pp);
401 } 469 }
402 470
@@ -404,21 +472,27 @@ void show_perf_probe_events(void)
404} 472}
405 473
406/* Get current perf-probe event names */ 474/* Get current perf-probe event names */
407static struct strlist *get_perf_event_names(int fd) 475static struct strlist *get_perf_event_names(int fd, bool include_group)
408{ 476{
409 unsigned int i; 477 char buf[128];
410 char *group, *event;
411 struct strlist *sl, *rawlist; 478 struct strlist *sl, *rawlist;
412 struct str_node *ent; 479 struct str_node *ent;
480 struct probe_point pp;
413 481
482 memset(&pp, 0, sizeof(pp));
414 rawlist = get_trace_kprobe_event_rawlist(fd); 483 rawlist = get_trace_kprobe_event_rawlist(fd);
415 484
416 sl = strlist__new(false, NULL); 485 sl = strlist__new(true, NULL);
417 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 486 strlist__for_each(ent, rawlist) {
418 ent = strlist__entry(rawlist, i); 487 parse_trace_kprobe_event(ent->s, &pp);
419 parse_trace_kprobe_event(ent->s, &group, &event, NULL); 488 if (include_group) {
420 strlist__add(sl, event); 489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
421 free(group); 490 pp.event) < 0)
491 die("Failed to copy group:event name.");
492 strlist__add(sl, buf);
493 } else
494 strlist__add(sl, pp.event);
495 clear_probe_point(&pp);
422 } 496 }
423 497
424 strlist__delete(rawlist); 498 strlist__delete(rawlist);
@@ -426,24 +500,36 @@ static struct strlist *get_perf_event_names(int fd)
426 return sl; 500 return sl;
427} 501}
428 502
429static int write_trace_kprobe_event(int fd, const char *buf) 503static void write_trace_kprobe_event(int fd, const char *buf)
430{ 504{
431 int ret; 505 int ret;
432 506
507 pr_debug("Writing event: %s\n", buf);
433 ret = write(fd, buf, strlen(buf)); 508 ret = write(fd, buf, strlen(buf));
434 if (ret <= 0) 509 if (ret <= 0)
435 die("Failed to create event."); 510 die("Failed to write event: %s", strerror(errno));
436 else
437 printf("Added new event: %s\n", buf);
438
439 return ret;
440} 511}
441 512
442static void get_new_event_name(char *buf, size_t len, const char *base, 513static void get_new_event_name(char *buf, size_t len, const char *base,
443 struct strlist *namelist) 514 struct strlist *namelist, bool allow_suffix)
444{ 515{
445 int i, ret; 516 int i, ret;
446 for (i = 0; i < MAX_EVENT_INDEX; i++) { 517
518 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0)
521 die("snprintf() failed: %s", strerror(-ret));
522 if (!strlist__has_entry(namelist, buf))
523 return;
524
525 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event.");
529 }
530
531 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
447 ret = e_snprintf(buf, len, "%s_%d", base, i); 533 ret = e_snprintf(buf, len, "%s_%d", base, i);
448 if (ret < 0) 534 if (ret < 0)
449 die("snprintf() failed: %s", strerror(-ret)); 535 die("snprintf() failed: %s", strerror(-ret));
@@ -454,31 +540,138 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
454 die("Too many events are on the same function."); 540 die("Too many events are on the same function.");
455} 541}
456 542
457void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) 543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
544 bool force_add)
458{ 545{
459 int i, j, fd; 546 int i, j, fd;
460 struct probe_point *pp; 547 struct probe_point *pp;
461 char buf[MAX_CMDLEN]; 548 char buf[MAX_CMDLEN];
462 char event[64]; 549 char event[64];
463 struct strlist *namelist; 550 struct strlist *namelist;
551 bool allow_suffix;
464 552
465 fd = open_kprobe_events(O_RDWR, O_APPEND); 553 fd = open_kprobe_events(O_RDWR, O_APPEND);
466 /* Get current event names */ 554 /* Get current event names */
467 namelist = get_perf_event_names(fd); 555 namelist = get_perf_event_names(fd, false);
468 556
469 for (j = 0; j < nr_probes; j++) { 557 for (j = 0; j < nr_probes; j++) {
470 pp = probes + j; 558 pp = probes + j;
559 if (!pp->event)
560 pp->event = strdup(pp->function);
561 if (!pp->group)
562 pp->group = strdup(PERFPROBE_GROUP);
563 DIE_IF(!pp->event || !pp->group);
564 /* If force_add is true, suffix search is allowed */
565 allow_suffix = force_add;
471 for (i = 0; i < pp->found; i++) { 566 for (i = 0; i < pp->found; i++) {
472 /* Get an unused new event name */ 567 /* Get an unused new event name */
473 get_new_event_name(event, 64, pp->function, namelist); 568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
474 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
475 pp->retprobe ? 'r' : 'p', 571 pp->retprobe ? 'r' : 'p',
476 PERFPROBE_GROUP, event, 572 pp->group, event,
477 pp->probes[i]); 573 pp->probes[i]);
478 write_trace_kprobe_event(fd, buf); 574 write_trace_kprobe_event(fd, buf);
575 printf("Added new event:\n");
576 /* Get the first parameter (probe-point) */
577 sscanf(pp->probes[i], "%s", buf);
578 show_perf_probe_event(event, buf, pp);
479 /* Add added event name to namelist */ 579 /* Add added event name to namelist */
480 strlist__add(namelist, event); 580 strlist__add(namelist, event);
581 /*
582 * Probes after the first probe which comes from same
583 * user input are always allowed to add suffix, because
584 * there might be several addresses corresponding to
585 * one code line.
586 */
587 allow_suffix = true;
588 }
589 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593
594 strlist__delete(namelist);
595 close(fd);
596}
597
598static void __del_trace_kprobe_event(int fd, struct str_node *ent)
599{
600 char *p;
601 char buf[128];
602
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':');
607 if (!p)
608 die("Internal error: %s should have ':' but not.", ent->s);
609 *p = '/';
610
611 write_trace_kprobe_event(fd, buf);
612 printf("Remove event: %s\n", ent->s);
613}
614
615static void del_trace_kprobe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist)
617{
618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
621
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
623 die("Failed to copy event.");
624
625 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) {
628 found++;
629 __del_trace_kprobe_event(fd, ent);
630 strlist__remove(namelist, ent);
631 }
632 } else {
633 ent = strlist__find(namelist, buf);
634 if (ent) {
635 found++;
636 __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent);
481 } 638 }
482 } 639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
642}
643
644void del_trace_kprobe_events(struct strlist *dellist)
645{
646 int fd;
647 const char *group, *event;
648 char *p, *str;
649 struct str_node *ent;
650 struct strlist *namelist;
651
652 fd = open_kprobe_events(O_RDWR, O_APPEND);
653 /* Get current event names */
654 namelist = get_perf_event_names(fd, true);
655
656 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s);
658 if (!str)
659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':');
662 if (p) {
663 group = str;
664 *p = '\0';
665 event = p + 1;
666 } else {
667 group = "*";
668 event = str;
669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist);
672 free(str);
673 }
674 strlist__delete(namelist);
483 close(fd); 675 close(fd);
484} 676}
677
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 0c6fe56fe38a..7f1d499118c0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,15 +1,19 @@
1#ifndef _PROBE_EVENT_H 1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h>
4#include "probe-finder.h" 5#include "probe-finder.h"
5#include "strlist.h" 6#include "strlist.h"
6 7
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 8extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp); 11extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group, 12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist);
13extern void show_perf_probe_events(void); 17extern void show_perf_probe_events(void);
14 18
15/* Maximum index number of event-name postfix */ 19/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 293cdfc1b8ca..4b852c0d16a5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -106,7 +106,7 @@ static int strtailcmp(const char *s1, const char *s2)
106{ 106{
107 int i1 = strlen(s1); 107 int i1 = strlen(s1);
108 int i2 = strlen(s2); 108 int i2 = strlen(s2);
109 while (--i1 > 0 && --i2 > 0) { 109 while (--i1 >= 0 && --i2 >= 0) {
110 if (s1[i1] != s2[i2]) 110 if (s1[i1] != s2[i2])
111 return s1[i1] - s2[i2]; 111 return s1[i1] - s2[i2];
112 } 112 }
@@ -687,10 +687,8 @@ int find_probepoint(int fd, struct probe_point *pp)
687 struct probe_finder pf = {.pp = pp}; 687 struct probe_finder pf = {.pp = pp};
688 688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK) { 690 if (ret != DW_DLV_OK)
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT; 691 return -ENOENT;
693 }
694 692
695 pp->found = 0; 693 pp->found = 0;
696 while (++cu_number) { 694 while (++cu_number) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bdebca6697d2..a4086aaddb73 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,9 +1,9 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#define MAX_PATH_LEN 256 4#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 5#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 6#define MAX_PROBES 128
7 7
8static inline int is_c_varname(const char *name) 8static inline int is_c_varname(const char *name)
9{ 9{
@@ -12,45 +12,53 @@ static inline int is_c_varname(const char *name)
12} 12}
13 13
14struct probe_point { 14struct probe_point {
15 char *event; /* Event name */
16 char *group; /* Event group */
17
15 /* Inputs */ 18 /* Inputs */
16 char *file; /* File name */ 19 char *file; /* File name */
17 int line; /* Line number */ 20 int line; /* Line number */
18 21
19 char *function; /* Function name */ 22 char *function; /* Function name */
20 int offset; /* Offset bytes */ 23 int offset; /* Offset bytes */
21 24
22 int nr_args; /* Number of arguments */ 25 int nr_args; /* Number of arguments */
23 char **args; /* Arguments */ 26 char **args; /* Arguments */
24 27
25 int retprobe; /* Return probe */ 28 int retprobe; /* Return probe */
26 29
27 /* Output */ 30 /* Output */
28 int found; /* Number of found probe points */ 31 int found; /* Number of found probe points */
29 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
30}; 33};
31 34
32#ifndef NO_LIBDWARF 35#ifndef NO_LIBDWARF
33extern int find_probepoint(int fd, struct probe_point *pp); 36extern int find_probepoint(int fd, struct probe_point *pp);
34 37
35#include <libdwarf/dwarf.h> 38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
36#include <libdwarf/libdwarf.h> 39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42
43#include <dwarf.h>
44#include <libdwarf.h>
37 45
38struct probe_finder { 46struct probe_finder {
39 struct probe_point *pp; /* Target probe point */ 47 struct probe_point *pp; /* Target probe point */
40 48
41 /* For function searching */ 49 /* For function searching */
42 Dwarf_Addr addr; /* Address */ 50 Dwarf_Addr addr; /* Address */
43 Dwarf_Unsigned fno; /* File number */ 51 Dwarf_Unsigned fno; /* File number */
44 Dwarf_Unsigned lno; /* Line number */ 52 Dwarf_Unsigned lno; /* Line number */
45 Dwarf_Off inl_offs; /* Inline offset */ 53 Dwarf_Off inl_offs; /* Inline offset */
46 Dwarf_Die cu_die; /* Current CU */ 54 Dwarf_Die cu_die; /* Current CU */
47 55
48 /* For variable searching */ 56 /* For variable searching */
49 Dwarf_Addr cu_base; /* Current CU base address */ 57 Dwarf_Addr cu_base; /* Current CU base address */
50 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
51 const char *var; /* Current variable name */ 59 const char *var; /* Current variable name */
52 char *buf; /* Current output buffer */ 60 char *buf; /* Current output buffer */
53 int len; /* Length of output buffer */ 61 int len; /* Length of output buffer */
54}; 62};
55#endif /* NO_LIBDWARF */ 63#endif /* NO_LIBDWARF */
56 64
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..ce3a6c8abe76
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,150 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "sort.h"
8#include "util.h"
9
10static int perf_session__open(struct perf_session *self, bool force)
11{
12 struct stat input_stat;
13
14 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename);
17 if (!strcmp(self->filename, "perf.data"))
18 pr_err(" (try 'perf record' first)");
19 pr_err("\n");
20 return -errno;
21 }
22
23 if (fstat(self->fd, &input_stat) < 0)
24 goto out_close;
25
26 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
27 pr_err("file %s not owned by current user or root\n",
28 self->filename);
29 goto out_close;
30 }
31
32 if (!input_stat.st_size) {
33 pr_info("zero-sized file (%s), nothing to do!\n",
34 self->filename);
35 goto out_close;
36 }
37
38 if (perf_header__read(&self->header, self->fd) < 0) {
39 pr_err("incompatible file format");
40 goto out_close;
41 }
42
43 self->size = input_stat.st_size;
44 return 0;
45
46out_close:
47 close(self->fd);
48 self->fd = -1;
49 return -1;
50}
51
52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{
54 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len);
56
57 if (self == NULL)
58 goto out;
59
60 if (perf_header__init(&self->header) < 0)
61 goto out_free;
62
63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
73
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
75 goto out_delete;
76out:
77 return self;
78out_free:
79 free(self);
80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
84}
85
86void perf_session__delete(struct perf_session *self)
87{
88 perf_header__exit(&self->header);
89 close(self->fd);
90 free(self->cwd);
91 free(self);
92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..32eaa1bada06
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
13
14struct perf_session {
15 struct perf_header header;
16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
25 int fd;
26 int cwdlen;
27 char *cwd;
28 char filename[0];
29};
30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self);
50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
61#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b490354d1b23..cb0f327de9e8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -288,3 +288,29 @@ int sort_dimension__add(const char *tok)
288 288
289 return -ESRCH; 289 return -ESRCH;
290} 290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 333e664ff45f..753f9ea99fb0 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,9 +49,13 @@ struct hist_entry {
49 struct symbol *sym; 49 struct symbol *sym;
50 u64 ip; 50 u64 ip;
51 char level; 51 char level;
52 struct symbol *parent; 52 struct symbol *parent;
53 struct callchain_node callchain; 53 struct callchain_node callchain;
54 struct rb_root sorted_chain; 54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
55}; 59};
56 60
57enum sort_type { 61enum sort_type {
@@ -81,6 +85,8 @@ struct sort_entry {
81extern struct sort_entry sort_thread; 85extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list; 86extern struct list_head hist_entry__sort_list;
83 87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...); 90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
@@ -95,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *); 103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
98 106
99#endif /* __PERF_SORT_H */ 107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f24a8cc933d5..5352d7dccc61 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -226,3 +226,28 @@ fail:
226 argv_free(argv); 226 argv_free(argv);
227 return NULL; 227 return NULL;
228} 228}
229
230/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bfecec265a1a..02ede58c54b4 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
@@ -8,6 +9,7 @@ char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 9s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
11 13
12#define _STR(x) #x 14#define _STR(x) #x
13#define STR(x) _STR(x) 15#define STR(x) _STR(x)
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index cb4659306d7b..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* __PERF_STRLIST_H */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index fffcb937cdcb..ab92763edb03 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,7 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
5#include "thread.h" 7#include "thread.h"
@@ -29,33 +31,50 @@ enum dso_origin {
29}; 31};
30 32
31static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *thread__find_map_by_name(struct thread *self, char *name);
33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct thread *thread, symbol_filter_t filter); 36 struct perf_session *session, symbol_filter_t filter);
37unsigned int symbol__priv_size;
38static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
39static char **vmlinux_path; 38static char **vmlinux_path;
40 39
41static struct symbol_conf symbol_conf__defaults = { 40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
42 .use_modules = true, 42 .use_modules = true,
43 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
44}; 44};
45 45
46static struct thread kthread_mem;
47struct thread *kthread = &kthread_mem;
48
49bool dso__loaded(const struct dso *self, enum map_type type) 46bool dso__loaded(const struct dso *self, enum map_type type)
50{ 47{
51 return self->loaded & (1 << type); 48 return self->loaded & (1 << type);
52} 49}
53 50
51bool dso__sorted_by_name(const struct dso *self, enum map_type type)
52{
53 return self->sorted_by_name & (1 << type);
54}
55
54static void dso__set_loaded(struct dso *self, enum map_type type) 56static void dso__set_loaded(struct dso *self, enum map_type type)
55{ 57{
56 self->loaded |= (1 << type); 58 self->loaded |= (1 << type);
57} 59}
58 60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{
63 self->sorted_by_name |= (1 << type);
64}
65
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{
68 switch (map_type) {
69 case MAP__FUNCTION:
70 return symbol_type == 'T' || symbol_type == 'W';
71 case MAP__VARIABLE:
72 return symbol_type == 'D' || symbol_type == 'd';
73 default:
74 return false;
75 }
76}
77
59static void symbols__fixup_end(struct rb_root *self) 78static void symbols__fixup_end(struct rb_root *self)
60{ 79{
61 struct rb_node *nd, *prevnd = rb_first(self); 80 struct rb_node *nd, *prevnd = rb_first(self);
@@ -79,7 +98,7 @@ static void symbols__fixup_end(struct rb_root *self)
79 curr->end = roundup(curr->start, 4096); 98 curr->end = roundup(curr->start, 4096);
80} 99}
81 100
82static void __thread__fixup_maps_end(struct thread *self, enum map_type type) 101static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
83{ 102{
84 struct map *prev, *curr; 103 struct map *prev, *curr;
85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 104 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
@@ -102,23 +121,23 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
102 curr->end = ~0UL; 121 curr->end = ~0UL;
103} 122}
104 123
105static void thread__fixup_maps_end(struct thread *self) 124static void map_groups__fixup_end(struct map_groups *self)
106{ 125{
107 int i; 126 int i;
108 for (i = 0; i < MAP__NR_TYPES; ++i) 127 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i); 128 __map_groups__fixup_end(self, i);
110} 129}
111 130
112static struct symbol *symbol__new(u64 start, u64 len, const char *name) 131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
113{ 132{
114 size_t namelen = strlen(name) + 1; 133 size_t namelen = strlen(name) + 1;
115 struct symbol *self = zalloc(symbol__priv_size + 134 struct symbol *self = zalloc(symbol_conf.priv_size +
116 sizeof(*self) + namelen); 135 sizeof(*self) + namelen);
117 if (self == NULL) 136 if (self == NULL)
118 return NULL; 137 return NULL;
119 138
120 if (symbol__priv_size) 139 if (symbol_conf.priv_size)
121 self = ((void *)self) + symbol__priv_size; 140 self = ((void *)self) + symbol_conf.priv_size;
122 141
123 self->start = start; 142 self->start = start;
124 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
@@ -132,7 +151,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
132 151
133static void symbol__delete(struct symbol *self) 152static void symbol__delete(struct symbol *self)
134{ 153{
135 free(((void *)self) - symbol__priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
136} 155}
137 156
138static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -164,11 +183,11 @@ struct dso *dso__new(const char *name)
164 dso__set_long_name(self, self->name); 183 dso__set_long_name(self, self->name);
165 self->short_name = self->name; 184 self->short_name = self->name;
166 for (i = 0; i < MAP__NR_TYPES; ++i) 185 for (i = 0; i < MAP__NR_TYPES; ++i)
167 self->symbols[i] = RB_ROOT; 186 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
168 self->find_symbol = dso__find_symbol;
169 self->slen_calculated = 0; 187 self->slen_calculated = 0;
170 self->origin = DSO__ORIG_NOT_FOUND; 188 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0; 189 self->loaded = 0;
190 self->sorted_by_name = 0;
172 self->has_build_id = 0; 191 self->has_build_id = 0;
173 } 192 }
174 193
@@ -246,11 +265,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
246 return NULL; 265 return NULL;
247} 266}
248 267
249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 268struct symbol_name_rb_node {
269 struct rb_node rb_node;
270 struct symbol sym;
271};
272
273static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
274{
275 struct rb_node **p = &self->rb_node;
276 struct rb_node *parent = NULL;
277 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
278
279 while (*p != NULL) {
280 parent = *p;
281 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
282 if (strcmp(sym->name, s->sym.name) < 0)
283 p = &(*p)->rb_left;
284 else
285 p = &(*p)->rb_right;
286 }
287 rb_link_node(&symn->rb_node, parent, p);
288 rb_insert_color(&symn->rb_node, self);
289}
290
291static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
292{
293 struct rb_node *nd;
294
295 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
296 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
297 symbols__insert_by_name(self, pos);
298 }
299}
300
301static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
302{
303 struct rb_node *n;
304
305 if (self == NULL)
306 return NULL;
307
308 n = self->rb_node;
309
310 while (n) {
311 struct symbol_name_rb_node *s;
312 int cmp;
313
314 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
315 cmp = strcmp(name, s->sym.name);
316
317 if (cmp < 0)
318 n = n->rb_left;
319 else if (cmp > 0)
320 n = n->rb_right;
321 else
322 return &s->sym;
323 }
324
325 return NULL;
326}
327
328struct symbol *dso__find_symbol(struct dso *self,
329 enum map_type type, u64 addr)
250{ 330{
251 return symbols__find(&self->symbols[type], addr); 331 return symbols__find(&self->symbols[type], addr);
252} 332}
253 333
334struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
335 const char *name)
336{
337 return symbols__find_by_name(&self->symbol_names[type], name);
338}
339
340void dso__sort_by_name(struct dso *self, enum map_type type)
341{
342 dso__set_sorted_by_name(self, type);
343 return symbols__sort_by_name(&self->symbol_names[type],
344 &self->symbols[type]);
345}
346
254int build_id__sprintf(u8 *self, int len, char *bf) 347int build_id__sprintf(u8 *self, int len, char *bf)
255{ 348{
256 char *bid = bf; 349 char *bid = bf;
@@ -327,10 +420,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
327 continue; 420 continue;
328 421
329 symbol_type = toupper(line[len]); 422 symbol_type = toupper(line[len]);
330 /* 423 if (!symbol_type__is_a(symbol_type, map->type))
331 * We're interested only in code ('T'ext)
332 */
333 if (symbol_type != 'T' && symbol_type != 'W')
334 continue; 424 continue;
335 425
336 symbol_name = line + len + 2; 426 symbol_name = line + len + 2;
@@ -364,8 +454,8 @@ out_failure:
364 * kernel range is broken in several maps, named [kernel].N, as we don't have 454 * kernel range is broken in several maps, named [kernel].N, as we don't have
365 * the original ELF section names vmlinux have. 455 * the original ELF section names vmlinux have.
366 */ 456 */
367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, 457static int dso__split_kallsyms(struct dso *self, struct map *map,
368 symbol_filter_t filter) 458 struct perf_session *session, symbol_filter_t filter)
369{ 459{
370 struct map *curr_map = map; 460 struct map *curr_map = map;
371 struct symbol *pos; 461 struct symbol *pos;
@@ -382,13 +472,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
382 472
383 module = strchr(pos->name, '\t'); 473 module = strchr(pos->name, '\t');
384 if (module) { 474 if (module) {
385 if (!thread->use_modules) 475 if (!symbol_conf.use_modules)
386 goto discard_symbol; 476 goto discard_symbol;
387 477
388 *module++ = '\0'; 478 *module++ = '\0';
389 479
390 if (strcmp(self->name, module)) { 480 if (strcmp(self->name, module)) {
391 curr_map = thread__find_map_by_name(thread, module); 481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
392 if (curr_map == NULL) { 482 if (curr_map == NULL) {
393 pr_debug("/proc/{kallsyms,modules} " 483 pr_debug("/proc/{kallsyms,modules} "
394 "inconsistency!\n"); 484 "inconsistency!\n");
@@ -419,7 +509,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
419 } 509 }
420 510
421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422 __thread__insert_map(thread, curr_map); 512 map_groups__insert(&session->kmaps, curr_map);
423 ++kernel_range; 513 ++kernel_range;
424 } 514 }
425 515
@@ -440,7 +530,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
440 530
441 531
442static int dso__load_kallsyms(struct dso *self, struct map *map, 532static int dso__load_kallsyms(struct dso *self, struct map *map,
443 struct thread *thread, symbol_filter_t filter) 533 struct perf_session *session, symbol_filter_t filter)
444{ 534{
445 if (dso__load_all_kallsyms(self, map) < 0) 535 if (dso__load_all_kallsyms(self, map) < 0)
446 return -1; 536 return -1;
@@ -448,14 +538,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
448 symbols__fixup_end(&self->symbols[map->type]); 538 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL; 539 self->origin = DSO__ORIG_KERNEL;
450 540
451 return dso__split_kallsyms(self, map, thread, filter); 541 return dso__split_kallsyms(self, map, session, filter);
452}
453
454size_t kernel_maps__fprintf(FILE *fp)
455{
456 size_t printed = fprintf(fp, "Kernel maps:\n");
457 printed += thread__fprintf_maps(kthread, fp);
458 return printed + fprintf(fp, "END kernel maps\n");
459} 542}
460 543
461static int dso__load_perf_map(struct dso *self, struct map *map, 544static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -544,6 +627,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
544 sym->st_shndx != SHN_UNDEF; 627 sym->st_shndx != SHN_UNDEF;
545} 628}
546 629
630static inline bool elf_sym__is_object(const GElf_Sym *sym)
631{
632 return elf_sym__type(sym) == STT_OBJECT &&
633 sym->st_name != 0 &&
634 sym->st_shndx != SHN_UNDEF;
635}
636
547static inline int elf_sym__is_label(const GElf_Sym *sym) 637static inline int elf_sym__is_label(const GElf_Sym *sym)
548{ 638{
549 return elf_sym__type(sym) == STT_NOTYPE && 639 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -564,6 +654,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
564 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 654 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
565} 655}
566 656
657static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
658 const Elf_Data *secstrs)
659{
660 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
661}
662
567static inline const char *elf_sym__name(const GElf_Sym *sym, 663static inline const char *elf_sym__name(const GElf_Sym *sym,
568 const Elf_Data *symstrs) 664 const Elf_Data *symstrs)
569{ 665{
@@ -744,8 +840,32 @@ out:
744 return 0; 840 return 0;
745} 841}
746 842
843static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
844{
845 switch (type) {
846 case MAP__FUNCTION:
847 return elf_sym__is_function(self);
848 case MAP__VARIABLE:
849 return elf_sym__is_object(self);
850 default:
851 return false;
852 }
853}
854
855static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
856{
857 switch (type) {
858 case MAP__FUNCTION:
859 return elf_sec__is_text(self, secstrs);
860 case MAP__VARIABLE:
861 return elf_sec__is_data(self, secstrs);
862 default:
863 return false;
864 }
865}
866
747static int dso__load_sym(struct dso *self, struct map *map, 867static int dso__load_sym(struct dso *self, struct map *map,
748 struct thread *thread, const char *name, int fd, 868 struct perf_session *session, const char *name, int fd,
749 symbol_filter_t filter, int kernel, int kmodule) 869 symbol_filter_t filter, int kernel, int kmodule)
750{ 870{
751 struct map *curr_map = map; 871 struct map *curr_map = map;
@@ -818,7 +938,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
818 int is_label = elf_sym__is_label(&sym); 938 int is_label = elf_sym__is_label(&sym);
819 const char *section_name; 939 const char *section_name;
820 940
821 if (!is_label && !elf_sym__is_function(&sym)) 941 if (!is_label && !elf_sym__is_a(&sym, map->type))
822 continue; 942 continue;
823 943
824 sec = elf_getscn(elf, sym.st_shndx); 944 sec = elf_getscn(elf, sym.st_shndx);
@@ -827,7 +947,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
827 947
828 gelf_getshdr(sec, &shdr); 948 gelf_getshdr(sec, &shdr);
829 949
830 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
831 continue; 951 continue;
832 952
833 elf_name = elf_sym__name(&sym, symstrs); 953 elf_name = elf_sym__name(&sym, symstrs);
@@ -849,7 +969,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
849 snprintf(dso_name, sizeof(dso_name), 969 snprintf(dso_name, sizeof(dso_name),
850 "%s%s", self->short_name, section_name); 970 "%s%s", self->short_name, section_name);
851 971
852 curr_map = thread__find_map_by_name(thread, dso_name); 972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
853 if (curr_map == NULL) { 973 if (curr_map == NULL) {
854 u64 start = sym.st_value; 974 u64 start = sym.st_value;
855 975
@@ -868,7 +988,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
868 curr_map->map_ip = identity__map_ip; 988 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip; 989 curr_map->unmap_ip = identity__map_ip;
870 curr_dso->origin = DSO__ORIG_KERNEL; 990 curr_dso->origin = DSO__ORIG_KERNEL;
871 __thread__insert_map(kthread, curr_map); 991 map_groups__insert(&session->kmaps, curr_map);
872 dsos__add(&dsos__kernel, curr_dso); 992 dsos__add(&dsos__kernel, curr_dso);
873 } else 993 } else
874 curr_dso = curr_map->dso; 994 curr_dso = curr_map->dso;
@@ -938,8 +1058,9 @@ static bool __dsos__read_build_ids(struct list_head *head)
938 1058
939bool dsos__read_build_ids(void) 1059bool dsos__read_build_ids(void)
940{ 1060{
941 return __dsos__read_build_ids(&dsos__kernel) || 1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
942 __dsos__read_build_ids(&dsos__user); 1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
943} 1064}
944 1065
945/* 1066/*
@@ -1082,7 +1203,8 @@ char dso__symtab_origin(const struct dso *self)
1082 return origin[self->origin]; 1203 return origin[self->origin];
1083} 1204}
1084 1205
1085int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
1086{ 1208{
1087 int size = PATH_MAX; 1209 int size = PATH_MAX;
1088 char *name; 1210 char *name;
@@ -1093,7 +1215,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1093 dso__set_loaded(self, map->type); 1215 dso__set_loaded(self, map->type);
1094 1216
1095 if (self->kernel) 1217 if (self->kernel)
1096 return dso__load_kernel_sym(self, map, kthread, filter); 1218 return dso__load_kernel_sym(self, map, session, filter);
1097 1219
1098 name = malloc(size); 1220 name = malloc(size);
1099 if (!name) 1221 if (!name)
@@ -1179,11 +1301,12 @@ out:
1179 return ret; 1301 return ret;
1180} 1302}
1181 1303
1182static struct map *thread__find_map_by_name(struct thread *self, char *name) 1304struct map *map_groups__find_by_name(struct map_groups *self,
1305 enum map_type type, const char *name)
1183{ 1306{
1184 struct rb_node *nd; 1307 struct rb_node *nd;
1185 1308
1186 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1187 struct map *map = rb_entry(nd, struct map, rb_node); 1310 struct map *map = rb_entry(nd, struct map, rb_node);
1188 1311
1189 if (map->dso && strcmp(map->dso->name, name) == 0) 1312 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1193,7 +1316,7 @@ static struct map *thread__find_map_by_name(struct thread *self, char *name)
1193 return NULL; 1316 return NULL;
1194} 1317}
1195 1318
1196static int dsos__set_modules_path_dir(char *dirname) 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1197{ 1320{
1198 struct dirent *dent; 1321 struct dirent *dent;
1199 DIR *dir = opendir(dirname); 1322 DIR *dir = opendir(dirname);
@@ -1213,7 +1336,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1213 1336
1214 snprintf(path, sizeof(path), "%s/%s", 1337 snprintf(path, sizeof(path), "%s/%s",
1215 dirname, dent->d_name); 1338 dirname, dent->d_name);
1216 if (dsos__set_modules_path_dir(path) < 0) 1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1217 goto failure; 1340 goto failure;
1218 } else { 1341 } else {
1219 char *dot = strrchr(dent->d_name, '.'), 1342 char *dot = strrchr(dent->d_name, '.'),
@@ -1227,7 +1350,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1227 (int)(dot - dent->d_name), dent->d_name); 1350 (int)(dot - dent->d_name), dent->d_name);
1228 1351
1229 strxfrchar(dso_name, '-', '_'); 1352 strxfrchar(dso_name, '-', '_');
1230 map = thread__find_map_by_name(kthread, dso_name); 1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1231 if (map == NULL) 1354 if (map == NULL)
1232 continue; 1355 continue;
1233 1356
@@ -1247,7 +1370,7 @@ failure:
1247 return -1; 1370 return -1;
1248} 1371}
1249 1372
1250static int dsos__set_modules_path(void) 1373static int perf_session__set_modules_path(struct perf_session *self)
1251{ 1374{
1252 struct utsname uts; 1375 struct utsname uts;
1253 char modules_path[PATH_MAX]; 1376 char modules_path[PATH_MAX];
@@ -1258,7 +1381,7 @@ static int dsos__set_modules_path(void)
1258 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1259 uts.release); 1382 uts.release);
1260 1383
1261 return dsos__set_modules_path_dir(modules_path); 1384 return perf_session__set_modules_path_dir(self, modules_path);
1262} 1385}
1263 1386
1264/* 1387/*
@@ -1280,7 +1403,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1280 return self; 1403 return self;
1281} 1404}
1282 1405
1283static int thread__create_module_maps(struct thread *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
1284{ 1407{
1285 char *line = NULL; 1408 char *line = NULL;
1286 size_t n; 1409 size_t n;
@@ -1337,14 +1460,14 @@ static int thread__create_module_maps(struct thread *self)
1337 dso->has_build_id = true; 1460 dso->has_build_id = true;
1338 1461
1339 dso->origin = DSO__ORIG_KMODULE; 1462 dso->origin = DSO__ORIG_KMODULE;
1340 __thread__insert_map(self, map); 1463 map_groups__insert(&self->kmaps, map);
1341 dsos__add(&dsos__kernel, dso); 1464 dsos__add(&dsos__kernel, dso);
1342 } 1465 }
1343 1466
1344 free(line); 1467 free(line);
1345 fclose(file); 1468 fclose(file);
1346 1469
1347 return dsos__set_modules_path(); 1470 return perf_session__set_modules_path(self);
1348 1471
1349out_delete_line: 1472out_delete_line:
1350 free(line); 1473 free(line);
@@ -1352,7 +1475,8 @@ out_failure:
1352 return -1; 1475 return -1;
1353} 1476}
1354 1477
1355static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1356 const char *vmlinux, symbol_filter_t filter) 1480 const char *vmlinux, symbol_filter_t filter)
1357{ 1481{
1358 int err = -1, fd; 1482 int err = -1, fd;
@@ -1386,14 +1510,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t
1386 return -1; 1510 return -1;
1387 1511
1388 dso__set_loaded(self, map->type); 1512 dso__set_loaded(self, map->type);
1389 err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); 1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
1390 close(fd); 1514 close(fd);
1391 1515
1392 return err; 1516 return err;
1393} 1517}
1394 1518
1395static int dso__load_kernel_sym(struct dso *self, struct map *map, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
1396 struct thread *thread, symbol_filter_t filter) 1520 struct perf_session *session, symbol_filter_t filter)
1397{ 1521{
1398 int err; 1522 int err;
1399 bool is_kallsyms; 1523 bool is_kallsyms;
@@ -1403,7 +1527,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1403 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1404 vmlinux_path__nr_entries); 1528 vmlinux_path__nr_entries);
1405 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1406 err = dso__load_vmlinux(self, map, thread, 1530 err = dso__load_vmlinux(self, map, session,
1407 vmlinux_path[i], filter); 1531 vmlinux_path[i], filter);
1408 if (err > 0) { 1532 if (err > 0) {
1409 pr_debug("Using %s for symbols\n", 1533 pr_debug("Using %s for symbols\n",
@@ -1419,12 +1543,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1419 if (is_kallsyms) 1543 if (is_kallsyms)
1420 goto do_kallsyms; 1544 goto do_kallsyms;
1421 1545
1422 err = dso__load_vmlinux(self, map, thread, self->long_name, filter); 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1423 if (err <= 0) { 1547 if (err <= 0) {
1424 pr_info("The file %s cannot be used, " 1548 pr_info("The file %s cannot be used, "
1425 "trying to use /proc/kallsyms...", self->long_name); 1549 "trying to use /proc/kallsyms...", self->long_name);
1426do_kallsyms: 1550do_kallsyms:
1427 err = dso__load_kallsyms(self, map, thread, filter); 1551 err = dso__load_kallsyms(self, map, session, filter);
1428 if (err > 0 && !is_kallsyms) 1552 if (err > 0 && !is_kallsyms)
1429 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1430 } 1554 }
@@ -1507,42 +1631,59 @@ size_t dsos__fprintf_buildid(FILE *fp)
1507 __dsos__fprintf_buildid(&dsos__user, fp)); 1631 __dsos__fprintf_buildid(&dsos__user, fp));
1508} 1632}
1509 1633
1510static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1634static struct dso *dsos__create_kernel( const char *vmlinux)
1511{ 1635{
1512 struct map *kmap;
1513 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1514 1637
1515 if (kernel == NULL) 1638 if (kernel == NULL)
1516 return -1; 1639 return NULL;
1517
1518 kmap = map__new2(0, kernel, MAP__FUNCTION);
1519 if (kmap == NULL)
1520 goto out_delete_kernel_dso;
1521 1640
1522 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1523 kernel->short_name = "[kernel]"; 1641 kernel->short_name = "[kernel]";
1524 kernel->kernel = 1; 1642 kernel->kernel = 1;
1525 1643
1526 vdso = dso__new("[vdso]"); 1644 vdso = dso__new("[vdso]");
1527 if (vdso == NULL) 1645 if (vdso == NULL)
1528 goto out_delete_kernel_map; 1646 goto out_delete_kernel_dso;
1529 dso__set_loaded(vdso, MAP__FUNCTION); 1647 dso__set_loaded(vdso, MAP__FUNCTION);
1530 1648
1531 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1532 sizeof(kernel->build_id)) == 0) 1650 sizeof(kernel->build_id)) == 0)
1533 kernel->has_build_id = true; 1651 kernel->has_build_id = true;
1534 1652
1535 __thread__insert_map(self, kmap);
1536 dsos__add(&dsos__kernel, kernel); 1653 dsos__add(&dsos__kernel, kernel);
1537 dsos__add(&dsos__user, vdso); 1654 dsos__add(&dsos__user, vdso);
1538 1655
1539 return 0; 1656 return kernel;
1540 1657
1541out_delete_kernel_map:
1542 map__delete(kmap);
1543out_delete_kernel_dso: 1658out_delete_kernel_dso:
1544 dso__delete(kernel); 1659 dso__delete(kernel);
1545 return -1; 1660 return NULL;
1661}
1662
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1664{
1665 struct map *functions, *variables;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667
1668 if (kernel == NULL)
1669 return -1;
1670
1671 functions = map__new2(0, kernel, MAP__FUNCTION);
1672 if (functions == NULL)
1673 return -1;
1674
1675 variables = map__new2(0, kernel, MAP__VARIABLE);
1676 if (variables == NULL) {
1677 map__delete(functions);
1678 return -1;
1679 }
1680
1681 functions->map_ip = functions->unmap_ip =
1682 variables->map_ip = variables->unmap_ip = identity__map_ip;
1683 map_groups__insert(self, functions);
1684 map_groups__insert(self, variables);
1685
1686 return 0;
1546} 1687}
1547 1688
1548static void vmlinux_path__exit(void) 1689static void vmlinux_path__exit(void)
@@ -1600,29 +1741,69 @@ out_fail:
1600 return -1; 1741 return -1;
1601} 1742}
1602 1743
1603int symbol__init(struct symbol_conf *conf) 1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1604{ 1746{
1605 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1747 if (list_str == NULL)
1748 return 0;
1606 1749
1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1757
1758int symbol__init(void)
1759{
1607 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1608 symbol__priv_size = pconf->priv_size; 1761 if (symbol_conf.sort_by_name)
1609 thread__init(kthread, 0); 1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1763 sizeof(struct symbol));
1610 1764
1611 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1612 return -1; 1766 return -1;
1613 1767
1614 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { 1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1615 vmlinux_path__exit(); 1769 pr_err("'.' is the only non valid --field-separator argument\n");
1616 return -1; 1770 return -1;
1617 } 1771 }
1618 1772
1619 kthread->use_modules = pconf->use_modules; 1773 if (setup_list(&symbol_conf.dso_list,
1620 if (pconf->use_modules && thread__create_module_maps(kthread) < 0) 1774 symbol_conf.dso_list_str, "dso") < 0)
1621 pr_debug("Failed to load list of modules in use, " 1775 return -1;
1622 "continuing...\n"); 1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1623 /* 1804 /*
1624 * Now that we have all the maps created, just set the ->end of them: 1805 * Now that we have all the maps created, just set the ->end of them:
1625 */ 1806 */
1626 thread__fixup_maps_end(kthread); 1807 map_groups__fixup_end(&self->kmaps);
1627 return 0; 1808 return 0;
1628} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 17003efa0b39..8aded2356f79 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,18 +49,32 @@ struct symbol {
49 char name[0]; 49 char name[0];
50}; 50};
51 51
52struct strlist;
53
52struct symbol_conf { 54struct symbol_conf {
53 unsigned short priv_size; 55 unsigned short priv_size;
54 bool try_vmlinux_path, 56 bool try_vmlinux_path,
55 use_modules; 57 use_modules,
56 const char *vmlinux_name; 58 sort_by_name,
59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
57}; 71};
58 72
59extern unsigned int symbol__priv_size; 73extern struct symbol_conf symbol_conf;
60 74
61static inline void *symbol__priv(struct symbol *self) 75static inline void *symbol__priv(struct symbol *self)
62{ 76{
63 return ((void *)self) - symbol__priv_size; 77 return ((void *)self) - symbol_conf.priv_size;
64} 78}
65 79
66struct addr_location { 80struct addr_location {
@@ -69,18 +83,19 @@ struct addr_location {
69 struct symbol *sym; 83 struct symbol *sym;
70 u64 addr; 84 u64 addr;
71 char level; 85 char level;
86 bool filtered;
72}; 87};
73 88
74struct dso { 89struct dso {
75 struct list_head node; 90 struct list_head node;
76 struct rb_root symbols[MAP__NR_TYPES]; 91 struct rb_root symbols[MAP__NR_TYPES];
77 struct symbol *(*find_symbol)(struct dso *self, 92 struct rb_root symbol_names[MAP__NR_TYPES];
78 enum map_type type, u64 addr);
79 u8 adjust_symbols:1; 93 u8 adjust_symbols:1;
80 u8 slen_calculated:1; 94 u8 slen_calculated:1;
81 u8 has_build_id:1; 95 u8 has_build_id:1;
82 u8 kernel:1; 96 u8 kernel:1;
83 unsigned char origin; 97 unsigned char origin;
98 u8 sorted_by_name;
84 u8 loaded; 99 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE]; 100 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len; 101 u16 long_name_len;
@@ -93,9 +108,15 @@ struct dso *dso__new(const char *name);
93void dso__delete(struct dso *self); 108void dso__delete(struct dso *self);
94 109
95bool dso__loaded(const struct dso *self, enum map_type type); 110bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112
113void dso__sort_by_name(struct dso *self, enum map_type type);
114
115struct perf_session;
96 116
97struct dso *dsos__findnew(const char *name); 117struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
99void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
100size_t dsos__fprintf_buildid(FILE *fp); 121size_t dsos__fprintf_buildid(FILE *fp);
101 122
@@ -103,18 +124,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
104char dso__symtab_origin(const struct dso *self); 125char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id); 126void dso__set_build_id(struct dso *self, void *build_id);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name);
106 130
107int filename__read_build_id(const char *filename, void *bf, size_t size); 131int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size); 132int sysfs__read_build_id(const char *filename, void *bf, size_t size);
109bool dsos__read_build_ids(void); 133bool dsos__read_build_ids(void);
110int build_id__sprintf(u8 *self, int len, char *bf); 134int build_id__sprintf(u8 *self, int len, char *bf);
111 135
112size_t kernel_maps__fprintf(FILE *fp); 136int symbol__init(void);
113 137int perf_session__create_kernel_maps(struct perf_session *self);
114int symbol__init(struct symbol_conf *conf);
115 138
116struct thread;
117struct thread *kthread;
118extern struct list_head dsos__user, dsos__kernel; 139extern struct list_head dsos__user, dsos__kernel;
119extern struct dso *vdso; 140extern struct dso *vdso;
120#endif /* __PERF_SYMBOL */ 141#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 603f5610861b..4a08dcf50b68 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,18 +2,14 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
9static struct rb_root threads; 10void map_groups__init(struct map_groups *self)
10static struct thread *last_match;
11
12void thread__init(struct thread *self, pid_t pid)
13{ 11{
14 int i; 12 int i;
15 self->pid = pid;
16 self->comm = NULL;
17 for (i = 0; i < MAP__NR_TYPES; ++i) { 13 for (i = 0; i < MAP__NR_TYPES; ++i) {
18 self->maps[i] = RB_ROOT; 14 self->maps[i] = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps[i]); 15 INIT_LIST_HEAD(&self->removed_maps[i]);
@@ -25,7 +21,8 @@ static struct thread *thread__new(pid_t pid)
25 struct thread *self = zalloc(sizeof(*self)); 21 struct thread *self = zalloc(sizeof(*self));
26 22
27 if (self != NULL) { 23 if (self != NULL) {
28 thread__init(self, pid); 24 map_groups__init(&self->mg);
25 self->pid = pid;
29 self->comm = malloc(32); 26 self->comm = malloc(32);
30 if (self->comm) 27 if (self->comm)
31 snprintf(self->comm, 32, ":%d", self->pid); 28 snprintf(self->comm, 32, ":%d", self->pid);
@@ -55,10 +52,11 @@ int thread__comm_len(struct thread *self)
55 52
56static const char *map_type__name[MAP__NR_TYPES] = { 53static const char *map_type__name[MAP__NR_TYPES] = {
57 [MAP__FUNCTION] = "Functions", 54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
58}; 56};
59 57
60static size_t __thread__fprintf_maps(struct thread *self, 58static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp) 59 enum map_type type, FILE *fp)
62{ 60{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64 struct rb_node *nd; 62 struct rb_node *nd;
@@ -76,16 +74,16 @@ static size_t __thread__fprintf_maps(struct thread *self,
76 return printed; 74 return printed;
77} 75}
78 76
79size_t thread__fprintf_maps(struct thread *self, FILE *fp) 77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80{ 78{
81 size_t printed = 0, i; 79 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i) 80 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __thread__fprintf_maps(self, i, fp); 81 printed += __map_groups__fprintf_maps(self, i, fp);
84 return printed; 82 return printed;
85} 83}
86 84
87static size_t __thread__fprintf_removed_maps(struct thread *self, 85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
88 enum map_type type, FILE *fp) 86 enum map_type type, FILE *fp)
89{ 87{
90 struct map *pos; 88 struct map *pos;
91 size_t printed = 0; 89 size_t printed = 0;
@@ -101,25 +99,30 @@ static size_t __thread__fprintf_removed_maps(struct thread *self,
101 return printed; 99 return printed;
102} 100}
103 101
104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) 102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
105{ 103{
106 size_t printed = 0, i; 104 size_t printed = 0, i;
107 for (i = 0; i < MAP__NR_TYPES; ++i) 105 for (i = 0; i < MAP__NR_TYPES; ++i)
108 printed += __thread__fprintf_removed_maps(self, i, fp); 106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
109 return printed; 107 return printed;
110} 108}
111 109
112static size_t thread__fprintf(struct thread *self, FILE *fp) 110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113{ 111{
114 size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 112 size_t printed = map_groups__fprintf_maps(self, fp);
115 printed += thread__fprintf_removed_maps(self, fp);
116 printed += fprintf(fp, "Removed maps:\n"); 113 printed += fprintf(fp, "Removed maps:\n");
117 return printed + thread__fprintf_removed_maps(self, fp); 114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp)
118{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp);
118} 121}
119 122
120struct thread *threads__findnew(pid_t pid) 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
121{ 124{
122 struct rb_node **p = &threads.rb_node; 125 struct rb_node **p = &self->threads.rb_node;
123 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
124 struct thread *th; 127 struct thread *th;
125 128
@@ -128,15 +131,15 @@ struct thread *threads__findnew(pid_t pid)
128 * so most of the time we dont have to look up 131 * so most of the time we dont have to look up
129 * the full rbtree: 132 * the full rbtree:
130 */ 133 */
131 if (last_match && last_match->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
132 return last_match; 135 return self->last_match;
133 136
134 while (*p != NULL) { 137 while (*p != NULL) {
135 parent = *p; 138 parent = *p;
136 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
137 140
138 if (th->pid == pid) { 141 if (th->pid == pid) {
139 last_match = th; 142 self->last_match = th;
140 return th; 143 return th;
141 } 144 }
142 145
@@ -149,26 +152,15 @@ struct thread *threads__findnew(pid_t pid)
149 th = thread__new(pid); 152 th = thread__new(pid);
150 if (th != NULL) { 153 if (th != NULL) {
151 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
152 rb_insert_color(&th->rb_node, &threads); 155 rb_insert_color(&th->rb_node, &self->threads);
153 last_match = th; 156 self->last_match = th;
154 } 157 }
155 158
156 return th; 159 return th;
157} 160}
158 161
159struct thread *register_idle_thread(void) 162static void map_groups__remove_overlappings(struct map_groups *self,
160{ 163 struct map *map)
161 struct thread *thread = threads__findnew(0);
162
163 if (!thread || thread__set_comm(thread, "swapper")) {
164 fprintf(stderr, "problem inserting idle task.\n");
165 exit(-1);
166 }
167
168 return thread;
169}
170
171static void thread__remove_overlappings(struct thread *self, struct map *map)
172{ 164{
173 struct rb_root *root = &self->maps[map->type]; 165 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root); 166 struct rb_node *next = rb_first(root);
@@ -238,12 +230,15 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
238 230
239void thread__insert_map(struct thread *self, struct map *map) 231void thread__insert_map(struct thread *self, struct map *map)
240{ 232{
241 thread__remove_overlappings(self, map); 233 map_groups__remove_overlappings(&self->mg, map);
242 maps__insert(&self->maps[map->type], map); 234 map_groups__insert(&self->mg, map);
243} 235}
244 236
245static int thread__clone_maps(struct thread *self, struct thread *parent, 237/*
246 enum map_type type) 238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
247{ 242{
248 struct rb_node *nd; 243 struct rb_node *nd;
249 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
@@ -251,7 +246,7 @@ static int thread__clone_maps(struct thread *self, struct thread *parent,
251 struct map *new = map__clone(map); 246 struct map *new = map__clone(map);
252 if (new == NULL) 247 if (new == NULL)
253 return -ENOMEM; 248 return -ENOMEM;
254 thread__insert_map(self, new); 249 map_groups__insert(self, new);
255 } 250 }
256 return 0; 251 return 0;
257} 252}
@@ -267,17 +262,17 @@ int thread__fork(struct thread *self, struct thread *parent)
267 return -ENOMEM; 262 return -ENOMEM;
268 263
269 for (i = 0; i < MAP__NR_TYPES; ++i) 264 for (i = 0; i < MAP__NR_TYPES; ++i)
270 if (thread__clone_maps(self, parent, i) < 0) 265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
271 return -ENOMEM; 266 return -ENOMEM;
272 return 0; 267 return 0;
273} 268}
274 269
275size_t threads__fprintf(FILE *fp) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
276{ 271{
277 size_t ret = 0; 272 size_t ret = 0;
278 struct rb_node *nd; 273 struct rb_node *nd;
279 274
280 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
281 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
282 277
283 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -286,14 +281,15 @@ size_t threads__fprintf(FILE *fp)
286 return ret; 281 return ret;
287} 282}
288 283
289struct symbol *thread__find_symbol(struct thread *self, 284struct symbol *map_groups__find_symbol(struct map_groups *self,
290 enum map_type type, u64 addr, 285 struct perf_session *session,
291 symbol_filter_t filter) 286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
292{ 288{
293 struct map *map = thread__find_map(self, type, addr); 289 struct map *map = map_groups__find(self, type, addr);
294 290
295 if (map != NULL) 291 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter); 292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
297 293
298 return NULL; 294 return NULL;
299} 295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 686d6e914d9e..c206f72c8881 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,52 +5,66 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct thread { 8struct map_groups {
9 struct rb_node rb_node;
10 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
13struct thread {
14 struct rb_node rb_node;
15 struct map_groups mg;
12 pid_t pid; 16 pid_t pid;
13 bool use_modules;
14 char shortname[3]; 17 char shortname[3];
15 char *comm; 18 char *comm;
16 int comm_len; 19 int comm_len;
17}; 20};
18 21
19void thread__init(struct thread *self, pid_t pid); 22void map_groups__init(struct map_groups *self);
20int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
21int thread__comm_len(struct thread *self); 24int thread__comm_len(struct thread *self);
22struct thread *threads__findnew(pid_t pid); 25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
23struct thread *register_idle_thread(void);
24void thread__insert_map(struct thread *self, struct map *map); 26void thread__insert_map(struct thread *self, struct map *map);
25int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
26size_t thread__fprintf_maps(struct thread *self, FILE *fp); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
27size_t threads__fprintf(FILE *fp); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
28 30
29void maps__insert(struct rb_root *maps, struct map *map); 31void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 addr); 32struct map *maps__find(struct rb_root *maps, u64 addr);
31 33
32static inline struct map *thread__find_map(struct thread *self, 34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
33 enum map_type type, u64 addr) 40 enum map_type type, u64 addr)
34{ 41{
35 return self ? maps__find(&self->maps[type], addr) : NULL; 42 return maps__find(&self->maps[type], addr);
36} 43}
37 44
38static inline void __thread__insert_map(struct thread *self, struct map *map) 45static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr)
39{ 47{
40 maps__insert(&self->maps[map->type], map); 48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
41} 49}
42 50
43void thread__find_addr_location(struct thread *self, u8 cpumode, 51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
44 enum map_type type, u64 addr, 53 enum map_type type, u64 addr,
45 struct addr_location *al, 54 struct addr_location *al,
46 symbol_filter_t filter); 55 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self, 56struct symbol *map_groups__find_symbol(struct map_groups *self,
48 enum map_type type, u64 addr, 57 struct perf_session *session,
49 symbol_filter_t filter); 58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
50 60
51static inline struct symbol * 61static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) 62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
53{ 64{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
55} 66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
56#endif /* __PERF_THREAD_H */ 70#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 0302405aa2ca..c5c32be040bf 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -177,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
177 func_count++; 177 func_count++;
178 } 178 }
179 179
180 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181 181
182 i = 0; 182 i = 0;
183 while (list) { 183 while (list) {
@@ -1477,7 +1477,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1477 goto out_free; 1477 goto out_free;
1478 1478
1479 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1480 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1481 1481
1482 value = arg_eval(arg); 1482 value = arg_eval(arg);
1483 field->value = strdup(value); 1483 field->value = strdup(value);
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index 51e833fd58c3..6d6d76b8a21e 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -32,9 +32,6 @@
32 32
33void xs_init(pTHX); 33void xs_init(pTHX);
34 34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37
38void xs_init(pTHX) 35void xs_init(pTHX)
39{ 36{
40 const char *file = __FILE__; 37 const char *file = __FILE__;
@@ -270,7 +267,7 @@ int common_lock_depth(struct scripting_context *context)
270} 267}
271 268
272static void perl_process_event(int cpu, void *data, 269static void perl_process_event(int cpu, void *data,
273 int size __attribute((unused)), 270 int size __unused,
274 unsigned long long nsecs, char *comm) 271 unsigned long long nsecs, char *comm)
275{ 272{
276 struct format_field *field; 273 struct format_field *field;
@@ -362,28 +359,46 @@ static void run_start_sub(void)
362/* 359/*
363 * Start trace script 360 * Start trace script
364 */ 361 */
365static int perl_start_script(const char *script) 362static int perl_start_script(const char *script, int argc, const char **argv)
366{ 363{
367 const char *command_line[2] = { "", NULL }; 364 const char **command_line;
365 int i, err = 0;
368 366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
369 command_line[1] = script; 369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
370 372
371 my_perl = perl_alloc(); 373 my_perl = perl_alloc();
372 perl_construct(my_perl); 374 perl_construct(my_perl);
373 375
374 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
375 (char **)NULL)) 377 (char **)NULL)) {
376 return -1; 378 err = -1;
379 goto error;
380 }
377 381
378 perl_run(my_perl); 382 if (perl_run(my_perl)) {
379 if (SvTRUE(ERRSV)) 383 err = -1;
380 return -1; 384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
381 391
382 run_start_sub(); 392 run_start_sub();
383 393
394 free(command_line);
384 fprintf(stderr, "perf trace started with Perl script %s\n\n", script); 395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
385
386 return 0; 396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
387} 402}
388 403
389/* 404/*
@@ -573,26 +588,74 @@ struct scripting_ops perl_scripting_ops = {
573 .generate_script = perl_generate_script, 588 .generate_script = perl_generate_script,
574}; 589};
575 590
576#ifdef NO_LIBPERL 591static void print_unsupported_msg(void)
577void setup_perl_scripting(void)
578{ 592{
579 fprintf(stderr, "Perl scripting not supported." 593 fprintf(stderr, "Perl scripting not supported."
580 " Install libperl and rebuild perf to enable it. e.g. " 594 " Install libperl and rebuild perf to enable it.\n"
581 "apt-get install libperl-dev (ubuntu), yum install " 595 "For example:\n # apt-get install libperl-dev (ubuntu)"
582 "perl-ExtUtils-Embed (Fedora), etc.\n"); 596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
583} 598}
584#else 599
585void setup_perl_scripting(void) 600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
586{ 638{
587 int err; 639 int err;
588 err = script_spec_register("Perl", &perl_scripting_ops); 640 err = script_spec_register("Perl", scripting_ops);
589 if (err) 641 if (err)
590 die("error registering Perl script extension"); 642 die("error registering Perl script extension");
591 643
592 err = script_spec_register("pl", &perl_scripting_ops); 644 err = script_spec_register("pl", scripting_ops);
593 if (err) 645 if (err)
594 die("error registering pl script extension"); 646 die("error registering pl script extension");
595 647
596 scripting_context = malloc(sizeof(struct scripting_context)); 648 scripting_context = malloc(sizeof(struct scripting_context));
597} 649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
598#endif 661#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
index 8fe0d866fe1a..e88fb26137bb 100644
--- a/tools/perf/util/trace-event-perl.h
+++ b/tools/perf/util/trace-event-perl.h
@@ -34,9 +34,13 @@ typedef int INTERP;
34#define dXSUB_SYS 34#define dXSUB_SYS
35#define pTHX_ 35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {} 36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
37#else 39#else
38#include <EXTERN.h> 40#include <EXTERN.h>
39#include <perl.h> 41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
40typedef PerlInterpreter * INTERP; 44typedef PerlInterpreter * INTERP;
41#endif 45#endif
42 46
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 342dfdd43f87..1744422cafcb 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void)
145 if (!size) 145 if (!size)
146 return; 146 return;
147 147
148 buf = malloc_or_die(size); 148 buf = malloc_or_die(size + 1);
149 read_or_die(buf, size); 149 read_or_die(buf, size);
150 buf[size] = '\0';
150 151
151 parse_proc_kallsyms(buf, size); 152 parse_proc_kallsyms(buf, size);
152 153
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81698d5e6503..6ad405620c9b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -270,7 +270,7 @@ enum trace_flag_type {
270 270
271struct scripting_ops { 271struct scripting_ops {
272 const char *name; 272 const char *name;
273 int (*start_script) (const char *); 273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void); 274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size, 275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm); 276 unsigned long long nsecs, char *comm);