aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-05-16 18:40:56 -0400
committerHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-05-16 18:40:56 -0400
commitb65b34895437915f411882dd40d704eb0863ffb0 (patch)
tree3e9302ab09c9a9068fd8fd80708ef3a35b55e665 /tools/perf/util
parent88cc83772a3c7756b9f2b4ba835545ad90a08409 (diff)
parentb57f95a38233a2e73b679bea4a5453a1cc2a1cc9 (diff)
Merge mainline (v2.6.34-rc7)
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/build-id.c39
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/cpumap.c59
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c220
-rw-r--r--tools/perf/util/event.h86
-rw-r--r--tools/perf/util/header.c284
-rw-r--r--tools/perf/util/header.h9
-rw-r--r--tools/perf/util/hist.c52
-rw-r--r--tools/perf/util/hist.h12
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h1
-rw-r--r--tools/perf/util/map.c52
-rw-r--r--tools/perf/util/map.h94
-rw-r--r--tools/perf/util/parse-events.c48
-rw-r--r--tools/perf/util/probe-event.c162
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/probe-finder.c965
-rw-r--r--tools/perf/util/probe-finder.h65
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c (renamed from tools/perf/util/trace-event-perl.c)115
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c580
-rw-r--r--tools/perf/util/session.c432
-rw-r--r--tools/perf/util/session.h56
-rw-r--r--tools/perf/util/string.c96
-rw-r--r--tools/perf/util/string.h1
-rw-r--r--tools/perf/util/symbol.c545
-rw-r--r--tools/perf/util/symbol.h55
-rw-r--r--tools/perf/util/thread.c93
-rw-r--r--tools/perf/util/thread.h27
-rw-r--r--tools/perf/util/trace-event-info.c64
-rw-r--r--tools/perf/util/trace-event-parse.c24
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c18
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h10
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.c1
42 files changed, 3485 insertions, 1393 deletions
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..04904b35ba81
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,39 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "build-id.h"
10#include "event.h"
11#include "symbol.h"
12#include <linux/kernel.h>
13
14static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
15{
16 struct addr_location al;
17 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
18 struct thread *thread = perf_session__findnew(session, event->ip.pid);
19
20 if (thread == NULL) {
21 pr_err("problem processing %d event, skipping it.\n",
22 event->header.type);
23 return -1;
24 }
25
26 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
27 event->ip.ip, &al);
28
29 if (al.map != NULL)
30 al.map->dso->hit = 1;
31
32 return 0;
33}
34
35struct perf_event_ops build_id__mark_dso_hit_ops = {
36 .sample = build_id__mark_dso_hit,
37 .mmap = event__process_mmap,
38 .fork = event__process_task,
39};
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..1d981d63cf9a
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,8 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8#endif
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644
index 000000000000..4e01490e51e5
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,59 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7int cpumap[MAX_NR_CPUS];
8
9static int default_cpu_map(void)
10{
11 int nr_cpus, i;
12
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS);
15 assert((int)nr_cpus >= 0);
16
17 for (i = 0; i < nr_cpus; ++i)
18 cpumap[i] = i;
19
20 return nr_cpus;
21}
22
23int read_cpu_map(void)
24{
25 FILE *onlnf;
26 int nr_cpus = 0;
27 int n, cpu, prev;
28 char sep;
29
30 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf)
32 return default_cpu_map();
33
34 sep = 0;
35 prev = -1;
36 for (;;) {
37 n = fscanf(onlnf, "%u%c", &cpu, &sep);
38 if (n <= 0)
39 break;
40 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
42 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev;
44 }
45 assert (nr_cpus < MAX_NR_CPUS);
46 cpumap[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-')
48 prev = cpu;
49 else
50 prev = -1;
51 if (n == 1 || sep == '\n')
52 break;
53 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57
58 return default_cpu_map();
59}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..86c78bb33098
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4extern int read_cpu_map(void);
5extern int cpumap[];
6
7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b836de3d..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
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)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
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;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,6 +9,7 @@
9#include "color.h" 9#include "color.h"
10#include "event.h" 10#include "event.h"
11#include "debug.h" 11#include "debug.h"
12#include "util.h"
12 13
13int verbose = 0; 14int verbose = 0;
14int dump_trace = 0; 15int dump_trace = 0;
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8a9e6baa3099..705ec63548b4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -8,8 +8,7 @@
8#include "thread.h" 8#include "thread.h"
9 9
10static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event, 11 event__handler_t process,
12 struct perf_session *session),
13 struct perf_session *session) 12 struct perf_session *session)
14{ 13{
15 event_t ev; 14 event_t ev;
@@ -91,8 +90,7 @@ out_failure:
91} 90}
92 91
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 93 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 94 struct perf_session *session)
97{ 95{
98 char filename[PATH_MAX]; 96 char filename[PATH_MAX];
@@ -112,7 +110,10 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 while (1) { 110 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 111 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = { 112 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP }, 113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
116 }; 117 };
117 int n; 118 int n;
118 size_t size; 119 size_t size;
@@ -156,9 +157,38 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 157 return 0;
157} 158}
158 159
159int event__synthesize_thread(pid_t pid, 160int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 161 struct perf_session *session)
161 struct perf_session *session), 162{
163 struct rb_node *nd;
164
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) {
167 event_t ev;
168 size_t size;
169 struct map *pos = rb_entry(nd, struct map, rb_node);
170
171 if (pos->dso->kernel)
172 continue;
173
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev));
176 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
177 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start;
182
183 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1);
185 process(&ev, session);
186 }
187
188 return 0;
189}
190
191int event__synthesize_thread(pid_t pid, event__handler_t process,
162 struct perf_session *session) 192 struct perf_session *session)
163{ 193{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 194 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +197,7 @@ int event__synthesize_thread(pid_t pid,
167 return event__synthesize_mmap_events(pid, tgid, process, session); 197 return event__synthesize_mmap_events(pid, tgid, process, session);
168} 198}
169 199
170void event__synthesize_threads(int (*process)(event_t *event, 200void event__synthesize_threads(event__handler_t process,
171 struct perf_session *session),
172 struct perf_session *session) 201 struct perf_session *session)
173{ 202{
174 DIR *proc; 203 DIR *proc;
@@ -189,6 +218,59 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 218 closedir(proc);
190} 219}
191 220
221struct process_symbol_args {
222 const char *name;
223 u64 start;
224};
225
226static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
227{
228 struct process_symbol_args *args = arg;
229
230 /*
231 * Must be a function or at least an alias, as in PARISC64, where "_text" is
232 * an 'A' to the same address as "_stext".
233 */
234 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
235 type == 'A') || strcmp(name, args->name))
236 return 0;
237
238 args->start = start;
239 return 1;
240}
241
242int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session,
244 const char *symbol_name)
245{
246 size_t size;
247 event_t ev = {
248 .header = {
249 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 },
252 };
253 /*
254 * We should get this from /sys/kernel/sections/.text, but till that is
255 * available use this, and after it is use this as a fallback for older
256 * kernels.
257 */
258 struct process_symbol_args args = { .name = symbol_name, };
259
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
261 return -ENOENT;
262
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
270
271 return process(&ev, session);
272}
273
192static void thread__comm_adjust(struct thread *self) 274static void thread__comm_adjust(struct thread *self)
193{ 275{
194 char *comm = self->comm; 276 char *comm = self->comm;
@@ -240,22 +322,88 @@ int event__process_lost(event_t *self, struct perf_session *session)
240 322
241int event__process_mmap(event_t *self, struct perf_session *session) 323int event__process_mmap(event_t *self, struct perf_session *session)
242{ 324{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 325 struct thread *thread;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 326 struct map *map;
245 session->cwd, session->cwdlen); 327
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
329 self->mmap.pid, self->mmap.tid, self->mmap.start,
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
331
332 if (self->mmap.pid == 0) {
333 static const char kmmap_prefix[] = "[kernel.kallsyms.";
334
335 if (self->mmap.filename[0] == '/') {
336 char short_module_name[1024];
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338
339 if (name == NULL)
340 goto out_problem;
341
342 ++name; /* skip / */
343 dot = strrchr(name, '.');
344 if (dot == NULL)
345 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_');
350
351 map = perf_session__new_module_map(session,
352 self->mmap.start,
353 self->mmap.filename);
354 if (map == NULL)
355 goto out_problem;
356
357 name = strdup(short_module_name);
358 if (name == NULL)
359 goto out_problem;
360
361 map->dso->short_name = name;
362 map->end = map->start + self->mmap.len;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix,
364 sizeof(kmmap_prefix) - 1) == 0) {
365 const char *symbol_name = (self->mmap.filename +
366 sizeof(kmmap_prefix) - 1);
367 /*
368 * Should be there already, from the build-id table in
369 * the header.
370 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel,
372 "[kernel.kallsyms]");
373 if (kernel == NULL)
374 goto out_problem;
375
376 kernel->kernel = 1;
377 if (__perf_session__create_kernel_maps(session, kernel) < 0)
378 goto out_problem;
379
380 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
381 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
382 /*
383 * Be a bit paranoid here, some perf.data file came with
384 * a zero sized synthesized MMAP event for the kernel.
385 */
386 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0)
387 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
388
389 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
390 self->mmap.pgoff);
391 }
392 return 0;
393 }
246 394
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 395 thread = perf_session__findnew(session, self->mmap.pid);
248 self->mmap.pid, self->mmap.tid, 396 map = map__new(&self->mmap, MAP__FUNCTION,
249 (void *)(long)self->mmap.start, 397 session->cwd, session->cwdlen);
250 (void *)(long)self->mmap.len,
251 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename);
253 398
254 if (thread == NULL || map == NULL) 399 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 400 goto out_problem;
256 else
257 thread__insert_map(thread, map);
258 401
402 thread__insert_map(thread, map);
403 return 0;
404
405out_problem:
406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 407 return 0;
260} 408}
261 409
@@ -284,11 +432,10 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 432 return 0;
285} 433}
286 434
287void thread__find_addr_location(struct thread *self, 435void thread__find_addr_map(struct thread *self,
288 struct perf_session *session, u8 cpumode, 436 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr, 437 enum map_type type, u64 addr,
290 struct addr_location *al, 438 struct addr_location *al)
291 symbol_filter_t filter)
292{ 439{
293 struct map_groups *mg = &self->mg; 440 struct map_groups *mg = &self->mg;
294 441
@@ -303,7 +450,6 @@ void thread__find_addr_location(struct thread *self,
303 else { 450 else {
304 al->level = 'H'; 451 al->level = 'H';
305 al->map = NULL; 452 al->map = NULL;
306 al->sym = NULL;
307 return; 453 return;
308 } 454 }
309try_again: 455try_again:
@@ -322,11 +468,21 @@ try_again:
322 mg = &session->kmaps; 468 mg = &session->kmaps;
323 goto try_again; 469 goto try_again;
324 } 470 }
325 al->sym = NULL; 471 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 472 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter); 473}
329 } 474
475void thread__find_addr_location(struct thread *self,
476 struct perf_session *session, u8 cpumode,
477 enum map_type type, u64 addr,
478 struct addr_location *al,
479 symbol_filter_t filter)
480{
481 thread__find_addr_map(self, session, cpumode, type, addr, al);
482 if (al->map != NULL)
483 al->sym = map__find_symbol(al->map, al->addr, filter);
484 else
485 al->sym = NULL;
330} 486}
331 487
332static void dso__calc_col_width(struct dso *self) 488static void dso__calc_col_width(struct dso *self)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..a33b94952e34 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -99,76 +99,30 @@ struct events_stats {
99 u64 lost; 99 u64 lost;
100}; 100};
101 101
102void event__print_totals(void); 102struct event_stat_id {
103 103 struct rb_node rb_node;
104enum map_type { 104 struct rb_root hists;
105 MAP__FUNCTION = 0, 105 struct events_stats stats;
106 MAP__VARIABLE, 106 u64 config;
107}; 107 u64 event_stream;
108 108 u32 type;
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
111struct map {
112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
116 u64 start;
117 u64 end;
118 enum map_type type;
119 u64 pgoff;
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123}; 109};
124 110
125static inline u64 map__map_ip(struct map *map, u64 ip) 111void event__print_totals(void);
126{
127 return ip - map->start + map->pgoff;
128}
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152 112
153struct perf_session; 113struct perf_session;
154 114
155int map__load(struct map *self, struct perf_session *session, 115typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
156 symbol_filter_t filter); 116
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 117int event__synthesize_thread(pid_t pid, event__handler_t process,
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);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session); 118 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event, 119void event__synthesize_threads(event__handler_t process,
170 struct perf_session *session),
171 struct perf_session *session); 120 struct perf_session *session);
121int event__synthesize_kernel_mmap(event__handler_t process,
122 struct perf_session *session,
123 const char *symbol_name);
124int event__synthesize_modules(event__handler_t process,
125 struct perf_session *session);
172 126
173int event__process_comm(event_t *self, struct perf_session *session); 127int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session); 128int event__process_lost(event_t *self, struct perf_session *session);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca55106f..6c9aa16ee51f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,12 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
5#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h>
6 10
7#include "util.h" 11#include "util.h"
8#include "header.h" 12#include "header.h"
@@ -105,24 +109,28 @@ struct perf_trace_event_type {
105static int event_count; 109static int event_count;
106static struct perf_trace_event_type *events; 110static struct perf_trace_event_type *events;
107 111
108void perf_header__push_event(u64 id, const char *name) 112int perf_header__push_event(u64 id, const char *name)
109{ 113{
110 if (strlen(name) > MAX_EVENT_NAME) 114 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 115 pr_warning("Event %s will be truncated\n", name);
112 116
113 if (!events) { 117 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 118 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 119 if (events == NULL)
116 die("nomem"); 120 return -ENOMEM;
117 } else { 121 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 122 struct perf_trace_event_type *nevents;
119 if (!events) 123
120 die("nomem"); 124 nevents = realloc(events, (event_count + 1) * sizeof(*events));
125 if (nevents == NULL)
126 return -ENOMEM;
127 events = nevents;
121 } 128 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 129 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 130 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 131 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 132 event_count++;
133 return 0;
126} 134}
127 135
128char *perf_header__find_event(u64 id) 136char *perf_header__find_event(u64 id)
@@ -169,31 +177,48 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 177 return 0;
170} 178}
171 179
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
173{ 184{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 185 static const char zero_buf[NAME_ALIGN];
186 int err = do_write(fd, bf, count);
187
188 if (!err)
189 err = do_write(fd, zero_buf, count_aligned - count);
190
191 return err;
192}
177 193
178 list_for_each_entry(pos, head, node) { 194#define dsos__for_each_with_build_id(pos, head) \
195 list_for_each_entry(pos, head, node) \
196 if (!pos->has_build_id) \
197 continue; \
198 else
199
200static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
201{
202 struct dso *pos;
203
204 dsos__for_each_with_build_id(pos, head) {
179 int err; 205 int err;
180 struct build_id_event b; 206 struct build_id_event b;
181 size_t len; 207 size_t len;
182 208
183 if (!pos->has_build_id) 209 if (!pos->hit)
184 continue; 210 continue;
185 len = pos->long_name_len + 1; 211 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 212 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 213 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 214 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
215 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 216 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 217 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 218 if (err < 0)
192 return err; 219 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 220 err = write_padded(fd, pos->long_name,
194 if (err < 0) 221 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 222 if (err < 0)
198 return err; 223 return err;
199 } 224 }
@@ -203,12 +228,143 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
203 228
204static int dsos__write_buildid_table(int fd) 229static int dsos__write_buildid_table(int fd)
205{ 230{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 231 int err = __dsos__write_buildid_table(&dsos__kernel,
232 PERF_RECORD_MISC_KERNEL, fd);
207 if (err == 0) 233 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 234 err = __dsos__write_buildid_table(&dsos__user,
235 PERF_RECORD_MISC_USER, fd);
209 return err; 236 return err;
210} 237}
211 238
239int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
240 const char *name, bool is_kallsyms)
241{
242 const size_t size = PATH_MAX;
243 char *filename = malloc(size),
244 *linkname = malloc(size), *targetname;
245 int len, err = -1;
246
247 if (filename == NULL || linkname == NULL)
248 goto out_free;
249
250 len = snprintf(filename, size, "%s%s%s",
251 debugdir, is_kallsyms ? "/" : "", name);
252 if (mkdir_p(filename, 0755))
253 goto out_free;
254
255 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
256
257 if (access(filename, F_OK)) {
258 if (is_kallsyms) {
259 if (copyfile("/proc/kallsyms", filename))
260 goto out_free;
261 } else if (link(name, filename) && copyfile(name, filename))
262 goto out_free;
263 }
264
265 len = snprintf(linkname, size, "%s/.build-id/%.2s",
266 debugdir, sbuild_id);
267
268 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
269 goto out_free;
270
271 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
272 targetname = filename + strlen(debugdir) - 5;
273 memcpy(targetname, "../..", 5);
274
275 if (symlink(targetname, linkname) == 0)
276 err = 0;
277out_free:
278 free(filename);
279 free(linkname);
280 return err;
281}
282
283static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
284 const char *name, const char *debugdir,
285 bool is_kallsyms)
286{
287 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
288
289 build_id__sprintf(build_id, build_id_size, sbuild_id);
290
291 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
292}
293
294int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
295{
296 const size_t size = PATH_MAX;
297 char *filename = malloc(size),
298 *linkname = malloc(size);
299 int err = -1;
300
301 if (filename == NULL || linkname == NULL)
302 goto out_free;
303
304 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
305 debugdir, sbuild_id, sbuild_id + 2);
306
307 if (access(linkname, F_OK))
308 goto out_free;
309
310 if (readlink(linkname, filename, size) < 0)
311 goto out_free;
312
313 if (unlink(linkname))
314 goto out_free;
315
316 /*
317 * Since the link is relative, we must make it absolute:
318 */
319 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
320 debugdir, sbuild_id, filename);
321
322 if (unlink(linkname))
323 goto out_free;
324
325 err = 0;
326out_free:
327 free(filename);
328 free(linkname);
329 return err;
330}
331
332static int dso__cache_build_id(struct dso *self, const char *debugdir)
333{
334 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
335
336 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
337 self->long_name, debugdir, is_kallsyms);
338}
339
340static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
341{
342 struct dso *pos;
343 int err = 0;
344
345 dsos__for_each_with_build_id(pos, head)
346 if (dso__cache_build_id(pos, debugdir))
347 err = -1;
348
349 return err;
350}
351
352static int dsos__cache_build_ids(void)
353{
354 int err_kernel, err_user;
355 char debugdir[PATH_MAX];
356
357 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
358 DEBUG_CACHE_DIR);
359
360 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
361 return -1;
362
363 err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
364 err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
365 return err_kernel || err_user ? -1 : 0;
366}
367
212static int perf_header__adds_write(struct perf_header *self, int fd) 368static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 369{
214 int nr_sections; 370 int nr_sections;
@@ -217,7 +373,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
217 u64 sec_start; 373 u64 sec_start;
218 int idx = 0, err; 374 int idx = 0, err;
219 375
220 if (dsos__read_build_ids()) 376 if (dsos__read_build_ids(true))
221 perf_header__set_feat(self, HEADER_BUILD_ID); 377 perf_header__set_feat(self, HEADER_BUILD_ID);
222 378
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 379 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -257,7 +413,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
257 pr_debug("failed to write buildid table\n"); 413 pr_debug("failed to write buildid table\n");
258 goto out_free; 414 goto out_free;
259 } 415 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 416 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
417 buildid_sec->offset;
418 dsos__cache_build_ids();
261 } 419 }
262 420
263 lseek(fd, sec_start, SEEK_SET); 421 lseek(fd, sec_start, SEEK_SET);
@@ -360,30 +518,43 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 518 return 0;
361} 519}
362 520
363static void do_read(int fd, void *buf, size_t size) 521static int do_read(int fd, void *buf, size_t size)
364{ 522{
365 while (size) { 523 while (size) {
366 int ret = read(fd, buf, size); 524 int ret = read(fd, buf, size);
367 525
368 if (ret < 0) 526 if (ret <= 0)
369 die("failed to read"); 527 return -1;
370 if (ret == 0)
371 die("failed to read: missing data");
372 528
373 size -= ret; 529 size -= ret;
374 buf += ret; 530 buf += ret;
375 } 531 }
532
533 return 0;
534}
535
536static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size)
538{
539 if (do_read(fd, buf, size))
540 return -1;
541
542 if (self->needs_swap)
543 mem_bswap_64(buf, size);
544
545 return 0;
376} 546}
377 547
378int perf_header__process_sections(struct perf_header *self, int fd, 548int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 549 int (*process)(struct perf_file_section *self,
550 struct perf_header *ph,
380 int feat, int fd)) 551 int feat, int fd))
381{ 552{
382 struct perf_file_section *feat_sec; 553 struct perf_file_section *feat_sec;
383 int nr_sections; 554 int nr_sections;
384 int sec_size; 555 int sec_size;
385 int idx = 0; 556 int idx = 0;
386 int err = 0, feat = 1; 557 int err = -1, feat = 1;
387 558
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 559 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 560 if (!nr_sections)
@@ -397,33 +568,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 568
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 569 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 570
400 do_read(fd, feat_sec, sec_size); 571 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
572 goto out_free;
401 573
574 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 575 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 576 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 577 struct perf_file_section *sec = &feat_sec[idx++];
405 578
406 err = process(sec, feat, fd); 579 err = process(sec, self, feat, fd);
407 if (err < 0) 580 if (err < 0)
408 break; 581 break;
409 } 582 }
410 ++feat; 583 ++feat;
411 } 584 }
412 585out_free:
413 free(feat_sec); 586 free(feat_sec);
414 return err; 587 return err;
415}; 588}
416 589
417int perf_file_header__read(struct perf_file_header *self, 590int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 591 struct perf_header *ph, int fd)
419{ 592{
420 lseek(fd, 0, SEEK_SET); 593 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 594
423 if (self->magic != PERF_MAGIC || 595 if (do_read(fd, self, sizeof(*self)) ||
424 self->attr_size != sizeof(struct perf_file_attr)) 596 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 597 return -1;
426 598
599 if (self->attr_size != sizeof(struct perf_file_attr)) {
600 u64 attr_size = bswap_64(self->attr_size);
601
602 if (attr_size != sizeof(struct perf_file_attr))
603 return -1;
604
605 mem_bswap_64(self, offsetof(struct perf_file_header,
606 adds_features));
607 ph->needs_swap = true;
608 }
609
427 if (self->size != sizeof(*self)) { 610 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 611 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 612 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +616,31 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 616 }
434 617
435 memcpy(&ph->adds_features, &self->adds_features, 618 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 619 sizeof(ph->adds_features));
620 /*
621 * FIXME: hack that assumes that if we need swap the perf.data file
622 * may be coming from an arch with a different word-size, ergo different
623 * DEFINE_BITMAP format, investigate more later, but for now its mostly
624 * safe to assume that we have a build-id section. Trace files probably
625 * have several other issues in this realm anyway...
626 */
627 if (ph->needs_swap) {
628 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
629 perf_header__set_feat(ph, HEADER_BUILD_ID);
630 }
437 631
438 ph->event_offset = self->event_types.offset; 632 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 633 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 634 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 635 ph->data_size = self->data.size;
442 return 0; 636 return 0;
443} 637}
444 638
445static int perf_file_section__process(struct perf_file_section *self, 639static int perf_file_section__process(struct perf_file_section *self,
640 struct perf_header *ph,
446 int feat, int fd) 641 int feat, int fd)
447{ 642{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 643 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 644 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 645 "continuing...\n", self->offset, feat);
451 return 0; 646 return 0;
@@ -457,7 +652,7 @@ static int perf_file_section__process(struct perf_file_section *self,
457 break; 652 break;
458 653
459 case HEADER_BUILD_ID: 654 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 655 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 656 pr_debug("Failed to read buildids, continuing...\n");
462 break; 657 break;
463 default: 658 default:
@@ -469,7 +664,7 @@ static int perf_file_section__process(struct perf_file_section *self,
469 664
470int perf_header__read(struct perf_header *self, int fd) 665int perf_header__read(struct perf_header *self, int fd)
471{ 666{
472 struct perf_file_header f_header; 667 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 668 struct perf_file_attr f_attr;
474 u64 f_id; 669 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 670 int nr_attrs, nr_ids, i, j;
@@ -486,7 +681,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 681 struct perf_header_attr *attr;
487 off_t tmp; 682 off_t tmp;
488 683
489 do_read(fd, &f_attr, sizeof(f_attr)); 684 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
685 goto out_errno;
686
490 tmp = lseek(fd, 0, SEEK_CUR); 687 tmp = lseek(fd, 0, SEEK_CUR);
491 688
492 attr = perf_header_attr__new(&f_attr.attr); 689 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +694,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 694 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 695
499 for (j = 0; j < nr_ids; j++) { 696 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 697 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
698 goto out_errno;
501 699
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 700 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 701 perf_header_attr__delete(attr);
@@ -517,7 +715,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 715 events = malloc(f_header.event_types.size);
518 if (events == NULL) 716 if (events == NULL)
519 return -ENOMEM; 717 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 718 if (perf_header__getbuffer64(self, fd, events,
719 f_header.event_types.size))
720 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 721 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 722 }
523 723
@@ -527,6 +727,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 727
528 self->frozen = 1; 728 self->frozen = 1;
529 return 0; 729 return 0;
730out_errno:
731 return -errno;
530} 732}
531 733
532u64 perf_header__sample_type(struct perf_header *header) 734u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -52,6 +53,7 @@ struct perf_header {
52 u64 data_size; 53 u64 data_size;
53 u64 event_offset; 54 u64 event_offset;
54 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 58};
57 59
@@ -64,7 +66,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit);
64int perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
66 68
67void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
69 71
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -80,6 +82,11 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 82
81int perf_header__process_sections(struct perf_header *self, int fd, 83int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
83 int feat, int fd)); 86 int feat, int fd));
84 87
88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
91
85#endif /* __PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e8daf5ca6fd2..2be33c7dbf03 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -12,12 +12,12 @@ struct callchain_param callchain_param = {
12 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
13 */ 13 */
14 14
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
16 struct addr_location *al, 16 struct addr_location *al,
17 struct symbol *sym_parent, 17 struct symbol *sym_parent,
18 u64 count, bool *hit) 18 u64 count, bool *hit)
19{ 19{
20 struct rb_node **p = &self->hists.rb_node; 20 struct rb_node **p = &hists->rb_node;
21 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
22 struct hist_entry *he; 22 struct hist_entry *he;
23 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -53,7 +53,7 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
53 return NULL; 53 return NULL;
54 *he = entry; 54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, &self->hists); 56 rb_insert_color(&he->rb_node, hists);
57 *hit = false; 57 *hit = false;
58 return he; 58 return he;
59} 59}
@@ -130,7 +130,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
130 rb_insert_color(&he->rb_node, root); 130 rb_insert_color(&he->rb_node, root);
131} 131}
132 132
133void perf_session__collapse_resort(struct perf_session *self) 133void perf_session__collapse_resort(struct rb_root *hists)
134{ 134{
135 struct rb_root tmp; 135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
@@ -140,17 +140,17 @@ void perf_session__collapse_resort(struct perf_session *self)
140 return; 140 return;
141 141
142 tmp = RB_ROOT; 142 tmp = RB_ROOT;
143 next = rb_first(&self->hists); 143 next = rb_first(hists);
144 144
145 while (next) { 145 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
148 148
149 rb_erase(&n->rb_node, &self->hists); 149 rb_erase(&n->rb_node, hists);
150 collapse__insert_entry(&tmp, n); 150 collapse__insert_entry(&tmp, n);
151 } 151 }
152 152
153 self->hists = tmp; 153 *hists = tmp;
154} 154}
155 155
156/* 156/*
@@ -183,7 +183,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,
183 rb_insert_color(&he->rb_node, root); 183 rb_insert_color(&he->rb_node, root);
184} 184}
185 185
186void perf_session__output_resort(struct perf_session *self, u64 total_samples) 186void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
187{ 187{
188 struct rb_root tmp; 188 struct rb_root tmp;
189 struct rb_node *next; 189 struct rb_node *next;
@@ -194,18 +194,18 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples)
194 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
195 195
196 tmp = RB_ROOT; 196 tmp = RB_ROOT;
197 next = rb_first(&self->hists); 197 next = rb_first(hists);
198 198
199 while (next) { 199 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
202 202
203 rb_erase(&n->rb_node, &self->hists); 203 rb_erase(&n->rb_node, hists);
204 perf_session__insert_output_hist_entry(&tmp, n, 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits); 205 min_callchain_hits);
206 } 206 }
207 207
208 self->hists = tmp; 208 *hists = tmp;
209} 209}
210 210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -321,7 +321,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 321 new_depth_mask &= ~(1 << (depth - 1));
322 322
323 /* 323 /*
324 * But we keep the older depth mask for the line seperator 324 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 325 * to keep the level link until we reach the last child
326 */ 326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
@@ -456,10 +456,10 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
456} 456}
457 457
458static size_t hist_entry__fprintf(struct hist_entry *self, 458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session, 459 struct perf_session *pair_session,
461 bool show_displacement, 460 bool show_displacement,
462 long displacement, FILE *fp) 461 long displacement, FILE *fp,
462 u64 session_total)
463{ 463{
464 struct sort_entry *se; 464 struct sort_entry *se;
465 u64 count, total; 465 u64 count, total;
@@ -474,7 +474,7 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
474 total = pair_session->events_stats.total; 474 total = pair_session->events_stats.total;
475 } else { 475 } else {
476 count = self->count; 476 count = self->count;
477 total = session->events_stats.total; 477 total = session_total;
478 } 478 }
479 479
480 if (total) 480 if (total)
@@ -496,8 +496,8 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
496 496
497 if (total > 0) 497 if (total > 0)
498 old_percent = (count * 100.0) / total; 498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0) 499 if (session_total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total; 500 new_percent = (self->count * 100.0) / session_total;
501 501
502 diff = new_percent - old_percent; 502 diff = new_percent - old_percent;
503 503
@@ -544,16 +544,17 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
544 left_margin -= thread__comm_len(self->thread); 544 left_margin -= thread__comm_len(self->thread);
545 } 545 }
546 546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total, 547 hist_entry_callchain__fprintf(fp, self, session_total,
548 left_margin); 548 left_margin);
549 } 549 }
550 550
551 return ret; 551 return ret;
552} 552}
553 553
554size_t perf_session__fprintf_hists(struct perf_session *self, 554size_t perf_session__fprintf_hists(struct rb_root *hists,
555 struct perf_session *pair, 555 struct perf_session *pair,
556 bool show_displacement, FILE *fp) 556 bool show_displacement, FILE *fp,
557 u64 session_total)
557{ 558{
558 struct sort_entry *se; 559 struct sort_entry *se;
559 struct rb_node *nd; 560 struct rb_node *nd;
@@ -641,7 +642,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
641 fprintf(fp, "\n#\n"); 642 fprintf(fp, "\n#\n");
642 643
643print_entries: 644print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 645 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 646 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646 647
647 if (show_displacement) { 648 if (show_displacement) {
@@ -652,8 +653,13 @@ print_entries:
652 displacement = 0; 653 displacement = 0;
653 ++position; 654 ++position;
654 } 655 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement, 656 ret += hist_entry__fprintf(h, pair, show_displacement,
656 displacement, fp); 657 displacement, fp, session_total);
658 if (h->map == NULL && verbose > 1) {
659 __map_groups__fprintf_maps(&h->thread->mg,
660 MAP__FUNCTION, fp);
661 fprintf(fp, "%.10s end\n", graph_dotted_line);
662 }
657 } 663 }
658 664
659 free(rem_sq_bracket); 665 free(rem_sq_bracket);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index e5f99b24048b..16f360cce5bf 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -10,8 +10,9 @@ struct perf_session;
10struct hist_entry; 10struct hist_entry;
11struct addr_location; 11struct addr_location;
12struct symbol; 12struct symbol;
13struct rb_root;
13 14
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
15 struct addr_location *al, 16 struct addr_location *al,
16 struct symbol *parent, 17 struct symbol *parent,
17 u64 count, bool *hit); 18 u64 count, bool *hit);
@@ -19,9 +20,10 @@ extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
20void hist_entry__free(struct hist_entry *); 21void hist_entry__free(struct hist_entry *);
21 22
22void perf_session__output_resort(struct perf_session *self, u64 total_samples); 23void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self); 24void perf_session__collapse_resort(struct rb_root *hists);
24size_t perf_session__fprintf_hists(struct perf_session *self, 25size_t perf_session__fprintf_hists(struct rb_root *hists,
25 struct perf_session *pair, 26 struct perf_session *pair,
26 bool show_displacement, FILE *fp); 27 bool show_displacement, FILE *fp,
28 u64 session_total);
27#endif /* __PERF_HIST_H */ 29#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 21c0274c02fa..f2611655ab51 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -101,5 +101,6 @@ simple_strtoul(const char *nptr, char **endptr, int base)
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
104 105
105#endif 106#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c4d55a0da2ea..e509cd59c67d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -5,6 +5,11 @@
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h" 6#include "debug.h"
7 7
8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions",
10 [MAP__VARIABLE] = "Variables",
11};
12
8static inline int is_anon_memory(const char *filename) 13static inline int is_anon_memory(const char *filename)
9{ 14{
10 return strcmp(filename, "//anon") == 0; 15 return strcmp(filename, "//anon") == 0;
@@ -68,8 +73,13 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
68 map__init(self, type, event->start, event->start + event->len, 73 map__init(self, type, event->start, event->start + event->len,
69 event->pgoff, dso); 74 event->pgoff, dso);
70 75
71 if (self->dso == vdso || anon) 76 if (anon) {
77set_identity:
72 self->map_ip = self->unmap_ip = identity__map_ip; 78 self->map_ip = self->unmap_ip = identity__map_ip;
79 } else if (strcmp(filename, "[vdso]") == 0) {
80 dso__set_loaded(dso, self->type);
81 goto set_identity;
82 }
73 } 83 }
74 return self; 84 return self;
75out_delete: 85out_delete:
@@ -104,8 +114,7 @@ void map__fixup_end(struct map *self)
104 114
105#define DSO__DELETED "(deleted)" 115#define DSO__DELETED "(deleted)"
106 116
107int map__load(struct map *self, struct perf_session *session, 117int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 118{
110 const char *name = self->dso->long_name; 119 const char *name = self->dso->long_name;
111 int nr; 120 int nr;
@@ -113,7 +122,7 @@ int map__load(struct map *self, struct perf_session *session,
113 if (dso__loaded(self->dso, self->type)) 122 if (dso__loaded(self->dso, self->type))
114 return 0; 123 return 0;
115 124
116 nr = dso__load(self->dso, self, session, filter); 125 nr = dso__load(self->dso, self, filter);
117 if (nr < 0) { 126 if (nr < 0) {
118 if (self->dso->has_build_id) { 127 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 128 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -144,24 +153,29 @@ int map__load(struct map *self, struct perf_session *session,
144 153
145 return -1; 154 return -1;
146 } 155 }
156 /*
157 * Only applies to the kernel, as its symtabs aren't relative like the
158 * module ones.
159 */
160 if (self->dso->kernel)
161 map__reloc_vmlinux(self);
147 162
148 return 0; 163 return 0;
149} 164}
150 165
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 166struct symbol *map__find_symbol(struct map *self, u64 addr,
152 u64 addr, symbol_filter_t filter) 167 symbol_filter_t filter)
153{ 168{
154 if (map__load(self, session, filter) < 0) 169 if (map__load(self, filter) < 0)
155 return NULL; 170 return NULL;
156 171
157 return dso__find_symbol(self->dso, self->type, addr); 172 return dso__find_symbol(self->dso, self->type, addr);
158} 173}
159 174
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 175struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter) 176 symbol_filter_t filter)
163{ 177{
164 if (map__load(self, session, filter) < 0) 178 if (map__load(self, filter) < 0)
165 return NULL; 179 return NULL;
166 180
167 if (!dso__sorted_by_name(self->dso, self->type)) 181 if (!dso__sorted_by_name(self->dso, self->type))
@@ -201,3 +215,23 @@ size_t map__fprintf(struct map *self, FILE *fp)
201 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 215 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
202 self->start, self->end, self->pgoff, self->dso->name); 216 self->start, self->end, self->pgoff, self->dso->name);
203} 217}
218
219/*
220 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222 */
223u64 map__rip_2objdump(struct map *map, u64 rip)
224{
225 u64 addr = map->dso->adjust_symbols ?
226 map->unmap_ip(map, rip) : /* RIP -> IP */
227 rip;
228 return addr;
229}
230
231u64 map__objdump_2ip(struct map *map, u64 addr)
232{
233 u64 ip = map->dso->adjust_symbols ?
234 addr :
235 map->unmap_ip(map, addr); /* RIP -> IP */
236 return ip;
237}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..b756368076c6
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,94 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <linux/types.h>
8
9enum map_type {
10 MAP__FUNCTION = 0,
11 MAP__VARIABLE,
12};
13
14#define MAP__NR_TYPES (MAP__VARIABLE + 1)
15
16extern const char *map_type__name[MAP__NR_TYPES];
17
18struct dso;
19struct ref_reloc_sym;
20struct map_groups;
21
22struct map {
23 union {
24 struct rb_node rb_node;
25 struct list_head node;
26 };
27 u64 start;
28 u64 end;
29 enum map_type type;
30 u64 pgoff;
31
32 /* ip -> dso rip */
33 u64 (*map_ip)(struct map *, u64);
34 /* dso rip -> ip */
35 u64 (*unmap_ip)(struct map *, u64);
36
37 struct dso *dso;
38};
39
40struct kmap {
41 struct ref_reloc_sym *ref_reloc_sym;
42 struct map_groups *kmaps;
43};
44
45static inline struct kmap *map__kmap(struct map *self)
46{
47 return (struct kmap *)(self + 1);
48}
49
50static inline u64 map__map_ip(struct map *map, u64 ip)
51{
52 return ip - map->start + map->pgoff;
53}
54
55static inline u64 map__unmap_ip(struct map *map, u64 ip)
56{
57 return ip + map->start - map->pgoff;
58}
59
60static inline u64 identity__map_ip(struct map *map __used, u64 ip)
61{
62 return ip;
63}
64
65
66/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
67u64 map__rip_2objdump(struct map *map, u64 rip);
68u64 map__objdump_2ip(struct map *map, u64 addr);
69
70struct symbol;
71struct mmap_event;
72
73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
74
75void map__init(struct map *self, enum map_type type,
76 u64 start, u64 end, u64 pgoff, struct dso *dso);
77struct map *map__new(struct mmap_event *event, enum map_type,
78 char *cwd, int cwdlen);
79void map__delete(struct map *self);
80struct map *map__clone(struct map *self);
81int map__overlap(struct map *l, struct map *r);
82size_t map__fprintf(struct map *self, FILE *fp);
83
84int map__load(struct map *self, symbol_filter_t filter);
85struct symbol *map__find_symbol(struct map *self,
86 u64 addr, symbol_filter_t filter);
87struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
88 symbol_filter_t filter);
89void map__fixup_start(struct map *self);
90void map__fixup_end(struct map *self);
91
92void map__reloc_vmlinux(struct map *self);
93
94#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -450,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
450/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 452static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
454{ 455{
455 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -474,6 +475,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 476 continue;
476 477
478 if (!strglobmatch(evt_ent->d_name, evt_exp))
479 continue;
480
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 482 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 483 flags ?: "");
@@ -522,9 +526,10 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 527 return EVT_FAILED;
524 528
525 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
528 } else 533 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 535 evt_length, flags,
@@ -753,11 +758,11 @@ modifier:
753 return ret; 758 return ret;
754} 759}
755 760
756static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
757{ 762{
758 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
759 FILE *file; 764 FILE *file;
760 int id; 765 int id, n;
761 766
762 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +774,14 @@ static void store_event_type(const char *orgname)
769 774
770 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
771 if (!file) 776 if (!file)
772 return; 777 return 0;
773 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 779 fclose(file);
776 perf_header__push_event(id, orgname); 780 if (n < 1) {
781 pr_err("cannot store event ID\n");
782 return -EINVAL;
783 }
784 return perf_header__push_event(id, orgname);
777} 785}
778 786
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 787int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -782,7 +790,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 790 enum event_result ret;
783 791
784 if (strchr(str, ':')) 792 if (strchr(str, ':'))
785 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
786 795
787 for (;;) { 796 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +844,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 844}
836 845
837static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 847 "Hardware event",
840 "Software event", 848 "Software event",
841 "Tracepoint event", 849 "Tracepoint event",
842 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
843}; 853};
844 854
845/* 855/*
@@ -872,7 +882,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 886 }
877 closedir(evt_dir); 887 closedir(evt_dir);
878 } 888 }
@@ -892,9 +902,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
893 903
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 905 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 906
899 if (type != prev_type) 907 if (type != prev_type)
900 printf("\n"); 908 printf("\n");
@@ -919,17 +927,19 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 931 }
924 } 932 }
925 } 933 }
926 934
927 printf("\n"); 935 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
929 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 938 printf("\n");
931 939
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 943 printf("\n");
934 944
935 print_tracepoint_events(); 945 print_tracepoint_events();
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fde17b090a47..7c004b6ef24f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -37,6 +37,8 @@
37#include "string.h" 37#include "string.h"
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h"
41#include "color.h"
40#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h" 43#include "probe-event.h"
42 44
@@ -62,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 64 return ret;
63} 65}
64 66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
65/* Check the name is good for event/group */ 103/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 104static bool check_event_name(const char *name)
67{ 105{
@@ -81,14 +119,14 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
81 char c, nc = 0; 119 char c, nc = 0;
82 /* 120 /*
83 * <Syntax> 121 * <Syntax>
84 * perf probe [EVENT=]SRC:LN 122 * perf probe [EVENT=]SRC[:LN|;PTN]
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
86 * 124 *
87 * TODO:Group name support 125 * TODO:Group name support
88 */ 126 */
89 127
90 ptr = strchr(arg, '='); 128 ptr = strpbrk(arg, ";=@+%");
91 if (ptr) { /* Event name */ 129 if (ptr && *ptr == '=') { /* Event name */
92 *ptr = '\0'; 130 *ptr = '\0';
93 tmp = ptr + 1; 131 tmp = ptr + 1;
94 ptr = strchr(arg, ':'); 132 ptr = strchr(arg, ':');
@@ -101,7 +139,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
101 arg = tmp; 139 arg = tmp;
102 } 140 }
103 141
104 ptr = strpbrk(arg, ":+@%"); 142 ptr = strpbrk(arg, ";:+@%");
105 if (ptr) { 143 if (ptr) {
106 nc = *ptr; 144 nc = *ptr;
107 *ptr++ = '\0'; 145 *ptr++ = '\0';
@@ -118,7 +156,11 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
118 while (ptr) { 156 while (ptr) {
119 arg = ptr; 157 arg = ptr;
120 c = nc; 158 c = nc;
121 ptr = strpbrk(arg, ":+@%"); 159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
122 if (ptr) { 164 if (ptr) {
123 nc = *ptr; 165 nc = *ptr;
124 *ptr++ = '\0'; 166 *ptr++ = '\0';
@@ -127,13 +169,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
127 case ':': /* Line number */ 169 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0); 170 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0') 171 if (*tmp != '\0')
130 semantic_error("There is non-digit charactor" 172 semantic_error("There is non-digit char"
131 " in line number."); 173 " in line number.");
132 break; 174 break;
133 case '+': /* Byte offset from a symbol */ 175 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0); 176 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0') 177 if (*tmp != '\0')
136 semantic_error("There is non-digit charactor" 178 semantic_error("There is non-digit character"
137 " in offset."); 179 " in offset.");
138 break; 180 break;
139 case '@': /* File name */ 181 case '@': /* File name */
@@ -141,9 +183,6 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
141 semantic_error("SRC@SRC is not allowed."); 183 semantic_error("SRC@SRC is not allowed.");
142 pp->file = strdup(arg); 184 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL); 185 DIE_IF(pp->file == NULL);
144 if (ptr)
145 semantic_error("@SRC must be the last "
146 "option.");
147 break; 186 break;
148 case '%': /* Probe places */ 187 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) { 188 if (strcmp(arg, "return") == 0) {
@@ -158,11 +197,18 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
158 } 197 }
159 198
160 /* Exclusion check */ 199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
161 if (pp->line && pp->offset) 206 if (pp->line && pp->offset)
162 semantic_error("Offset can't be used with line number."); 207 semantic_error("Offset can't be used with line number.");
163 208
164 if (!pp->line && pp->file && !pp->function) 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
165 semantic_error("File always requires line number."); 210 semantic_error("File always requires line number or "
211 "lazy pattern.");
166 212
167 if (pp->offset && !pp->function) 213 if (pp->offset && !pp->function)
168 semantic_error("Offset requires an entry function."); 214 semantic_error("Offset requires an entry function.");
@@ -170,11 +216,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
170 if (pp->retprobe && !pp->function) 216 if (pp->retprobe && !pp->function)
171 semantic_error("Return probe requires an entry function."); 217 semantic_error("Return probe requires an entry function.");
172 218
173 if ((pp->offset || pp->line) && pp->retprobe) 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
174 semantic_error("Offset/Line can't be used with return probe."); 220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
175 222
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
178} 226}
179 227
180/* Parse perf-probe event definition */ 228/* Parse perf-probe event definition */
@@ -194,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
194 242
195 /* Parse probe point */ 243 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp); 244 parse_perf_probe_probepoint(argv[0], pp);
197 if (pp->file || pp->line) 245 if (pp->file || pp->line || pp->lazy_line)
198 *need_dwarf = true; 246 *need_dwarf = true;
199 247
200 /* Copy arguments and ensure return probe has no C argument */ 248 /* Copy arguments and ensure return probe has no C argument */
@@ -370,7 +418,7 @@ static int open_kprobe_events(int flags, int mode)
370 if (ret < 0) { 418 if (ret < 0) {
371 if (errno == ENOENT) 419 if (errno == ENOENT)
372 die("kprobe_events file does not exist -" 420 die("kprobe_events file does not exist -"
373 " please rebuild with CONFIG_KPROBE_TRACER."); 421 " please rebuild with CONFIG_KPROBE_EVENT.");
374 else 422 else
375 die("Could not open kprobe_events file: %s", 423 die("Could not open kprobe_events file: %s",
376 strerror(errno)); 424 strerror(errno));
@@ -420,6 +468,8 @@ static void clear_probe_point(struct probe_point *pp)
420 free(pp->function); 468 free(pp->function);
421 if (pp->file) 469 if (pp->file)
422 free(pp->file); 470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
423 for (i = 0; i < pp->nr_args; i++) 473 for (i = 0; i < pp->nr_args; i++)
424 free(pp->args[i]); 474 free(pp->args[i]);
425 if (pp->args) 475 if (pp->args)
@@ -457,7 +507,9 @@ void show_perf_probe_events(void)
457 struct strlist *rawlist; 507 struct strlist *rawlist;
458 struct str_node *ent; 508 struct str_node *ent;
459 509
510 setup_pager();
460 memset(&pp, 0, sizeof(pp)); 511 memset(&pp, 0, sizeof(pp));
512
461 fd = open_kprobe_events(O_RDONLY, 0); 513 fd = open_kprobe_events(O_RDONLY, 0);
462 rawlist = get_trace_kprobe_event_rawlist(fd); 514 rawlist = get_trace_kprobe_event_rawlist(fd);
463 close(fd); 515 close(fd);
@@ -678,3 +730,73 @@ void del_trace_kprobe_events(struct strlist *dellist)
678 close(fd); 730 close(fd);
679} 731}
680 732
733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
735
736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
737{
738 char buf[LINEBUF_SIZE];
739 const char *color = PERF_COLOR_BLUE;
740
741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
742 goto error;
743 if (!skip) {
744 if (show_num)
745 fprintf(stdout, "%7u %s", l, buf);
746 else
747 color_fprintf(stdout, color, " %s", buf);
748 }
749
750 while (strlen(buf) == LINEBUF_SIZE - 1 &&
751 buf[LINEBUF_SIZE - 2] != '\n') {
752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
753 goto error;
754 if (!skip) {
755 if (show_num)
756 fprintf(stdout, "%s", buf);
757 else
758 color_fprintf(stdout, color, "%s", buf);
759 }
760 }
761 return;
762error:
763 if (feof(fp))
764 die("Source file is shorter than expected.");
765 else
766 die("File read error: %s", strerror(errno));
767}
768
769void show_line_range(struct line_range *lr)
770{
771 unsigned int l = 1;
772 struct line_node *ln;
773 FILE *fp;
774
775 setup_pager();
776
777 if (lr->function)
778 fprintf(stdout, "<%s:%d>\n", lr->function,
779 lr->start - lr->offset);
780 else
781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
782
783 fp = fopen(lr->path, "r");
784 if (fp == NULL)
785 die("Failed to open %s: %s", lr->path, strerror(errno));
786 /* Skip to starting line number */
787 while (l < lr->start)
788 show_one_line(fp, l++, true, false);
789
790 list_for_each_entry(ln, &lr->line_list, list) {
791 while (ln->line > l)
792 show_one_line(fp, (l++) - lr->offset, false, false);
793 show_one_line(fp, (l++) - lr->offset, false, true);
794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
801 fclose(fp);
802}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..711287d4baea 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,7 @@
5#include "probe-finder.h" 5#include "probe-finder.h"
6#include "strlist.h" 6#include "strlist.h"
7 7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf); 10 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp); 11extern int synthesize_perf_probe_point(struct probe_point *pp);
@@ -15,6 +16,7 @@ extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add); 16 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist); 17extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void); 18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
18 20
19/* Maximum index number of event-name postfix */ 21/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 22#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..c171a243d05b 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -32,21 +32,13 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34 34
35#include "string.h"
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
38#include "probe-finder.h" 39#include "probe-finder.h"
39 40
40 41
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/* 42/*
51 * Generic dwarf analysis helpers 43 * Generic dwarf analysis helpers
52 */ 44 */
@@ -113,256 +105,190 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 105 return 0;
114} 106}
115 107
116/* Find the fileno of the target file. */ 108/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118{
119 Dwarf_Signed cnt, i;
120 Dwarf_Unsigned found = 0;
121 char **srcs;
122 int ret;
123
124 if (!fname)
125 return 0;
126 109
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 110/* Add a line to line number list */
128 if (ret == DW_DLV_OK) { 111static void line_list__add_line(struct list_head *head, unsigned int line)
129 for (i = 0; i < cnt && !found; i++) { 112{
130 if (strtailcmp(srcs[i], fname) == 0) 113 struct line_node *ln;
131 found = i + 1; 114 struct list_head *p;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 115
133 } 116 /* Reverse search, because new line will be the last one */
134 for (; i < cnt; i++) 117 list_for_each_entry_reverse(ln, head, list) {
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 118 if (ln->line < line) {
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
137 } 123 }
138 if (found) 124 /* List is empty, or the smallest entry */
139 pr_debug("found fno: %d\n", (int)found); 125 p = head;
140 return found; 126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
141} 133}
142 134
143/* Compare diename and tname */ 135/* Check if the line in line number list */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 136static int line_list__has_line(struct list_head *head, unsigned int line)
145{ 137{
146 char *name; 138 struct line_node *ln;
147 int ret;
148 ret = dwarf_diename(dw_die, &name, &__dw_error);
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156}
157 139
158/* Check the address is in the subprogram(function). */ 140 /* Reverse search, because new line will be the last one */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 141 list_for_each_entry(ln, head, list)
160 Dwarf_Signed *offs) 142 if (ln->line == line)
161{ 143 return 1;
162 Dwarf_Addr lopc, hipc;
163 int ret;
164 144
165 /* TODO: check ranges */ 145 return 0;
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
167 DIE_IF(ret == DW_DLV_ERROR);
168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
171 DIE_IF(ret != DW_DLV_OK);
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177} 146}
178 147
179/* Check the die is inlined function */ 148/* Init line number list */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 149static void line_list__init(struct list_head *head)
181{ 150{
182 /* TODO: check strictly */ 151 INIT_LIST_HEAD(head);
183 Dwarf_Bool inl; 152}
184 int ret;
185 153
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 154/* Free line number list */
187 DIE_IF(ret == DW_DLV_ERROR); 155static void line_list__free(struct list_head *head)
188 return inl; 156{
157 struct line_node *ln;
158 while (!list_empty(head)) {
159 ln = list_first_entry(head, struct line_node, list);
160 list_del(&ln->list);
161 free(ln);
162 }
189} 163}
190 164
191/* Get the offset of abstruct_origin */ 165/* Dwarf wrappers */
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
193{ 169{
194 Dwarf_Attribute attr; 170 Dwarf_Files *files;
195 Dwarf_Off cu_offs; 171 size_t nfiles, i;
172 const char *src = NULL;
196 int ret; 173 int ret;
197 174
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 175 if (!fname)
199 DIE_IF(ret != DW_DLV_OK); 176 return NULL;
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 177
201 DIE_IF(ret != DW_DLV_OK); 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 179 if (ret != 0)
203 return cu_offs; 180 return NULL;
181
182 for (i = 0; i < nfiles; i++) {
183 src = dwarf_filesrc(files, i, NULL, NULL);
184 if (strtailcmp(src, fname) == 0)
185 break;
186 }
187 return src;
204} 188}
205 189
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 190struct __addr_die_search_param {
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
208{ 196{
209 Dwarf_Attribute attr; 197 struct __addr_die_search_param *ad = data;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215 198
216 /* Try to get entry pc */ 199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 200 dwarf_haspc(fn_die, ad->addr)) {
218 DIE_IF(ret == DW_DLV_ERROR); 201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
219 if (ret == DW_DLV_OK) { 202 return DWARF_CB_ABORT;
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
221 DIE_IF(ret != DW_DLV_OK);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 } 203 }
204 return DWARF_CB_OK;
205}
225 206
226 /* Try to get low pc */ 207/* Search a real subprogram including this line, */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
228 DIE_IF(ret == DW_DLV_ERROR); 209 Dwarf_Die *die_mem)
229 if (ret == DW_DLV_OK) 210{
230 return addr; 211 struct __addr_die_search_param ad;
231 212 ad.addr = addr;
232 /* Try to get ranges */ 213 ad.die_mem = die_mem;
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); 214 /* dwarf_getscopes can't find subprogram. */
234 DIE_IF(ret != DW_DLV_OK); 215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
235 ret = dwarf_formref(attr, &offs, &__dw_error); 216 return NULL;
236 DIE_IF(ret != DW_DLV_OK); 217 else
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, 218 return die_mem;
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243} 219}
244 220
245/* 221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
246 * Search a Die from Die tree. 222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
247 * Note: cur_link->die should be deallocated in this function. 223 Dwarf_Die *die_mem)
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{ 224{
253 Dwarf_Die new_die; 225 Dwarf_Die child_die;
254 struct die_link new_link;
255 int ret; 226 int ret;
256 227
257 if (!die_cb) 228 ret = dwarf_child(sp_die, die_mem);
258 return 0; 229 if (ret != 0)
259 230 return NULL;
260 /* Check current die */
261 while (!(ret = die_cb(cur_link, data))) {
262 /* Check child die */
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
264 DIE_IF(ret == DW_DLV_ERROR);
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 }
272 231
273 /* Move to next sibling */ 232 do {
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
275 &__dw_error); 234 dwarf_haspc(die_mem, addr))
276 DIE_IF(ret == DW_DLV_ERROR); 235 return die_mem;
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284}
285 236
286/* Search a die in its children's die tree */ 237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
287static int search_die_from_children(Dwarf_Die parent_die, 238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
288 int (*die_cb)(struct die_link *, void *), 239 return die_mem;
289 void *data) 240 }
290{ 241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
291 struct die_link new_link;
292 int ret;
293 242
294 new_link.parent = NULL; 243 return NULL;
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
296 DIE_IF(ret == DW_DLV_ERROR);
297 if (ret == DW_DLV_OK)
298 return __search_die_tree(&new_link, die_cb, data);
299 else
300 return 0;
301} 244}
302 245
303/* Find a locdesc corresponding to the address */ 246/* Compare diename and tname */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
305 Dwarf_Addr addr)
306{ 248{
307 Dwarf_Signed lcnt; 249 const char *name;
308 Dwarf_Locdesc **llbuf; 250 name = dwarf_diename(dw_die);
309 int ret, i; 251 DIE_IF(name == NULL);
310 252 return strcmp(tname, name);
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
312 DIE_IF(ret != DW_DLV_OK);
313 ret = DW_DLV_NO_ENTRY;
314 for (i = 0; i < lcnt; ++i) {
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336} 253}
337 254
338/* Get decl_file attribute value (file number) */ 255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
340{ 257{
341 Dwarf_Attribute attr; 258 Dwarf_Addr epc;
342 Dwarf_Unsigned fno;
343 int ret; 259 int ret;
344 260
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 261 ret = dwarf_entrypc(dw_die, &epc);
346 DIE_IF(ret != DW_DLV_OK); 262 DIE_IF(ret == -1);
347 dwarf_formudata(attr, &fno, &__dw_error); 263 return epc;
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351} 264}
352 265
353/* Get decl_line attribute value (line number) */ 266/* Get a variable die */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
355{ 269{
356 Dwarf_Attribute attr; 270 Dwarf_Die child_die;
357 Dwarf_Unsigned lno; 271 int tag;
358 int ret; 272 int ret;
359 273
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 274 ret = dwarf_child(sp_die, die_mem);
361 DIE_IF(ret != DW_DLV_OK); 275 if (ret != 0)
362 dwarf_formudata(attr, &lno, &__dw_error); 276 return NULL;
363 DIE_IF(ret != DW_DLV_OK); 277
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 278 do {
365 return lno; 279 tag = dwarf_tag(die_mem);
280 if ((tag == DW_TAG_formal_parameter ||
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284
285 if (die_find_variable(die_mem, name, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290
291 return NULL;
366} 292}
367 293
368/* 294/*
@@ -370,47 +296,45 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
370 */ 296 */
371 297
372/* Show a location */ 298/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
374{ 300{
375 Dwarf_Small op; 301 unsigned int regn;
376 Dwarf_Unsigned regn; 302 Dwarf_Word offs = 0;
377 Dwarf_Signed offs;
378 int deref = 0, ret; 303 int deref = 0, ret;
379 const char *regs; 304 const char *regs;
380 305
381 op = loc->lr_atom; 306 /* TODO: support CFA */
382
383 /* If this is based on frame buffer, set the offset */ 307 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
385 deref = 1; 311 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number; 312 offs = op->number;
387 op = pf->fbloc.ld_s[0].lr_atom; 313 op = &pf->fb_ops[0];
388 loc = &pf->fbloc.ld_s[0]; 314 }
389 } else
390 offs = 0;
391 315
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0; 317 regn = op->atom - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number; 318 offs += op->number;
395 deref = 1; 319 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0; 321 regn = op->atom - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) { 322 } else if (op->atom == DW_OP_bregx) {
399 regn = loc->lr_number; 323 regn = op->number;
400 offs += (Dwarf_Signed)loc->lr_number2; 324 offs += op->number2;
401 deref = 1; 325 deref = 1;
402 } else if (op == DW_OP_regx) { 326 } else if (op->atom == DW_OP_regx) {
403 regn = loc->lr_number; 327 regn = op->number;
404 } else 328 } else
405 die("Dwarf_OP %d is not supported.\n", op); 329 die("DW_OP %d is not supported.", op->atom);
406 330
407 regs = get_arch_regstr(regn); 331 regs = get_arch_regstr(regn);
408 if (!regs) 332 if (!regs)
409 die("%lld exceeds max register number.\n", regn); 333 die("%u exceeds max register number.", regn);
410 334
411 if (deref) 335 if (deref)
412 ret = snprintf(pf->buf, pf->len, 336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
413 " %s=%+lld(%s)", pf->var, offs, regs); 337 pf->var, (intmax_t)offs, regs);
414 else 338 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
416 DIE_IF(ret < 0); 340 DIE_IF(ret < 0);
@@ -418,52 +342,36 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
418} 342}
419 343
420/* Show a variables in kprobe event format */ 344/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
422{ 346{
423 Dwarf_Attribute attr; 347 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld; 348 Dwarf_Op *expr;
349 size_t nexpr;
425 int ret; 350 int ret;
426 351
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
428 if (ret != DW_DLV_OK)
429 goto error; 353 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 354 /* TODO: handle more than 1 exprs */
431 if (ret != DW_DLV_OK) 355 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
356 if (ret <= 0 || nexpr == 0)
432 goto error; 357 goto error;
433 /* TODO? */ 358
434 DIE_IF(ld.ld_cents != 1); 359 show_location(expr, pf);
435 show_location(&ld.ld_s[0], pf); 360 /* *expr will be cached in libdw. Don't free it. */
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ; 361 return ;
439error: 362error:
363 /* TODO: Support const_value */
440 die("Failed to find the location of %s at this address.\n" 364 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var); 365 " Perhaps, it has been optimized out.", pf->var);
442}
443
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
451 DIE_IF(ret == DW_DLV_ERROR);
452 if ((tag == DW_TAG_formal_parameter ||
453 tag == DW_TAG_variable) &&
454 (die_compare_name(dlink->die, pf->var) == 0)) {
455 show_variable(dlink->die, pf);
456 return 1;
457 }
458 /* TODO: Support struct members and arrays */
459 return 0;
460} 366}
461 367
462/* Find a variable in a subprogram die */ 368/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 369static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
464{ 370{
465 int ret; 371 int ret;
372 Dwarf_Die vr_die;
466 373
374 /* TODO: Support struct members and arrays */
467 if (!is_c_varname(pf->var)) { 375 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */ 376 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 377 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -474,58 +382,51 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
474 382
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 383 pr_debug("Searching '%s' variable in context.\n", pf->var);
476 /* Search child die for local variables and parameters. */ 384 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf); 385 if (!die_find_variable(sp_die, pf->var, &vr_die))
478 if (!ret) 386 die("Failed to find '%s' in this function.", pf->var);
479 die("Failed to find '%s' in this function.\n", pf->var);
480}
481 387
482/* Get a frame base on the address */ 388 show_variable(&vr_die, pf);
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
484{
485 Dwarf_Attribute attr;
486 int ret;
487
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
489 DIE_IF(ret != DW_DLV_OK);
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
491 DIE_IF(ret != DW_DLV_OK);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
493}
494
495static void free_current_frame_base(struct probe_finder *pf)
496{
497 free(pf->fbloc.ld_s);
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
499} 389}
500 390
501/* Show a probe point to output buffer */ 391/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 392static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
503 struct probe_finder *pf)
504{ 393{
505 struct probe_point *pp = pf->pp; 394 struct probe_point *pp = pf->pp;
506 char *name; 395 Dwarf_Addr eaddr;
396 Dwarf_Die die_mem;
397 const char *name;
507 char tmp[MAX_PROBE_BUFFER]; 398 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len; 399 int ret, i, len;
400 Dwarf_Attribute fb_attr;
401 size_t nops;
402
403 /* If no real subprogram, find a real one */
404 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
405 sp_die = die_get_real_subprogram(&pf->cu_die,
406 pf->addr, &die_mem);
407 if (!sp_die)
408 die("Probe point is not found in subprograms.");
409 }
509 410
510 /* Output name of probe point */ 411 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 412 name = dwarf_diename(sp_die);
512 DIE_IF(ret == DW_DLV_ERROR); 413 if (name) {
513 if (ret == DW_DLV_OK) { 414 dwarf_entrypc(sp_die, &eaddr);
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 415 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
515 (unsigned int)offs); 416 (unsigned long)(pf->addr - eaddr));
516 /* Copy the function name if possible */ 417 /* Copy the function name if possible */
517 if (!pp->function) { 418 if (!pp->function) {
518 pp->function = strdup(name); 419 pp->function = strdup(name);
519 pp->offset = offs; 420 pp->offset = (size_t)(pf->addr - eaddr);
520 } 421 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else { 422 } else {
523 /* This function has no name. */ 423 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 424 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
425 (uintmax_t)pf->addr);
525 if (!pp->function) { 426 if (!pp->function) {
526 /* TODO: Use _stext */ 427 /* TODO: Use _stext */
527 pp->function = strdup(""); 428 pp->function = strdup("");
528 pp->offset = (int)pf->addr; 429 pp->offset = (size_t)pf->addr;
529 } 430 }
530 } 431 }
531 DIE_IF(ret < 0); 432 DIE_IF(ret < 0);
@@ -533,8 +434,14 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
533 len = ret; 434 len = ret;
534 pr_debug("Probe point found: %s\n", tmp); 435 pr_debug("Probe point found: %s\n", tmp);
535 436
437 /* Get the frame base attribute/ops */
438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
439 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
440 if (ret <= 0 || nops == 0)
441 pf->fb_ops = NULL;
442
536 /* Find each argument */ 443 /* Find each argument */
537 get_current_frame_base(sp_die, pf); 444 /* TODO: use dwarf_cfi_addrframe */
538 for (i = 0; i < pp->nr_args; i++) { 445 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i]; 446 pf->var = pp->args[i];
540 pf->buf = &tmp[len]; 447 pf->buf = &tmp[len];
@@ -542,189 +449,381 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
542 find_variable(sp_die, pf); 449 find_variable(sp_die, pf);
543 len += strlen(pf->buf); 450 len += strlen(pf->buf);
544 } 451 }
545 free_current_frame_base(pf); 452
453 /* *pf->fb_ops will be cached in libdw. Don't free it. */
454 pf->fb_ops = NULL;
455
456 if (pp->found == MAX_PROBES)
457 die("Too many( > %d) probe point found.\n", MAX_PROBES);
546 458
547 pp->probes[pp->found] = strdup(tmp); 459 pp->probes[pp->found] = strdup(tmp);
548 pp->found++; 460 pp->found++;
549} 461}
550 462
551static int probeaddr_callback(struct die_link *dlink, void *data) 463/* Find probe point from its line number */
464static void find_probe_point_by_line(struct probe_finder *pf)
552{ 465{
553 struct probe_finder *pf = (struct probe_finder *)data; 466 Dwarf_Lines *lines;
554 Dwarf_Half tag; 467 Dwarf_Line *line;
555 Dwarf_Signed offs; 468 size_t nlines, i;
469 Dwarf_Addr addr;
470 int lineno;
556 int ret; 471 int ret;
557 472
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 473 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
559 DIE_IF(ret == DW_DLV_ERROR); 474 DIE_IF(ret != 0);
560 /* Check the address is in this subprogram */ 475
561 if (tag == DW_TAG_subprogram && 476 for (i = 0; i < nlines; i++) {
562 die_within_subprogram(dlink->die, pf->addr, &offs)) { 477 line = dwarf_onesrcline(lines, i);
563 show_probepoint(dlink->die, offs, pf); 478 dwarf_lineno(line, &lineno);
564 return 1; 479 if (lineno != pf->lno)
480 continue;
481
482 /* TODO: Get fileno from line, but how? */
483 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
484 continue;
485
486 ret = dwarf_lineaddr(line, &addr);
487 DIE_IF(ret != 0);
488 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
489 (int)i, lineno, (uintmax_t)addr);
490 pf->addr = addr;
491
492 show_probe_point(NULL, pf);
493 /* Continuing, because target line might be inlined. */
565 } 494 }
566 return 0;
567} 495}
568 496
569/* Find probe point from its line number */ 497/* Find lines which match lazy pattern */
570static void find_by_line(struct probe_finder *pf) 498static int find_lazy_match_lines(struct list_head *head,
499 const char *fname, const char *pat)
500{
501 char *fbuf, *p1, *p2;
502 int fd, line, nlines = 0;
503 struct stat st;
504
505 fd = open(fname, O_RDONLY);
506 if (fd < 0)
507 die("failed to open %s", fname);
508 DIE_IF(fstat(fd, &st) < 0);
509 fbuf = malloc(st.st_size + 2);
510 DIE_IF(fbuf == NULL);
511 DIE_IF(read(fd, fbuf, st.st_size) < 0);
512 close(fd);
513 fbuf[st.st_size] = '\n'; /* Dummy line */
514 fbuf[st.st_size + 1] = '\0';
515 p1 = fbuf;
516 line = 1;
517 while ((p2 = strchr(p1, '\n')) != NULL) {
518 *p2 = '\0';
519 if (strlazymatch(p1, pat)) {
520 line_list__add_line(head, line);
521 nlines++;
522 }
523 line++;
524 p1 = p2 + 1;
525 }
526 free(fbuf);
527 return nlines;
528}
529
530/* Find probe points from lazy pattern */
531static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
571{ 532{
572 Dwarf_Signed cnt, i, clm; 533 Dwarf_Lines *lines;
573 Dwarf_Line *lines; 534 Dwarf_Line *line;
574 Dwarf_Unsigned lineno = 0; 535 size_t nlines, i;
575 Dwarf_Addr addr; 536 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 537 Dwarf_Die die_mem;
538 int lineno;
577 int ret; 539 int ret;
578 540
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 541 if (list_empty(&pf->lcache)) {
580 DIE_IF(ret != DW_DLV_OK); 542 /* Matching lazy line pattern */
543 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
544 pf->pp->lazy_line);
545 if (ret <= 0)
546 die("No matched lines found in %s.", pf->fname);
547 }
548
549 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
550 DIE_IF(ret != 0);
551 for (i = 0; i < nlines; i++) {
552 line = dwarf_onesrcline(lines, i);
581 553
582 for (i = 0; i < cnt; i++) { 554 dwarf_lineno(line, &lineno);
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 555 if (!line_list__has_line(&pf->lcache, lineno))
584 DIE_IF(ret != DW_DLV_OK);
585 if (fno != pf->fno)
586 continue; 556 continue;
587 557
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 558 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 559 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 560 continue;
592 561
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 562 ret = dwarf_lineaddr(line, &addr);
594 DIE_IF(ret != DW_DLV_OK); 563 DIE_IF(ret != 0);
564 if (sp_die) {
565 /* Address filtering 1: does sp_die include addr? */
566 if (!dwarf_haspc(sp_die, addr))
567 continue;
568 /* Address filtering 2: No child include addr? */
569 if (die_get_inlinefunc(sp_die, addr, &die_mem))
570 continue;
571 }
595 572
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 573 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
597 DIE_IF(ret != DW_DLV_OK); 574 (int)i, lineno, (unsigned long long)addr);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr; 575 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 576
602 ret = search_die_from_children(pf->cu_die, 577 show_probe_point(sp_die, pf);
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */ 578 /* Continuing, because target line might be inlined. */
607 } 579 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 580 /* TODO: deallocate lines, but how? */
581}
582
583static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
584{
585 struct probe_finder *pf = (struct probe_finder *)data;
586 struct probe_point *pp = pf->pp;
587
588 if (pp->lazy_line)
589 find_probe_point_lazy(in_die, pf);
590 else {
591 /* Get probe address */
592 pf->addr = die_get_entrypc(in_die);
593 pf->addr += pp->offset;
594 pr_debug("found inline addr: 0x%jx\n",
595 (uintmax_t)pf->addr);
596
597 show_probe_point(in_die, pf);
598 }
599
600 return DWARF_CB_OK;
609} 601}
610 602
611/* Search function from function name */ 603/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data) 604static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
613{ 605{
614 struct probe_finder *pf = (struct probe_finder *)data; 606 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp; 607 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620 608
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 609 /* Check tag and diename */
622 DIE_IF(ret == DW_DLV_ERROR); 610 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
623 if (tag == DW_TAG_subprogram) { 611 die_compare_name(sp_die, pp->function) != 0)
624 if (die_compare_name(dlink->die, pp->function) == 0) { 612 return 0;
625 if (pp->line) { /* Function relative line */ 613
626 pf->fno = die_get_decl_file(dlink->die); 614 pf->fname = dwarf_decl_file(sp_die);
627 pf->lno = die_get_decl_line(dlink->die) 615 if (pp->line) { /* Function relative line */
628 + pp->line; 616 dwarf_decl_line(sp_die, &pf->lno);
629 find_by_line(pf); 617 pf->lno += pp->line;
630 return 1; 618 find_probe_point_by_line(pf);
631 } 619 } else if (!dwarf_func_inline(sp_die)) {
632 if (die_inlined_subprogram(dlink->die)) { 620 /* Real function */
633 /* Inlined function, save it. */ 621 if (pp->lazy_line)
634 ret = dwarf_die_CU_offset(dlink->die, 622 find_probe_point_lazy(sp_die, pf);
635 &pf->inl_offs, 623 else {
636 &__dw_error); 624 pf->addr = die_get_entrypc(sp_die);
637 DIE_IF(ret != DW_DLV_OK);
638 pr_debug("inline definition offset %lld\n",
639 pf->inl_offs);
640 return 0; /* Continue to search */
641 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 625 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 626 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 627 show_probe_point(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
651 /* Get probe address */
652 pf->addr = die_get_entrypc(dlink->die);
653 pf->addr += pp->offset;
654 pr_debug("found inline addr: 0x%llx\n", pf->addr);
655 /* Inlined function. Get a real subprogram */
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
657 tag = 0;
658 dwarf_tag(lk->die, &tag, &__dw_error);
659 DIE_IF(ret == DW_DLV_ERROR);
660 if (tag == DW_TAG_subprogram &&
661 !die_inlined_subprogram(lk->die))
662 goto found;
663 }
664 die("Failed to find real subprogram.\n");
665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
668 DIE_IF(!ret);
669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 } 628 }
672 } 629 } else
673 return 0; 630 /* Inlined function: search instances */
631 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
632
633 return 1; /* Exit; no same symbol in this CU. */
674} 634}
675 635
676static void find_by_func(struct probe_finder *pf) 636static void find_probe_point_by_func(struct probe_finder *pf)
677{ 637{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 638 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
679} 639}
680 640
681/* Find a probe point */ 641/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp) 642int find_probe_point(int fd, struct probe_point *pp)
683{ 643{
684 Dwarf_Half addr_size = 0;
685 Dwarf_Unsigned next_cuh = 0;
686 int cu_number = 0, ret;
687 struct probe_finder pf = {.pp = pp}; 644 struct probe_finder pf = {.pp = pp};
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
688 649
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 650 dbg = dwarf_begin(fd, DWARF_C_READ);
690 if (ret != DW_DLV_OK) 651 if (!dbg)
691 return -ENOENT; 652 return -ENOENT;
692 653
693 pp->found = 0; 654 pp->found = 0;
694 while (++cu_number) { 655 off = 0;
695 /* Search CU (Compilation Unit) */ 656 line_list__init(&pf.lcache);
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 657 /* Loop on CUs (Compilation Unit) */
697 &addr_size, &next_cuh, &__dw_error); 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
698 DIE_IF(ret == DW_DLV_ERROR);
699 if (ret == DW_DLV_NO_ENTRY)
700 break;
701
702 /* Get the DIE(Debugging Information Entry) of this CU */ 659 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
704 DIE_IF(ret != DW_DLV_OK); 661 if (!diep)
662 continue;
705 663
706 /* Check if target file is included. */ 664 /* Check if target file is included. */
707 if (pp->file) 665 if (pp->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
709 667 else
710 if (!pp->file || pf.fno) { 668 pf.fname = NULL;
711 /* Save CU base address (for frame_base) */ 669
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 670 if (!pp->file || pf.fname) {
713 DIE_IF(ret == DW_DLV_ERROR);
714 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0;
716 if (pp->function) 671 if (pp->function)
717 find_by_func(&pf); 672 find_probe_point_by_func(&pf);
673 else if (pp->lazy_line)
674 find_probe_point_lazy(NULL, &pf);
718 else { 675 else {
719 pf.lno = pp->line; 676 pf.lno = pp->line;
720 find_by_line(&pf); 677 find_probe_point_by_line(&pf);
721 } 678 }
722 } 679 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 680 off = noff;
724 } 681 }
725 ret = dwarf_finish(__dw_debug, &__dw_error); 682 line_list__free(&pf.lcache);
726 DIE_IF(ret != DW_DLV_OK); 683 dwarf_end(dbg);
727 684
728 return pp->found; 685 return pp->found;
729} 686}
730 687
688/* Find line range from its line number */
689static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
690{
691 Dwarf_Lines *lines;
692 Dwarf_Line *line;
693 size_t nlines, i;
694 Dwarf_Addr addr;
695 int lineno;
696 int ret;
697 const char *src;
698 Dwarf_Die die_mem;
699
700 line_list__init(&lf->lr->line_list);
701 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
702 DIE_IF(ret != 0);
703
704 for (i = 0; i < nlines; i++) {
705 line = dwarf_onesrcline(lines, i);
706 ret = dwarf_lineno(line, &lineno);
707 DIE_IF(ret != 0);
708 if (lf->lno_s > lineno || lf->lno_e < lineno)
709 continue;
710
711 if (sp_die) {
712 /* Address filtering 1: does sp_die include addr? */
713 ret = dwarf_lineaddr(line, &addr);
714 DIE_IF(ret != 0);
715 if (!dwarf_haspc(sp_die, addr))
716 continue;
717
718 /* Address filtering 2: No child include addr? */
719 if (die_get_inlinefunc(sp_die, addr, &die_mem))
720 continue;
721 }
722
723 /* TODO: Get fileno from line, but how? */
724 src = dwarf_linesrc(line, NULL, NULL);
725 if (strtailcmp(src, lf->fname) != 0)
726 continue;
727
728 /* Copy real path */
729 if (!lf->lr->path)
730 lf->lr->path = strdup(src);
731 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
732 }
733 /* Update status */
734 if (!list_empty(&lf->lr->line_list))
735 lf->found = 1;
736 else {
737 free(lf->lr->path);
738 lf->lr->path = NULL;
739 }
740}
741
742static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
743{
744 find_line_range_by_line(in_die, (struct line_finder *)data);
745 return DWARF_CB_ABORT; /* No need to find other instances */
746}
747
748/* Search function from function name */
749static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
750{
751 struct line_finder *lf = (struct line_finder *)data;
752 struct line_range *lr = lf->lr;
753
754 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
755 die_compare_name(sp_die, lr->function) == 0) {
756 lf->fname = dwarf_decl_file(sp_die);
757 dwarf_decl_line(sp_die, &lr->offset);
758 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
759 lf->lno_s = lr->offset + lr->start;
760 if (!lr->end)
761 lf->lno_e = INT_MAX;
762 else
763 lf->lno_e = lr->offset + lr->end;
764 lr->start = lf->lno_s;
765 lr->end = lf->lno_e;
766 if (dwarf_func_inline(sp_die))
767 dwarf_func_inline_instances(sp_die,
768 line_range_inline_cb, lf);
769 else
770 find_line_range_by_line(sp_die, lf);
771 return 1;
772 }
773 return 0;
774}
775
776static void find_line_range_by_func(struct line_finder *lf)
777{
778 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
779}
780
781int find_line_range(int fd, struct line_range *lr)
782{
783 struct line_finder lf = {.lr = lr, .found = 0};
784 int ret;
785 Dwarf_Off off = 0, noff;
786 size_t cuhl;
787 Dwarf_Die *diep;
788 Dwarf *dbg;
789
790 dbg = dwarf_begin(fd, DWARF_C_READ);
791 if (!dbg)
792 return -ENOENT;
793
794 /* Loop on CUs (Compilation Unit) */
795 while (!lf.found) {
796 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
797 if (ret != 0)
798 break;
799
800 /* Get the DIE(Debugging Information Entry) of this CU */
801 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
802 if (!diep)
803 continue;
804
805 /* Check if target file is included. */
806 if (lr->file)
807 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
808 else
809 lf.fname = 0;
810
811 if (!lr->file || lf.fname) {
812 if (lr->function)
813 find_line_range_by_func(&lf);
814 else {
815 lf.lno_s = lr->start;
816 if (!lr->end)
817 lf.lno_e = INT_MAX;
818 else
819 lf.lno_e = lr->end;
820 find_line_range_by_line(NULL, &lf);
821 }
822 }
823 off = noff;
824 }
825 pr_debug("path: %lx\n", (unsigned long)lr->path);
826 dwarf_end(dbg);
827 return lf.found;
828}
829
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..21f7354397b4 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +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#include <stdbool.h>
5#include "util.h"
6
4#define MAX_PATH_LEN 256 7#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 9#define MAX_PROBES 128
@@ -18,6 +21,7 @@ struct probe_point {
18 /* Inputs */ 21 /* Inputs */
19 char *file; /* File name */ 22 char *file; /* File name */
20 int line; /* Line number */ 23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
21 25
22 char *function; /* Function name */ 26 char *function; /* Function name */
23 int offset; /* Offset bytes */ 27 int offset; /* Offset bytes */
@@ -32,34 +36,57 @@ struct probe_point {
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 36 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33}; 37};
34 38
35#ifndef NO_LIBDWARF 39/* Line number container */
36extern int find_probepoint(int fd, struct probe_point *pp); 40struct line_node {
41 struct list_head list;
42 unsigned int line;
43};
44
45/* Line range */
46struct line_range {
47 char *file; /* File name */
48 char *function; /* Function name */
49 unsigned int start; /* Start line number */
50 unsigned int end; /* End line number */
51 int offset; /* Start line offset */
52 char *path; /* Real path name */
53 struct list_head line_list; /* Visible lines */
54};
37 55
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ 56#ifndef NO_DWARF_SUPPORT
39#ifndef _MIPS_SZLONG 57extern int find_probe_point(int fd, struct probe_point *pp);
40# define _MIPS_SZLONG 0 58extern int find_line_range(int fd, struct line_range *lr);
41#endif
42 59
43#include <dwarf.h> 60#include <dwarf.h>
44#include <libdwarf.h> 61#include <libdw.h>
45 62
46struct probe_finder { 63struct probe_finder {
47 struct probe_point *pp; /* Target probe point */ 64 struct probe_point *pp; /* Target probe point */
48 65
49 /* For function searching */ 66 /* For function searching */
50 Dwarf_Addr addr; /* Address */ 67 Dwarf_Addr addr; /* Address */
51 Dwarf_Unsigned fno; /* File number */ 68 const char *fname; /* File name */
52 Dwarf_Unsigned lno; /* Line number */ 69 int lno; /* Line number */
53 Dwarf_Off inl_offs; /* Inline offset */ 70 Dwarf_Die cu_die; /* Current CU */
54 Dwarf_Die cu_die; /* Current CU */
55 71
56 /* For variable searching */ 72 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */ 73 Dwarf_Op *fb_ops; /* Frame base attribute */
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 74 const char *var; /* Current variable name */
59 const char *var; /* Current variable name */ 75 char *buf; /* Current output buffer */
60 char *buf; /* Current output buffer */ 76 int len; /* Length of output buffer */
61 int len; /* Length of output buffer */ 77 struct list_head lcache; /* Line cache for lazy match */
62}; 78};
63#endif /* NO_LIBDWARF */ 79
80struct line_finder {
81 struct line_range *lr; /* Target line range */
82
83 const char *fname; /* File name */
84 int lno_s; /* Start line number */
85 int lno_e; /* End line number */
86 Dwarf_Die cu_die; /* Current CU */
87 int found;
88};
89
90#endif /* NO_DWARF_SUPPORT */
64 91
65#endif /*_PROBE_FINDER_H */ 92#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 6d6d76b8a21e..5376378e0cfc 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,10 +25,16 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../perf.h" 28#include "../../perf.h"
29#include "util.h" 29#include "../util.h"
30#include "trace-event.h" 30#include "../trace-event.h"
31#include "trace-event-perl.h" 31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
32 38
33void xs_init(pTHX); 39void xs_init(pTHX);
34 40
@@ -49,7 +55,7 @@ INTERP my_perl;
49 55
50struct event *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
51 57
52static struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
53 59
54static char *cur_field_name; 60static char *cur_field_name;
55static int zero_flag_atom; 61static int zero_flag_atom;
@@ -239,33 +245,6 @@ static inline struct event *find_cache_event(int type)
239 return event; 245 return event;
240} 246}
241 247
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data, 248static void perl_process_event(int cpu, void *data,
270 int size __unused, 249 int size __unused,
271 unsigned long long nsecs, char *comm) 250 unsigned long long nsecs, char *comm)
@@ -587,75 +566,3 @@ struct scripting_ops perl_scripting_ops = {
587 .process_event = perl_process_event, 566 .process_event = perl_process_event,
588 .generate_script = perl_generate_script, 567 .generate_script = perl_generate_script,
589}; 568};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
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)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
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}
661#endif
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..6a72f14c5986
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,580 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t, *obj;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 s = nsecs / NSECS_PER_SEC;
236 ns = nsecs - s * NSECS_PER_SEC;
237
238 scripting_context->event_data = data;
239
240 context = PyCObject_FromVoidPtr(scripting_context, NULL);
241
242 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
243 PyTuple_SetItem(t, n++,
244 PyCObject_FromVoidPtr(scripting_context, NULL));
245 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
246 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
247 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
248 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
249 PyTuple_SetItem(t, n++, PyString_FromString(comm));
250
251 for (field = event->format.fields; field; field = field->next) {
252 if (field->flags & FIELD_IS_STRING) {
253 int offset;
254 if (field->flags & FIELD_IS_DYNAMIC) {
255 offset = *(int *)(data + field->offset);
256 offset &= 0xffff;
257 } else
258 offset = field->offset;
259 obj = PyString_FromString((char *)data + offset);
260 } else { /* FIELD_IS_NUMERIC */
261 val = read_size(data + field->offset, field->size);
262 if (field->flags & FIELD_IS_SIGNED) {
263 if ((long long)val >= LONG_MIN &&
264 (long long)val <= LONG_MAX)
265 obj = PyInt_FromLong(val);
266 else
267 obj = PyLong_FromLongLong(val);
268 } else {
269 if (val <= LONG_MAX)
270 obj = PyInt_FromLong(val);
271 else
272 obj = PyLong_FromUnsignedLongLong(val);
273 }
274 }
275 PyTuple_SetItem(t, n++, obj);
276 }
277
278 if (_PyTuple_Resize(&t, n) == -1)
279 Py_FatalError("error resizing Python tuple");
280
281 handler = PyDict_GetItemString(main_dict, handler_name);
282 if (handler && PyCallable_Check(handler)) {
283 retval = PyObject_CallObject(handler, t);
284 if (retval == NULL)
285 handler_call_die(handler_name);
286 } else {
287 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
288 if (handler && PyCallable_Check(handler)) {
289 if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1)
290 Py_FatalError("error resizing Python tuple");
291
292 retval = PyObject_CallObject(handler, t);
293 if (retval == NULL)
294 handler_call_die("trace_unhandled");
295 }
296 }
297
298 Py_DECREF(t);
299}
300
301static int run_start_sub(void)
302{
303 PyObject *handler, *retval;
304 int err = 0;
305
306 main_module = PyImport_AddModule("__main__");
307 if (main_module == NULL)
308 return -1;
309 Py_INCREF(main_module);
310
311 main_dict = PyModule_GetDict(main_module);
312 if (main_dict == NULL) {
313 err = -1;
314 goto error;
315 }
316 Py_INCREF(main_dict);
317
318 handler = PyDict_GetItemString(main_dict, "trace_begin");
319 if (handler == NULL || !PyCallable_Check(handler))
320 goto out;
321
322 retval = PyObject_CallObject(handler, NULL);
323 if (retval == NULL)
324 handler_call_die("trace_begin");
325
326 Py_DECREF(retval);
327 return err;
328error:
329 Py_XDECREF(main_dict);
330 Py_XDECREF(main_module);
331out:
332 return err;
333}
334
335/*
336 * Start trace script
337 */
338static int python_start_script(const char *script, int argc, const char **argv)
339{
340 const char **command_line;
341 char buf[PATH_MAX];
342 int i, err = 0;
343 FILE *fp;
344
345 command_line = malloc((argc + 1) * sizeof(const char *));
346 command_line[0] = script;
347 for (i = 1; i < argc + 1; i++)
348 command_line[i] = argv[i - 1];
349
350 Py_Initialize();
351
352 initperf_trace_context();
353
354 PySys_SetArgv(argc + 1, (char **)command_line);
355
356 fp = fopen(script, "r");
357 if (!fp) {
358 sprintf(buf, "Can't open python script \"%s\"", script);
359 perror(buf);
360 err = -1;
361 goto error;
362 }
363
364 err = PyRun_SimpleFile(fp, script);
365 if (err) {
366 fprintf(stderr, "Error running python script %s\n", script);
367 goto error;
368 }
369
370 err = run_start_sub();
371 if (err) {
372 fprintf(stderr, "Error starting python script %s\n", script);
373 goto error;
374 }
375
376 free(command_line);
377 fprintf(stderr, "perf trace started with Python script %s\n\n",
378 script);
379
380 return err;
381error:
382 Py_Finalize();
383 free(command_line);
384
385 return err;
386}
387
388/*
389 * Stop trace script
390 */
391static int python_stop_script(void)
392{
393 PyObject *handler, *retval;
394 int err = 0;
395
396 handler = PyDict_GetItemString(main_dict, "trace_end");
397 if (handler == NULL || !PyCallable_Check(handler))
398 goto out;
399
400 retval = PyObject_CallObject(handler, NULL);
401 if (retval == NULL)
402 handler_call_die("trace_end");
403 else
404 Py_DECREF(retval);
405out:
406 Py_XDECREF(main_dict);
407 Py_XDECREF(main_module);
408 Py_Finalize();
409
410 fprintf(stderr, "\nperf trace Python script stopped\n");
411
412 return err;
413}
414
415static int python_generate_script(const char *outfile)
416{
417 struct event *event = NULL;
418 struct format_field *f;
419 char fname[PATH_MAX];
420 int not_first, count;
421 FILE *ofp;
422
423 sprintf(fname, "%s.py", outfile);
424 ofp = fopen(fname, "w");
425 if (ofp == NULL) {
426 fprintf(stderr, "couldn't open %s\n", fname);
427 return -1;
428 }
429 fprintf(ofp, "# perf trace event handlers, "
430 "generated by perf trace -g python\n");
431
432 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
433 " License version 2\n\n");
434
435 fprintf(ofp, "# The common_* event handler fields are the most useful "
436 "fields common to\n");
437
438 fprintf(ofp, "# all events. They don't necessarily correspond to "
439 "the 'common_*' fields\n");
440
441 fprintf(ofp, "# in the format files. Those fields not available as "
442 "handler params can\n");
443
444 fprintf(ofp, "# be retrieved using Python functions of the form "
445 "common_*(context).\n");
446
447 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
448 "of available functions.\n\n");
449
450 fprintf(ofp, "import os\n");
451 fprintf(ofp, "import sys\n\n");
452
453 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
454 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
455 fprintf(ofp, "\nfrom perf_trace_context import *\n");
456 fprintf(ofp, "from Core import *\n\n\n");
457
458 fprintf(ofp, "def trace_begin():\n");
459 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
460
461 fprintf(ofp, "def trace_end():\n");
462 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
463
464 while ((event = trace_find_next_event(event))) {
465 fprintf(ofp, "def %s__%s(", event->system, event->name);
466 fprintf(ofp, "event_name, ");
467 fprintf(ofp, "context, ");
468 fprintf(ofp, "common_cpu,\n");
469 fprintf(ofp, "\tcommon_secs, ");
470 fprintf(ofp, "common_nsecs, ");
471 fprintf(ofp, "common_pid, ");
472 fprintf(ofp, "common_comm,\n\t");
473
474 not_first = 0;
475 count = 0;
476
477 for (f = event->format.fields; f; f = f->next) {
478 if (not_first++)
479 fprintf(ofp, ", ");
480 if (++count % 5 == 0)
481 fprintf(ofp, "\n\t");
482
483 fprintf(ofp, "%s", f->name);
484 }
485 fprintf(ofp, "):\n");
486
487 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
488 "common_secs, common_nsecs,\n\t\t\t"
489 "common_pid, common_comm)\n\n");
490
491 fprintf(ofp, "\t\tprint \"");
492
493 not_first = 0;
494 count = 0;
495
496 for (f = event->format.fields; f; f = f->next) {
497 if (not_first++)
498 fprintf(ofp, ", ");
499 if (count && count % 3 == 0) {
500 fprintf(ofp, "\" \\\n\t\t\"");
501 }
502 count++;
503
504 fprintf(ofp, "%s=", f->name);
505 if (f->flags & FIELD_IS_STRING ||
506 f->flags & FIELD_IS_FLAG ||
507 f->flags & FIELD_IS_SYMBOLIC)
508 fprintf(ofp, "%%s");
509 else if (f->flags & FIELD_IS_SIGNED)
510 fprintf(ofp, "%%d");
511 else
512 fprintf(ofp, "%%u");
513 }
514
515 fprintf(ofp, "\\n\" %% \\\n\t\t(");
516
517 not_first = 0;
518 count = 0;
519
520 for (f = event->format.fields; f; f = f->next) {
521 if (not_first++)
522 fprintf(ofp, ", ");
523
524 if (++count % 5 == 0)
525 fprintf(ofp, "\n\t\t");
526
527 if (f->flags & FIELD_IS_FLAG) {
528 if ((count - 1) % 5 != 0) {
529 fprintf(ofp, "\n\t\t");
530 count = 4;
531 }
532 fprintf(ofp, "flag_str(\"");
533 fprintf(ofp, "%s__%s\", ", event->system,
534 event->name);
535 fprintf(ofp, "\"%s\", %s)", f->name,
536 f->name);
537 } else if (f->flags & FIELD_IS_SYMBOLIC) {
538 if ((count - 1) % 5 != 0) {
539 fprintf(ofp, "\n\t\t");
540 count = 4;
541 }
542 fprintf(ofp, "symbol_str(\"");
543 fprintf(ofp, "%s__%s\", ", event->system,
544 event->name);
545 fprintf(ofp, "\"%s\", %s)", f->name,
546 f->name);
547 } else
548 fprintf(ofp, "%s", f->name);
549 }
550
551 fprintf(ofp, "),\n\n");
552 }
553
554 fprintf(ofp, "def trace_unhandled(event_name, context, "
555 "common_cpu, common_secs, common_nsecs,\n\t\t"
556 "common_pid, common_comm):\n");
557
558 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
559 "common_secs, common_nsecs,\n\t\tcommon_pid, "
560 "common_comm)\n\n");
561
562 fprintf(ofp, "def print_header("
563 "event_name, cpu, secs, nsecs, pid, comm):\n"
564 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
565 "(event_name, cpu, secs, nsecs, pid, comm),\n");
566
567 fclose(ofp);
568
569 fprintf(stderr, "generated Python script: %s\n", fname);
570
571 return 0;
572}
573
574struct scripting_ops python_scripting_ops = {
575 .name = "Python",
576 .start_script = python_start_script,
577 .stop_script = python_stop_script,
578 .process_event = python_process_event,
579 .generate_script = python_generate_script,
580};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8abe76..eed1cb889008 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,8 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2 4
5#include <byteswap.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <sys/types.h> 7#include <sys/types.h>
5 8
@@ -49,6 +52,11 @@ out_close:
49 return -1; 52 return -1;
50} 53}
51 54
55static inline int perf_session__create_kernel_maps(struct perf_session *self)
56{
57 return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
58}
59
52struct perf_session *perf_session__new(const char *filename, int mode, bool force) 60struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{ 61{
54 size_t len = filename ? strlen(filename) + 1 : 0; 62 size_t len = filename ? strlen(filename) + 1 : 0;
@@ -62,17 +70,27 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
62 70
63 memcpy(self->filename, filename, len); 71 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT; 72 self->threads = RB_ROOT;
73 self->stats_by_id = RB_ROOT;
65 self->last_match = NULL; 74 self->last_match = NULL;
66 self->mmap_window = 32; 75 self->mmap_window = 32;
67 self->cwd = NULL; 76 self->cwd = NULL;
68 self->cwdlen = 0; 77 self->cwdlen = 0;
78 self->unknown_events = 0;
69 map_groups__init(&self->kmaps); 79 map_groups__init(&self->kmaps);
70 80
71 if (perf_session__create_kernel_maps(self) < 0) 81 if (mode == O_RDONLY) {
72 goto out_delete; 82 if (perf_session__open(self, force) < 0)
83 goto out_delete;
84 } else if (mode == O_WRONLY) {
85 /*
86 * In O_RDONLY mode this will be performed when reading the
87 * kernel MMAP event, in event__process_mmap().
88 */
89 if (perf_session__create_kernel_maps(self) < 0)
90 goto out_delete;
91 }
73 92
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 93 self->sample_type = perf_header__sample_type(&self->header);
75 goto out_delete;
76out: 94out:
77 return self; 95 return self;
78out_free: 96out_free:
@@ -148,3 +166,409 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
148 166
149 return syms; 167 return syms;
150} 168}
169
170static int process_event_stub(event_t *event __used,
171 struct perf_session *session __used)
172{
173 dump_printf(": unhandled!\n");
174 return 0;
175}
176
177static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
178{
179 if (handler->sample == NULL)
180 handler->sample = process_event_stub;
181 if (handler->mmap == NULL)
182 handler->mmap = process_event_stub;
183 if (handler->comm == NULL)
184 handler->comm = process_event_stub;
185 if (handler->fork == NULL)
186 handler->fork = process_event_stub;
187 if (handler->exit == NULL)
188 handler->exit = process_event_stub;
189 if (handler->lost == NULL)
190 handler->lost = process_event_stub;
191 if (handler->read == NULL)
192 handler->read = process_event_stub;
193 if (handler->throttle == NULL)
194 handler->throttle = process_event_stub;
195 if (handler->unthrottle == NULL)
196 handler->unthrottle = process_event_stub;
197}
198
199static const char *event__name[] = {
200 [0] = "TOTAL",
201 [PERF_RECORD_MMAP] = "MMAP",
202 [PERF_RECORD_LOST] = "LOST",
203 [PERF_RECORD_COMM] = "COMM",
204 [PERF_RECORD_EXIT] = "EXIT",
205 [PERF_RECORD_THROTTLE] = "THROTTLE",
206 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
207 [PERF_RECORD_FORK] = "FORK",
208 [PERF_RECORD_READ] = "READ",
209 [PERF_RECORD_SAMPLE] = "SAMPLE",
210};
211
212unsigned long event__total[PERF_RECORD_MAX];
213
214void event__print_totals(void)
215{
216 int i;
217 for (i = 0; i < PERF_RECORD_MAX; ++i)
218 pr_info("%10s events: %10ld\n",
219 event__name[i], event__total[i]);
220}
221
222void mem_bswap_64(void *src, int byte_size)
223{
224 u64 *m = src;
225
226 while (byte_size > 0) {
227 *m = bswap_64(*m);
228 byte_size -= sizeof(u64);
229 ++m;
230 }
231}
232
233static void event__all64_swap(event_t *self)
234{
235 struct perf_event_header *hdr = &self->header;
236 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
237}
238
239static void event__comm_swap(event_t *self)
240{
241 self->comm.pid = bswap_32(self->comm.pid);
242 self->comm.tid = bswap_32(self->comm.tid);
243}
244
245static void event__mmap_swap(event_t *self)
246{
247 self->mmap.pid = bswap_32(self->mmap.pid);
248 self->mmap.tid = bswap_32(self->mmap.tid);
249 self->mmap.start = bswap_64(self->mmap.start);
250 self->mmap.len = bswap_64(self->mmap.len);
251 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
252}
253
254static void event__task_swap(event_t *self)
255{
256 self->fork.pid = bswap_32(self->fork.pid);
257 self->fork.tid = bswap_32(self->fork.tid);
258 self->fork.ppid = bswap_32(self->fork.ppid);
259 self->fork.ptid = bswap_32(self->fork.ptid);
260 self->fork.time = bswap_64(self->fork.time);
261}
262
263static void event__read_swap(event_t *self)
264{
265 self->read.pid = bswap_32(self->read.pid);
266 self->read.tid = bswap_32(self->read.tid);
267 self->read.value = bswap_64(self->read.value);
268 self->read.time_enabled = bswap_64(self->read.time_enabled);
269 self->read.time_running = bswap_64(self->read.time_running);
270 self->read.id = bswap_64(self->read.id);
271}
272
273typedef void (*event__swap_op)(event_t *self);
274
275static event__swap_op event__swap_ops[] = {
276 [PERF_RECORD_MMAP] = event__mmap_swap,
277 [PERF_RECORD_COMM] = event__comm_swap,
278 [PERF_RECORD_FORK] = event__task_swap,
279 [PERF_RECORD_EXIT] = event__task_swap,
280 [PERF_RECORD_LOST] = event__all64_swap,
281 [PERF_RECORD_READ] = event__read_swap,
282 [PERF_RECORD_SAMPLE] = event__all64_swap,
283 [PERF_RECORD_MAX] = NULL,
284};
285
286static int perf_session__process_event(struct perf_session *self,
287 event_t *event,
288 struct perf_event_ops *ops,
289 u64 offset, u64 head)
290{
291 trace_event(event);
292
293 if (event->header.type < PERF_RECORD_MAX) {
294 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
295 offset + head, event->header.size,
296 event__name[event->header.type]);
297 ++event__total[0];
298 ++event__total[event->header.type];
299 }
300
301 if (self->header.needs_swap && event__swap_ops[event->header.type])
302 event__swap_ops[event->header.type](event);
303
304 switch (event->header.type) {
305 case PERF_RECORD_SAMPLE:
306 return ops->sample(event, self);
307 case PERF_RECORD_MMAP:
308 return ops->mmap(event, self);
309 case PERF_RECORD_COMM:
310 return ops->comm(event, self);
311 case PERF_RECORD_FORK:
312 return ops->fork(event, self);
313 case PERF_RECORD_EXIT:
314 return ops->exit(event, self);
315 case PERF_RECORD_LOST:
316 return ops->lost(event, self);
317 case PERF_RECORD_READ:
318 return ops->read(event, self);
319 case PERF_RECORD_THROTTLE:
320 return ops->throttle(event, self);
321 case PERF_RECORD_UNTHROTTLE:
322 return ops->unthrottle(event, self);
323 default:
324 self->unknown_events++;
325 return -1;
326 }
327}
328
329void perf_event_header__bswap(struct perf_event_header *self)
330{
331 self->type = bswap_32(self->type);
332 self->misc = bswap_16(self->misc);
333 self->size = bswap_16(self->size);
334}
335
336int perf_header__read_build_ids(struct perf_header *self,
337 int input, u64 offset, u64 size)
338{
339 struct build_id_event bev;
340 char filename[PATH_MAX];
341 u64 limit = offset + size;
342 int err = -1;
343
344 while (offset < limit) {
345 struct dso *dso;
346 ssize_t len;
347 struct list_head *head = &dsos__user;
348
349 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
350 goto out;
351
352 if (self->needs_swap)
353 perf_event_header__bswap(&bev.header);
354
355 len = bev.header.size - sizeof(bev);
356 if (read(input, filename, len) != len)
357 goto out;
358
359 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
360 head = &dsos__kernel;
361
362 dso = __dsos__findnew(head, filename);
363 if (dso != NULL) {
364 dso__set_build_id(dso, &bev.build_id);
365 if (head == &dsos__kernel && filename[0] == '[')
366 dso->kernel = 1;
367 }
368
369 offset += bev.header.size;
370 }
371 err = 0;
372out:
373 return err;
374}
375
376static struct thread *perf_session__register_idle_thread(struct perf_session *self)
377{
378 struct thread *thread = perf_session__findnew(self, 0);
379
380 if (thread == NULL || thread__set_comm(thread, "swapper")) {
381 pr_err("problem inserting idle task.\n");
382 thread = NULL;
383 }
384
385 return thread;
386}
387
388int __perf_session__process_events(struct perf_session *self,
389 u64 data_offset, u64 data_size,
390 u64 file_size, struct perf_event_ops *ops)
391{
392 int err, mmap_prot, mmap_flags;
393 u64 head, shift;
394 u64 offset = 0;
395 size_t page_size;
396 event_t *event;
397 uint32_t size;
398 char *buf;
399
400 perf_event_ops__fill_defaults(ops);
401
402 page_size = sysconf(_SC_PAGESIZE);
403
404 head = data_offset;
405 shift = page_size * (head / page_size);
406 offset += shift;
407 head -= shift;
408
409 mmap_prot = PROT_READ;
410 mmap_flags = MAP_SHARED;
411
412 if (self->header.needs_swap) {
413 mmap_prot |= PROT_WRITE;
414 mmap_flags = MAP_PRIVATE;
415 }
416remap:
417 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
418 mmap_flags, self->fd, offset);
419 if (buf == MAP_FAILED) {
420 pr_err("failed to mmap file\n");
421 err = -errno;
422 goto out_err;
423 }
424
425more:
426 event = (event_t *)(buf + head);
427
428 if (self->header.needs_swap)
429 perf_event_header__bswap(&event->header);
430 size = event->header.size;
431 if (size == 0)
432 size = 8;
433
434 if (head + event->header.size >= page_size * self->mmap_window) {
435 int munmap_ret;
436
437 shift = page_size * (head / page_size);
438
439 munmap_ret = munmap(buf, page_size * self->mmap_window);
440 assert(munmap_ret == 0);
441
442 offset += shift;
443 head -= shift;
444 goto remap;
445 }
446
447 size = event->header.size;
448
449 dump_printf("\n%#Lx [%#x]: event: %d\n",
450 offset + head, event->header.size, event->header.type);
451
452 if (size == 0 ||
453 perf_session__process_event(self, event, ops, offset, head) < 0) {
454 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
455 offset + head, event->header.size,
456 event->header.type);
457 /*
458 * assume we lost track of the stream, check alignment, and
459 * increment a single u64 in the hope to catch on again 'soon'.
460 */
461 if (unlikely(head & 7))
462 head &= ~7ULL;
463
464 size = 8;
465 }
466
467 head += size;
468
469 if (offset + head >= data_offset + data_size)
470 goto done;
471
472 if (offset + head < file_size)
473 goto more;
474done:
475 err = 0;
476out_err:
477 return err;
478}
479
480int perf_session__process_events(struct perf_session *self,
481 struct perf_event_ops *ops)
482{
483 int err;
484
485 if (perf_session__register_idle_thread(self) == NULL)
486 return -ENOMEM;
487
488 if (!symbol_conf.full_paths) {
489 char bf[PATH_MAX];
490
491 if (getcwd(bf, sizeof(bf)) == NULL) {
492 err = -errno;
493out_getcwd_err:
494 pr_err("failed to get the current directory\n");
495 goto out_err;
496 }
497 self->cwd = strdup(bf);
498 if (self->cwd == NULL) {
499 err = -ENOMEM;
500 goto out_getcwd_err;
501 }
502 self->cwdlen = strlen(self->cwd);
503 }
504
505 err = __perf_session__process_events(self, self->header.data_offset,
506 self->header.data_size,
507 self->size, ops);
508out_err:
509 return err;
510}
511
512bool perf_session__has_traces(struct perf_session *self, const char *msg)
513{
514 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
515 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
516 return false;
517 }
518
519 return true;
520}
521
522int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
523 const char *symbol_name,
524 u64 addr)
525{
526 char *bracket;
527 enum map_type i;
528
529 self->ref_reloc_sym.name = strdup(symbol_name);
530 if (self->ref_reloc_sym.name == NULL)
531 return -ENOMEM;
532
533 bracket = strchr(self->ref_reloc_sym.name, ']');
534 if (bracket)
535 *bracket = '\0';
536
537 self->ref_reloc_sym.addr = addr;
538
539 for (i = 0; i < MAP__NR_TYPES; ++i) {
540 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
541 kmap->ref_reloc_sym = &self->ref_reloc_sym;
542 }
543
544 return 0;
545}
546
547static u64 map__reloc_map_ip(struct map *map, u64 ip)
548{
549 return ip + (s64)map->pgoff;
550}
551
552static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
553{
554 return ip - (s64)map->pgoff;
555}
556
557void map__reloc_vmlinux(struct map *self)
558{
559 struct kmap *kmap = map__kmap(self);
560 s64 reloc;
561
562 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
563 return;
564
565 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
566 kmap->ref_reloc_sym->addr);
567
568 if (!reloc)
569 return;
570
571 self->map_ip = map__reloc_map_ip;
572 self->unmap_ip = map__reloc_unmap_ip;
573 self->pgoff = reloc;
574}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..5c33417eebb3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -3,13 +3,13 @@
3 3
4#include "event.h" 4#include "event.h"
5#include "header.h" 5#include "header.h"
6#include "symbol.h"
6#include "thread.h" 7#include "thread.h"
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h" 9#include "../../../include/linux/perf_event.h"
9 10
10struct ip_callchain; 11struct ip_callchain;
11struct thread; 12struct thread;
12struct symbol;
13 13
14struct perf_session { 14struct perf_session {
15 struct perf_header header; 15 struct perf_header header;
@@ -18,10 +18,14 @@ struct perf_session {
18 struct map_groups kmaps; 18 struct map_groups kmaps;
19 struct rb_root threads; 19 struct rb_root threads;
20 struct thread *last_match; 20 struct thread *last_match;
21 struct map *vmlinux_maps[MAP__NR_TYPES];
21 struct events_stats events_stats; 22 struct events_stats events_stats;
23 struct rb_root stats_by_id;
22 unsigned long event_total[PERF_RECORD_MAX]; 24 unsigned long event_total[PERF_RECORD_MAX];
25 unsigned long unknown_events;
23 struct rb_root hists; 26 struct rb_root hists;
24 u64 sample_type; 27 u64 sample_type;
28 struct ref_reloc_sym ref_reloc_sym;
25 int fd; 29 int fd;
26 int cwdlen; 30 int cwdlen;
27 char *cwd; 31 char *cwd;
@@ -31,23 +35,25 @@ struct perf_session {
31typedef int (*event_op)(event_t *self, struct perf_session *session); 35typedef int (*event_op)(event_t *self, struct perf_session *session);
32 36
33struct perf_event_ops { 37struct perf_event_ops {
34 event_op process_sample_event; 38 event_op sample,
35 event_op process_mmap_event; 39 mmap,
36 event_op process_comm_event; 40 comm,
37 event_op process_fork_event; 41 fork,
38 event_op process_exit_event; 42 exit,
39 event_op process_lost_event; 43 lost,
40 event_op process_read_event; 44 read,
41 event_op process_throttle_event; 45 throttle,
42 event_op process_unthrottle_event; 46 unthrottle;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46}; 47};
47 48
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 49struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self); 50void perf_session__delete(struct perf_session *self);
50 51
52void perf_event_header__bswap(struct perf_event_header *self);
53
54int __perf_session__process_events(struct perf_session *self,
55 u64 data_offset, u64 data_size, u64 size,
56 struct perf_event_ops *ops);
51int perf_session__process_events(struct perf_session *self, 57int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 58 struct perf_event_ops *event_ops);
53 59
@@ -56,6 +62,28 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
56 struct ip_callchain *chain, 62 struct ip_callchain *chain,
57 struct symbol **parent); 63 struct symbol **parent);
58 64
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 65bool perf_session__has_traces(struct perf_session *self, const char *msg);
66
67int perf_header__read_build_ids(struct perf_header *self, int input,
68 u64 offset, u64 file_size);
69
70int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
71 const char *symbol_name,
72 u64 addr);
73
74void mem_bswap_64(void *src, int byte_size);
75
76static inline int __perf_session__create_kernel_maps(struct perf_session *self,
77 struct dso *kernel)
78{
79 return __map_groups__create_kernel_maps(&self->kmaps,
80 self->vmlinux_maps, kernel);
81}
60 82
83static inline struct map *
84 perf_session__new_module_map(struct perf_session *self,
85 u64 start, const char *filename)
86{
87 return map_groups__new_module(&self->kmaps, start, filename);
88}
61#endif /* __PERF_SESSION_H */ 89#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 5352d7dccc61..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -227,16 +227,73 @@ fail:
227 return NULL; 227 return NULL;
228} 228}
229 229
230/* Glob expression pattern matching */ 230/* Character class matching */
231bool strglobmatch(const char *str, const char *pat) 231static bool __match_charclass(const char *pat, char c, const char **npat)
232{
233 bool complement = false, ret = true;
234
235 if (*pat == '!') {
236 complement = true;
237 pat++;
238 }
239 if (*pat++ == c) /* First character is special */
240 goto end;
241
242 while (*pat && *pat != ']') { /* Matching */
243 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
244 if (*(pat - 1) <= c && c <= *(pat + 1))
245 goto end;
246 if (*(pat - 1) > *(pat + 1))
247 goto error;
248 pat += 2;
249 } else if (*pat++ == c)
250 goto end;
251 }
252 if (!*pat)
253 goto error;
254 ret = false;
255
256end:
257 while (*pat && *pat != ']') /* Searching closing */
258 pat++;
259 if (!*pat)
260 goto error;
261 *npat = pat + 1;
262 return complement ? !ret : ret;
263
264error:
265 return false;
266}
267
268/* Glob/lazy pattern matching */
269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
232{ 270{
233 while (*str && *pat && *pat != '*') { 271 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') { 272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */
235 str++; 284 str++;
236 pat++; 285 pat++;
237 } else 286 continue;
238 if (*str++ != *pat++) 287 } else if (*pat == '[') /* Character classes/Ranges */
288 if (__match_charclass(pat + 1, *str, &pat)) {
289 str++;
290 continue;
291 } else
239 return false; 292 return false;
293 else if (*pat == '\\') /* Escaped char match as normal char */
294 pat++;
295 if (*str++ != *pat++)
296 return false;
240 } 297 }
241 /* Check wild card */ 298 /* Check wild card */
242 if (*pat == '*') { 299 if (*pat == '*') {
@@ -251,3 +308,32 @@ bool strglobmatch(const char *str, const char *pat)
251 return !*str && !*pat; 308 return !*str && !*pat;
252} 309}
253 310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 02ede58c54b4..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -10,6 +10,7 @@ s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat); 12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
13 14
14#define _STR(x) #x 15#define _STR(x) #x
15#define STR(x) _STR(x) 16#define STR(x) _STR(x)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763edb03..c458c4a371d1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,5 @@
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 "sort.h"
5#include "string.h" 4#include "string.h"
6#include "symbol.h" 5#include "symbol.h"
@@ -22,6 +21,7 @@
22enum dso_origin { 21enum dso_origin {
23 DSO__ORIG_KERNEL = 0, 22 DSO__ORIG_KERNEL = 0,
24 DSO__ORIG_JAVA_JIT, 23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
25 DSO__ORIG_FEDORA, 25 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
@@ -33,7 +33,7 @@ enum dso_origin {
33static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
34static 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);
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 perf_session *session, symbol_filter_t filter); 36 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 38static char **vmlinux_path;
39 39
@@ -53,17 +53,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53 return self->sorted_by_name & (1 << type); 53 return self->sorted_by_name & (1 << type);
54} 54}
55 55
56static void dso__set_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 56static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{ 57{
63 self->sorted_by_name |= (1 << type); 58 self->sorted_by_name |= (1 << type);
64} 59}
65 60
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 61bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 62{
68 switch (map_type) { 63 switch (map_type) {
69 case MAP__FUNCTION: 64 case MAP__FUNCTION:
@@ -142,14 +137,14 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
142 self->start = start; 137 self->start = start;
143 self->end = len ? start + len - 1 : start; 138 self->end = len ? start + len - 1 : start;
144 139
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146 141
147 memcpy(self->name, name, namelen); 142 memcpy(self->name, name, namelen);
148 143
149 return self; 144 return self;
150} 145}
151 146
152static void symbol__delete(struct symbol *self) 147void symbol__delete(struct symbol *self)
153{ 148{
154 free(((void *)self) - symbol_conf.priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
155} 150}
@@ -160,7 +155,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
160 self->start, self->end, self->name); 155 self->start, self->end, self->name);
161} 156}
162 157
163static void dso__set_long_name(struct dso *self, char *name) 158void dso__set_long_name(struct dso *self, char *name)
164{ 159{
165 if (name == NULL) 160 if (name == NULL)
166 return; 161 return;
@@ -168,20 +163,28 @@ static void dso__set_long_name(struct dso *self, char *name)
168 self->long_name_len = strlen(name); 163 self->long_name_len = strlen(name);
169} 164}
170 165
166static void dso__set_short_name(struct dso *self, const char *name)
167{
168 if (name == NULL)
169 return;
170 self->short_name = name;
171 self->short_name_len = strlen(name);
172}
173
171static void dso__set_basename(struct dso *self) 174static void dso__set_basename(struct dso *self)
172{ 175{
173 self->short_name = basename(self->long_name); 176 dso__set_short_name(self, basename(self->long_name));
174} 177}
175 178
176struct dso *dso__new(const char *name) 179struct dso *dso__new(const char *name)
177{ 180{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 181 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
179 182
180 if (self != NULL) { 183 if (self != NULL) {
181 int i; 184 int i;
182 strcpy(self->name, name); 185 strcpy(self->name, name);
183 dso__set_long_name(self, self->name); 186 dso__set_long_name(self, self->name);
184 self->short_name = self->name; 187 dso__set_short_name(self, self->name);
185 for (i = 0; i < MAP__NR_TYPES; ++i) 188 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 189 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
187 self->slen_calculated = 0; 190 self->slen_calculated = 0;
@@ -344,10 +347,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 347 &self->symbols[type]);
345} 348}
346 349
347int build_id__sprintf(u8 *self, int len, char *bf) 350int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 351{
349 char *bid = bf; 352 char *bid = bf;
350 u8 *raw = self; 353 const u8 *raw = self;
351 int i; 354 int i;
352 355
353 for (i = 0; i < len; ++i) { 356 for (i = 0; i < len; ++i) {
@@ -372,6 +375,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
372 struct rb_node *nd; 375 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 376 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374 377
378 if (self->short_name != self->long_name)
379 ret += fprintf(fp, "%s, ", self->long_name);
380 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
381 self->loaded ? "" : "NOT ");
375 ret += dso__fprintf_buildid(self, fp); 382 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n"); 383 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 384 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -382,24 +389,20 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 389 return ret;
383} 390}
384 391
385/* 392int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 393 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 394 char type, u64 start))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 395{
392 char *line = NULL; 396 char *line = NULL;
393 size_t n; 397 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 398 int err = 0;
395 FILE *file = fopen("/proc/kallsyms", "r"); 399 FILE *file = fopen(filename, "r");
396 400
397 if (file == NULL) 401 if (file == NULL)
398 goto out_failure; 402 goto out_failure;
399 403
400 while (!feof(file)) { 404 while (!feof(file)) {
401 u64 start; 405 u64 start;
402 struct symbol *sym;
403 int line_len, len; 406 int line_len, len;
404 char symbol_type; 407 char symbol_type;
405 char *symbol_name; 408 char *symbol_name;
@@ -420,43 +423,72 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 423 continue;
421 424
422 symbol_type = toupper(line[len]); 425 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type))
424 continue;
425
426 symbol_name = line + len + 2; 426 symbol_name = line + len + 2;
427 /*
428 * Will fix up the end later, when we have all symbols sorted.
429 */
430 sym = symbol__new(start, 0, symbol_name);
431 427
432 if (sym == NULL) 428 err = process_symbol(arg, symbol_name, symbol_type, start);
433 goto out_delete_line; 429 if (err)
434 /* 430 break;
435 * We will pass the symbols to the filter later, in
436 * map__split_kallsyms, when we have split the maps per module
437 */
438 symbols__insert(root, sym);
439 } 431 }
440 432
441 free(line); 433 free(line);
442 fclose(file); 434 fclose(file);
435 return err;
443 436
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 437out_failure:
449 return -1; 438 return -1;
450} 439}
451 440
441struct process_kallsyms_args {
442 struct map *map;
443 struct dso *dso;
444};
445
446static int map__process_kallsym_symbol(void *arg, const char *name,
447 char type, u64 start)
448{
449 struct symbol *sym;
450 struct process_kallsyms_args *a = arg;
451 struct rb_root *root = &a->dso->symbols[a->map->type];
452
453 if (!symbol_type__is_a(type, a->map->type))
454 return 0;
455
456 /*
457 * Will fix up the end later, when we have all symbols sorted.
458 */
459 sym = symbol__new(start, 0, name);
460
461 if (sym == NULL)
462 return -ENOMEM;
463 /*
464 * We will pass the symbols to the filter later, in
465 * map__split_kallsyms, when we have split the maps per module
466 */
467 symbols__insert(root, sym);
468 return 0;
469}
470
471/*
472 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
473 * so that we can in the next step set the symbol ->end address and then
474 * call kernel_maps__split_kallsyms.
475 */
476static int dso__load_all_kallsyms(struct dso *self, const char *filename,
477 struct map *map)
478{
479 struct process_kallsyms_args args = { .map = map, .dso = self, };
480 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
481}
482
452/* 483/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 484 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have 485 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have. 486 * the original ELF section names vmlinux have.
456 */ 487 */
457static int dso__split_kallsyms(struct dso *self, struct map *map, 488static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter) 489 symbol_filter_t filter)
459{ 490{
491 struct map_groups *kmaps = map__kmap(map)->kmaps;
460 struct map *curr_map = map; 492 struct map *curr_map = map;
461 struct symbol *pos; 493 struct symbol *pos;
462 int count = 0; 494 int count = 0;
@@ -477,13 +509,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 509
478 *module++ = '\0'; 510 *module++ = '\0';
479 511
480 if (strcmp(self->name, module)) { 512 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 513 curr_map = map_groups__find_by_name(kmaps, map->type, module);
482 if (curr_map == NULL) { 514 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 515 pr_debug("/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 516 "inconsistency while looking "
517 "for \"%s\" module!\n", module);
485 return -1; 518 return -1;
486 } 519 }
520
521 if (curr_map->dso->loaded)
522 goto discard_symbol;
487 } 523 }
488 /* 524 /*
489 * So that we look just like we get from .ko files, 525 * So that we look just like we get from .ko files,
@@ -503,13 +539,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
503 return -1; 539 return -1;
504 540
505 curr_map = map__new2(pos->start, dso, map->type); 541 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) { 542 if (curr_map == NULL) {
507 dso__delete(dso); 543 dso__delete(dso);
508 return -1; 544 return -1;
509 } 545 }
510 546
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 547 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map); 548 map_groups__insert(kmaps, curr_map);
513 ++kernel_range; 549 ++kernel_range;
514 } 550 }
515 551
@@ -528,17 +564,16 @@ discard_symbol: rb_erase(&pos->rb_node, root);
528 return count; 564 return count;
529} 565}
530 566
531 567int dso__load_kallsyms(struct dso *self, const char *filename,
532static int dso__load_kallsyms(struct dso *self, struct map *map, 568 struct map *map, symbol_filter_t filter)
533 struct perf_session *session, symbol_filter_t filter)
534{ 569{
535 if (dso__load_all_kallsyms(self, map) < 0) 570 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 571 return -1;
537 572
538 symbols__fixup_end(&self->symbols[map->type]); 573 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL; 574 self->origin = DSO__ORIG_KERNEL;
540 575
541 return dso__split_kallsyms(self, map, session, filter); 576 return dso__split_kallsyms(self, map, filter);
542} 577}
543 578
544static int dso__load_perf_map(struct dso *self, struct map *map, 579static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -864,13 +899,12 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
864 } 899 }
865} 900}
866 901
867static int dso__load_sym(struct dso *self, struct map *map, 902static int dso__load_sym(struct dso *self, struct map *map, const char *name,
868 struct perf_session *session, const char *name, int fd, 903 int fd, symbol_filter_t filter, int kmodule)
869 symbol_filter_t filter, int kernel, int kmodule)
870{ 904{
905 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
871 struct map *curr_map = map; 906 struct map *curr_map = map;
872 struct dso *curr_dso = self; 907 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
874 Elf_Data *symstrs, *secstrs; 908 Elf_Data *symstrs, *secstrs;
875 uint32_t nr_syms; 909 uint32_t nr_syms;
876 int err = -1; 910 int err = -1;
@@ -924,7 +958,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
924 nr_syms = shdr.sh_size / shdr.sh_entsize; 958 nr_syms = shdr.sh_size / shdr.sh_entsize;
925 959
926 memset(&sym, 0, sizeof(sym)); 960 memset(&sym, 0, sizeof(sym));
927 if (!kernel) { 961 if (!self->kernel) {
928 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 962 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
929 elf_section_by_name(elf, &ehdr, &shdr, 963 elf_section_by_name(elf, &ehdr, &shdr,
930 ".gnu.prelink_undo", 964 ".gnu.prelink_undo",
@@ -933,11 +967,15 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 967
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 968 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 969 struct symbol *f;
936 const char *elf_name; 970 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 971 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 972 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 973 const char *section_name;
940 974
975 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
976 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
977 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
978
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 979 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 980 continue;
943 981
@@ -950,14 +988,14 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 988 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 989 continue;
952 990
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 991 section_name = elf_sec__name(&shdr, secstrs);
955 992
956 if (kernel || kmodule) { 993 if (self->kernel || kmodule) {
957 char dso_name[PATH_MAX]; 994 char dso_name[PATH_MAX];
958 995
959 if (strcmp(section_name, 996 if (strcmp(section_name,
960 curr_dso->short_name + dso_name_len) == 0) 997 (curr_dso->short_name +
998 self->short_name_len)) == 0)
961 goto new_symbol; 999 goto new_symbol;
962 1000
963 if (strcmp(section_name, ".text") == 0) { 1001 if (strcmp(section_name, ".text") == 0) {
@@ -969,7 +1007,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
969 snprintf(dso_name, sizeof(dso_name), 1007 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name); 1008 "%s%s", self->short_name, section_name);
971 1009
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 1010 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
973 if (curr_map == NULL) { 1011 if (curr_map == NULL) {
974 u64 start = sym.st_value; 1012 u64 start = sym.st_value;
975 1013
@@ -980,7 +1018,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
980 if (curr_dso == NULL) 1018 if (curr_dso == NULL)
981 goto out_elf_end; 1019 goto out_elf_end;
982 curr_map = map__new2(start, curr_dso, 1020 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION); 1021 map->type);
984 if (curr_map == NULL) { 1022 if (curr_map == NULL) {
985 dso__delete(curr_dso); 1023 dso__delete(curr_dso);
986 goto out_elf_end; 1024 goto out_elf_end;
@@ -988,8 +1026,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
988 curr_map->map_ip = identity__map_ip; 1026 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip; 1027 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL; 1028 curr_dso->origin = DSO__ORIG_KERNEL;
991 map_groups__insert(&session->kmaps, curr_map); 1029 map_groups__insert(kmap->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso); 1030 dsos__add(&dsos__kernel, curr_dso);
1031 dso__set_loaded(curr_dso, map->type);
993 } else 1032 } else
994 curr_dso = curr_map->dso; 1033 curr_dso = curr_map->dso;
995 1034
@@ -997,9 +1036,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
997 } 1036 }
998 1037
999 if (curr_dso->adjust_symbols) { 1038 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1039 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1040 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1041 (u64)sym.st_value, (u64)shdr.sh_addr,
1042 (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1043 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1004 } 1044 }
1005 /* 1045 /*
@@ -1027,8 +1067,16 @@ new_symbol:
1027 /* 1067 /*
1028 * For misannotated, zeroed, ASM function sizes. 1068 * For misannotated, zeroed, ASM function sizes.
1029 */ 1069 */
1030 if (nr > 0) 1070 if (nr > 0) {
1031 symbols__fixup_end(&self->symbols[map->type]); 1071 symbols__fixup_end(&self->symbols[map->type]);
1072 if (kmap) {
1073 /*
1074 * We need to fixup this here too because we create new
1075 * maps here, for things like vsyscall sections.
1076 */
1077 __map_groups__fixup_end(kmap->kmaps, map->type);
1078 }
1079 }
1032 err = nr; 1080 err = nr;
1033out_elf_end: 1081out_elf_end:
1034 elf_end(elf); 1082 elf_end(elf);
@@ -1041,25 +1089,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1089 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042} 1090}
1043 1091
1044static bool __dsos__read_build_ids(struct list_head *head) 1092static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1045{ 1093{
1046 bool have_build_id = false; 1094 bool have_build_id = false;
1047 struct dso *pos; 1095 struct dso *pos;
1048 1096
1049 list_for_each_entry(pos, head, node) 1097 list_for_each_entry(pos, head, node) {
1098 if (with_hits && !pos->hit)
1099 continue;
1050 if (filename__read_build_id(pos->long_name, pos->build_id, 1100 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) { 1101 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true; 1102 have_build_id = true;
1053 pos->has_build_id = true; 1103 pos->has_build_id = true;
1054 } 1104 }
1105 }
1055 1106
1056 return have_build_id; 1107 return have_build_id;
1057} 1108}
1058 1109
1059bool dsos__read_build_ids(void) 1110bool dsos__read_build_ids(bool with_hits)
1060{ 1111{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 1112 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1062 ubuildids = __dsos__read_build_ids(&dsos__user); 1113 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
1063 return kbuildids || ubuildids; 1114 return kbuildids || ubuildids;
1064} 1115}
1065 1116
@@ -1191,6 +1242,7 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1242 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1243 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1244 [DSO__ORIG_JAVA_JIT] = 'j',
1245 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1246 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1247 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1248 [DSO__ORIG_BUILDID] = 'b',
@@ -1203,19 +1255,19 @@ char dso__symtab_origin(const struct dso *self)
1203 return origin[self->origin]; 1255 return origin[self->origin];
1204} 1256}
1205 1257
1206int dso__load(struct dso *self, struct map *map, struct perf_session *session, 1258int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1207 symbol_filter_t filter)
1208{ 1259{
1209 int size = PATH_MAX; 1260 int size = PATH_MAX;
1210 char *name; 1261 char *name;
1211 u8 build_id[BUILD_ID_SIZE]; 1262 u8 build_id[BUILD_ID_SIZE];
1263 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1212 int ret = -1; 1264 int ret = -1;
1213 int fd; 1265 int fd;
1214 1266
1215 dso__set_loaded(self, map->type); 1267 dso__set_loaded(self, map->type);
1216 1268
1217 if (self->kernel) 1269 if (self->kernel)
1218 return dso__load_kernel_sym(self, map, session, filter); 1270 return dso__load_kernel_sym(self, map, filter);
1219 1271
1220 name = malloc(size); 1272 name = malloc(size);
1221 if (!name) 1273 if (!name)
@@ -1230,8 +1282,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1282 return ret;
1231 } 1283 }
1232 1284
1233 self->origin = DSO__ORIG_FEDORA - 1; 1285 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1234 1286
1287 if (self->has_build_id) {
1288 build_id__sprintf(self->build_id, sizeof(self->build_id),
1289 build_id_hex);
1290 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1291 getenv("HOME"), DEBUG_CACHE_DIR,
1292 build_id_hex, build_id_hex + 2);
1293 goto open_file;
1294 }
1235more: 1295more:
1236 do { 1296 do {
1237 self->origin++; 1297 self->origin++;
@@ -1247,8 +1307,6 @@ more:
1247 case DSO__ORIG_BUILDID: 1307 case DSO__ORIG_BUILDID:
1248 if (filename__read_build_id(self->long_name, build_id, 1308 if (filename__read_build_id(self->long_name, build_id,
1249 sizeof(build_id))) { 1309 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id), 1310 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex); 1311 build_id_hex);
1254 snprintf(name, size, 1312 snprintf(name, size,
@@ -1276,11 +1334,11 @@ compare_build_id:
1276 if (!dso__build_id_equal(self, build_id)) 1334 if (!dso__build_id_equal(self, build_id))
1277 goto more; 1335 goto more;
1278 } 1336 }
1279 1337open_file:
1280 fd = open(name, O_RDONLY); 1338 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1339 } while (fd < 0);
1282 1340
1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1341 ret = dso__load_sym(self, map, name, fd, filter, 0);
1284 close(fd); 1342 close(fd);
1285 1343
1286 /* 1344 /*
@@ -1309,14 +1367,34 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1367 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1368 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1369
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1370 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1371 return map;
1314 } 1372 }
1315 1373
1316 return NULL; 1374 return NULL;
1317} 1375}
1318 1376
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1377static int dso__kernel_module_get_build_id(struct dso *self)
1378{
1379 char filename[PATH_MAX];
1380 /*
1381 * kernel module short names are of the form "[module]" and
1382 * we need just "module" here.
1383 */
1384 const char *name = self->short_name + 1;
1385
1386 snprintf(filename, sizeof(filename),
1387 "/sys/module/%.*s/notes/.note.gnu.build-id",
1388 (int)strlen(name - 1), name);
1389
1390 if (sysfs__read_build_id(filename, self->build_id,
1391 sizeof(self->build_id)) == 0)
1392 self->has_build_id = true;
1393
1394 return 0;
1395}
1396
1397static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
1320{ 1398{
1321 struct dirent *dent; 1399 struct dirent *dent;
1322 DIR *dir = opendir(dirname); 1400 DIR *dir = opendir(dirname);
@@ -1336,7 +1414,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1336 1414
1337 snprintf(path, sizeof(path), "%s/%s", 1415 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name); 1416 dirname, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0) 1417 if (map_groups__set_modules_path_dir(self, path) < 0)
1340 goto failure; 1418 goto failure;
1341 } else { 1419 } else {
1342 char *dot = strrchr(dent->d_name, '.'), 1420 char *dot = strrchr(dent->d_name, '.'),
@@ -1350,7 +1428,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1350 (int)(dot - dent->d_name), dent->d_name); 1428 (int)(dot - dent->d_name), dent->d_name);
1351 1429
1352 strxfrchar(dso_name, '-', '_'); 1430 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1431 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1354 if (map == NULL) 1432 if (map == NULL)
1355 continue; 1433 continue;
1356 1434
@@ -1361,6 +1439,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1361 if (long_name == NULL) 1439 if (long_name == NULL)
1362 goto failure; 1440 goto failure;
1363 dso__set_long_name(map->dso, long_name); 1441 dso__set_long_name(map->dso, long_name);
1442 dso__kernel_module_get_build_id(map->dso);
1364 } 1443 }
1365 } 1444 }
1366 1445
@@ -1370,7 +1449,7 @@ failure:
1370 return -1; 1449 return -1;
1371} 1450}
1372 1451
1373static int perf_session__set_modules_path(struct perf_session *self) 1452static int map_groups__set_modules_path(struct map_groups *self)
1374{ 1453{
1375 struct utsname uts; 1454 struct utsname uts;
1376 char modules_path[PATH_MAX]; 1455 char modules_path[PATH_MAX];
@@ -1381,7 +1460,7 @@ static int perf_session__set_modules_path(struct perf_session *self)
1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1460 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1382 uts.release); 1461 uts.release);
1383 1462
1384 return perf_session__set_modules_path_dir(self, modules_path); 1463 return map_groups__set_modules_path_dir(self, modules_path);
1385} 1464}
1386 1465
1387/* 1466/*
@@ -1391,8 +1470,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
1391 */ 1470 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1471static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{ 1472{
1394 struct map *self = malloc(sizeof(*self)); 1473 struct map *self = zalloc(sizeof(*self) +
1395 1474 (dso->kernel ? sizeof(struct kmap) : 0));
1396 if (self != NULL) { 1475 if (self != NULL) {
1397 /* 1476 /*
1398 * ->end will be filled after we load all the symbols 1477 * ->end will be filled after we load all the symbols
@@ -1403,7 +1482,25 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1482 return self;
1404} 1483}
1405 1484
1406static int perf_session__create_module_maps(struct perf_session *self) 1485struct map *map_groups__new_module(struct map_groups *self, u64 start,
1486 const char *filename)
1487{
1488 struct map *map;
1489 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1490
1491 if (dso == NULL)
1492 return NULL;
1493
1494 map = map__new2(start, dso, MAP__FUNCTION);
1495 if (map == NULL)
1496 return NULL;
1497
1498 dso->origin = DSO__ORIG_KMODULE;
1499 map_groups__insert(self, map);
1500 return map;
1501}
1502
1503static int map_groups__create_modules(struct map_groups *self)
1407{ 1504{
1408 char *line = NULL; 1505 char *line = NULL;
1409 size_t n; 1506 size_t n;
@@ -1416,7 +1513,6 @@ static int perf_session__create_module_maps(struct perf_session *self)
1416 while (!feof(file)) { 1513 while (!feof(file)) {
1417 char name[PATH_MAX]; 1514 char name[PATH_MAX];
1418 u64 start; 1515 u64 start;
1419 struct dso *dso;
1420 char *sep; 1516 char *sep;
1421 int line_len; 1517 int line_len;
1422 1518
@@ -1442,32 +1538,16 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1538 *sep = '\0';
1443 1539
1444 snprintf(name, sizeof(name), "[%s]", line); 1540 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1541 map = map_groups__new_module(self, start, name);
1446 1542 if (map == NULL)
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line; 1543 goto out_delete_line;
1454 } 1544 dso__kernel_module_get_build_id(map->dso);
1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
1465 } 1545 }
1466 1546
1467 free(line); 1547 free(line);
1468 fclose(file); 1548 fclose(file);
1469 1549
1470 return perf_session__set_modules_path(self); 1550 return map_groups__set_modules_path(self);
1471 1551
1472out_delete_line: 1552out_delete_line:
1473 free(line); 1553 free(line);
@@ -1476,7 +1556,6 @@ out_failure:
1476} 1556}
1477 1557
1478static int dso__load_vmlinux(struct dso *self, struct map *map, 1558static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter) 1559 const char *vmlinux, symbol_filter_t filter)
1481{ 1560{
1482 int err = -1, fd; 1561 int err = -1, fd;
@@ -1510,51 +1589,124 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1510 return -1; 1589 return -1;
1511 1590
1512 dso__set_loaded(self, map->type); 1591 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1592 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1514 close(fd); 1593 close(fd);
1515 1594
1595 if (err > 0)
1596 pr_debug("Using %s for symbols\n", vmlinux);
1597
1598 return err;
1599}
1600
1601int dso__load_vmlinux_path(struct dso *self, struct map *map,
1602 symbol_filter_t filter)
1603{
1604 int i, err = 0;
1605
1606 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1607 vmlinux_path__nr_entries);
1608
1609 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1610 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1611 if (err > 0) {
1612 dso__set_long_name(self, strdup(vmlinux_path[i]));
1613 break;
1614 }
1615 }
1616
1516 return err; 1617 return err;
1517} 1618}
1518 1619
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1620static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1621 symbol_filter_t filter)
1521{ 1622{
1522 int err; 1623 int err;
1523 bool is_kallsyms; 1624 const char *kallsyms_filename = NULL;
1625 char *kallsyms_allocated_filename = NULL;
1626 /*
1627 * Step 1: if the user specified a vmlinux filename, use it and only
1628 * it, reporting errors to the user if it cannot be used.
1629 *
1630 * For instance, try to analyse an ARM perf.data file _without_ a
1631 * build-id, or if the user specifies the wrong path to the right
1632 * vmlinux file, obviously we can't fallback to another vmlinux (a
1633 * x86_86 one, on the machine where analysis is being performed, say),
1634 * or worse, /proc/kallsyms.
1635 *
1636 * If the specified file _has_ a build-id and there is a build-id
1637 * section in the perf.data file, we will still do the expected
1638 * validation in dso__load_vmlinux and will bail out if they don't
1639 * match.
1640 */
1641 if (symbol_conf.vmlinux_name != NULL) {
1642 err = dso__load_vmlinux(self, map,
1643 symbol_conf.vmlinux_name, filter);
1644 goto out_try_fixup;
1645 }
1524 1646
1525 if (vmlinux_path != NULL) { 1647 if (vmlinux_path != NULL) {
1526 int i; 1648 err = dso__load_vmlinux_path(self, map, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1649 if (err > 0)
1528 vmlinux_path__nr_entries); 1650 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1651 }
1530 err = dso__load_vmlinux(self, map, session, 1652
1531 vmlinux_path[i], filter); 1653 /*
1532 if (err > 0) { 1654 * Say the kernel DSO was created when processing the build-id header table,
1533 pr_debug("Using %s for symbols\n", 1655 * we have a build-id, so check if it is the same as the running kernel,
1534 vmlinux_path[i]); 1656 * using it if it is.
1535 dso__set_long_name(self, 1657 */
1536 strdup(vmlinux_path[i])); 1658 if (self->has_build_id) {
1537 goto out_fixup; 1659 u8 kallsyms_build_id[BUILD_ID_SIZE];
1660 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1661
1662 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1663 sizeof(kallsyms_build_id)) == 0) {
1664 if (dso__build_id_equal(self, kallsyms_build_id)) {
1665 kallsyms_filename = "/proc/kallsyms";
1666 goto do_kallsyms;
1538 } 1667 }
1539 } 1668 }
1540 } 1669 /*
1670 * Now look if we have it on the build-id cache in
1671 * $HOME/.debug/[kernel.kallsyms].
1672 */
1673 build_id__sprintf(self->build_id, sizeof(self->build_id),
1674 sbuild_id);
1675
1676 if (asprintf(&kallsyms_allocated_filename,
1677 "%s/.debug/[kernel.kallsyms]/%s",
1678 getenv("HOME"), sbuild_id) == -1) {
1679 pr_err("Not enough memory for kallsyms file lookup\n");
1680 return -1;
1681 }
1541 1682
1542 is_kallsyms = self->long_name[0] == '['; 1683 kallsyms_filename = kallsyms_allocated_filename;
1543 if (is_kallsyms)
1544 goto do_kallsyms;
1545 1684
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1685 if (access(kallsyms_filename, F_OK)) {
1547 if (err <= 0) { 1686 pr_err("No kallsyms or vmlinux with build-id %s "
1548 pr_info("The file %s cannot be used, " 1687 "was found\n", sbuild_id);
1549 "trying to use /proc/kallsyms...", self->long_name); 1688 free(kallsyms_allocated_filename);
1550do_kallsyms: 1689 return -1;
1551 err = dso__load_kallsyms(self, map, session, filter); 1690 }
1552 if (err > 0 && !is_kallsyms) 1691 } else {
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1692 /*
1693 * Last resort, if we don't have a build-id and couldn't find
1694 * any vmlinux file, try the running kernel kallsyms table.
1695 */
1696 kallsyms_filename = "/proc/kallsyms";
1554 } 1697 }
1555 1698
1699do_kallsyms:
1700 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1701 if (err > 0)
1702 pr_debug("Using %s for symbols\n", kallsyms_filename);
1703 free(kallsyms_allocated_filename);
1704
1705out_try_fixup:
1556 if (err > 0) { 1706 if (err > 0) {
1557out_fixup: 1707out_fixup:
1708 if (kallsyms_filename != NULL)
1709 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1710 map__fixup_start(map);
1559 map__fixup_end(map); 1711 map__fixup_end(map);
1560 } 1712 }
@@ -1564,7 +1716,6 @@ out_fixup:
1564 1716
1565LIST_HEAD(dsos__user); 1717LIST_HEAD(dsos__user);
1566LIST_HEAD(dsos__kernel); 1718LIST_HEAD(dsos__kernel);
1567struct dso *vdso;
1568 1719
1569static void dsos__add(struct list_head *head, struct dso *dso) 1720static void dsos__add(struct list_head *head, struct dso *dso)
1570{ 1721{
@@ -1576,19 +1727,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 1727 struct dso *pos;
1577 1728
1578 list_for_each_entry(pos, head, node) 1729 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 1730 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 1731 return pos;
1581 return NULL; 1732 return NULL;
1582} 1733}
1583 1734
1584struct dso *dsos__findnew(const char *name) 1735struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 1736{
1586 struct dso *dso = dsos__find(&dsos__user, name); 1737 struct dso *dso = dsos__find(head, name);
1587 1738
1588 if (!dso) { 1739 if (!dso) {
1589 dso = dso__new(name); 1740 dso = dso__new(name);
1590 if (dso != NULL) { 1741 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 1742 dsos__add(head, dso);
1592 dso__set_basename(dso); 1743 dso__set_basename(dso);
1593 } 1744 }
1594 } 1745 }
@@ -1613,75 +1764,78 @@ void dsos__fprintf(FILE *fp)
1613 __dsos__fprintf(&dsos__user, fp); 1764 __dsos__fprintf(&dsos__user, fp);
1614} 1765}
1615 1766
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 1767static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1768 bool with_hits)
1617{ 1769{
1618 struct dso *pos; 1770 struct dso *pos;
1619 size_t ret = 0; 1771 size_t ret = 0;
1620 1772
1621 list_for_each_entry(pos, head, node) { 1773 list_for_each_entry(pos, head, node) {
1774 if (with_hits && !pos->hit)
1775 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 1776 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 1777 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 1778 }
1625 return ret; 1779 return ret;
1626} 1780}
1627 1781
1628size_t dsos__fprintf_buildid(FILE *fp) 1782size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
1629{ 1783{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1784 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 1785 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1632} 1786}
1633 1787
1634static struct dso *dsos__create_kernel( const char *vmlinux) 1788struct dso *dso__new_kernel(const char *name)
1635{ 1789{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1790 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1637 1791
1638 if (kernel == NULL) 1792 if (self != NULL) {
1639 return NULL; 1793 dso__set_short_name(self, "[kernel]");
1794 self->kernel = 1;
1795 }
1640 1796
1641 kernel->short_name = "[kernel]"; 1797 return self;
1642 kernel->kernel = 1; 1798}
1643 1799
1644 vdso = dso__new("[vdso]"); 1800void dso__read_running_kernel_build_id(struct dso *self)
1645 if (vdso == NULL) 1801{
1646 goto out_delete_kernel_dso; 1802 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1647 dso__set_loaded(vdso, MAP__FUNCTION); 1803 sizeof(self->build_id)) == 0)
1804 self->has_build_id = true;
1805}
1648 1806
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1807static struct dso *dsos__create_kernel(const char *vmlinux)
1650 sizeof(kernel->build_id)) == 0) 1808{
1651 kernel->has_build_id = true; 1809 struct dso *kernel = dso__new_kernel(vmlinux);
1652 1810
1653 dsos__add(&dsos__kernel, kernel); 1811 if (kernel != NULL) {
1654 dsos__add(&dsos__user, vdso); 1812 dso__read_running_kernel_build_id(kernel);
1813 dsos__add(&dsos__kernel, kernel);
1814 }
1655 1815
1656 return kernel; 1816 return kernel;
1657
1658out_delete_kernel_dso:
1659 dso__delete(kernel);
1660 return NULL;
1661} 1817}
1662 1818
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1819int __map_groups__create_kernel_maps(struct map_groups *self,
1820 struct map *vmlinux_maps[MAP__NR_TYPES],
1821 struct dso *kernel)
1664{ 1822{
1665 struct map *functions, *variables; 1823 enum map_type type;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667 1824
1668 if (kernel == NULL) 1825 for (type = 0; type < MAP__NR_TYPES; ++type) {
1669 return -1; 1826 struct kmap *kmap;
1670 1827
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 1828 vmlinux_maps[type] = map__new2(0, kernel, type);
1672 if (functions == NULL) 1829 if (vmlinux_maps[type] == NULL)
1673 return -1; 1830 return -1;
1674 1831
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 1832 vmlinux_maps[type]->map_ip =
1676 if (variables == NULL) { 1833 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1677 map__delete(functions);
1678 return -1;
1679 }
1680 1834
1681 functions->map_ip = functions->unmap_ip = 1835 kmap = map__kmap(vmlinux_maps[type]);
1682 variables->map_ip = variables->unmap_ip = identity__map_ip; 1836 kmap->kmaps = self;
1683 map_groups__insert(self, functions); 1837 map_groups__insert(self, vmlinux_maps[type]);
1684 map_groups__insert(self, variables); 1838 }
1685 1839
1686 return 0; 1840 return 0;
1687} 1841}
@@ -1791,19 +1945,22 @@ out_free_comm_list:
1791 return -1; 1945 return -1;
1792} 1946}
1793 1947
1794int perf_session__create_kernel_maps(struct perf_session *self) 1948int map_groups__create_kernel_maps(struct map_groups *self,
1949 struct map *vmlinux_maps[MAP__NR_TYPES])
1795{ 1950{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 1951 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1797 symbol_conf.vmlinux_name) < 0) 1952
1953 if (kernel == NULL)
1954 return -1;
1955
1956 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1798 return -1; 1957 return -1;
1799 1958
1800 if (symbol_conf.use_modules && 1959 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
1801 perf_session__create_module_maps(self) < 0) 1960 pr_debug("Problems creating module maps, continuing anyway...\n");
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1804 /* 1961 /*
1805 * Now that we have all the maps created, just set the ->end of them: 1962 * Now that we have all the maps created, just set the ->end of them:
1806 */ 1963 */
1807 map_groups__fixup_end(&self->kmaps); 1964 map_groups__fixup_end(self);
1808 return 0; 1965 return 0;
1809} 1966}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..f30a37428919 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -8,6 +8,8 @@
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9#include "event.h" 9#include "event.h"
10 10
11#define DEBUG_CACHE_DIR ".debug"
12
11#ifdef HAVE_CPLUS_DEMANGLE 13#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 14extern char *cplus_demangle(const char *, int);
13 15
@@ -49,6 +51,8 @@ struct symbol {
49 char name[0]; 51 char name[0];
50}; 52};
51 53
54void symbol__delete(struct symbol *self);
55
52struct strlist; 56struct strlist;
53 57
54struct symbol_conf { 58struct symbol_conf {
@@ -58,7 +62,8 @@ struct symbol_conf {
58 sort_by_name, 62 sort_by_name,
59 show_nr_samples, 63 show_nr_samples,
60 use_callchain, 64 use_callchain,
61 exclude_other; 65 exclude_other,
66 full_paths;
62 const char *vmlinux_name, 67 const char *vmlinux_name,
63 *field_sep; 68 *field_sep;
64 char *dso_list_str, 69 char *dso_list_str,
@@ -77,6 +82,12 @@ static inline void *symbol__priv(struct symbol *self)
77 return ((void *)self) - symbol_conf.priv_size; 82 return ((void *)self) - symbol_conf.priv_size;
78} 83}
79 84
85struct ref_reloc_sym {
86 const char *name;
87 u64 addr;
88 u64 unrelocated_addr;
89};
90
80struct addr_location { 91struct addr_location {
81 struct thread *thread; 92 struct thread *thread;
82 struct map *map; 93 struct map *map;
@@ -94,48 +105,68 @@ struct dso {
94 u8 slen_calculated:1; 105 u8 slen_calculated:1;
95 u8 has_build_id:1; 106 u8 has_build_id:1;
96 u8 kernel:1; 107 u8 kernel:1;
108 u8 hit:1;
97 unsigned char origin; 109 unsigned char origin;
98 u8 sorted_by_name; 110 u8 sorted_by_name;
99 u8 loaded; 111 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE]; 112 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name; 113 const char *short_name;
103 char *long_name; 114 char *long_name;
115 u16 long_name_len;
116 u16 short_name_len;
104 char name[0]; 117 char name[0];
105}; 118};
106 119
107struct dso *dso__new(const char *name); 120struct dso *dso__new(const char *name);
121struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 122void dso__delete(struct dso *self);
109 123
110bool dso__loaded(const struct dso *self, enum map_type type); 124bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type); 125bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 126
127static inline void dso__set_loaded(struct dso *self, enum map_type type)
128{
129 self->loaded |= (1 << type);
130}
131
113void dso__sort_by_name(struct dso *self, enum map_type type); 132void dso__sort_by_name(struct dso *self, enum map_type type);
114 133
115struct perf_session; 134extern struct list_head dsos__user, dsos__kernel;
135
136struct dso *__dsos__findnew(struct list_head *head, const char *name);
116 137
117struct dso *dsos__findnew(const char *name); 138static inline struct dso *dsos__findnew(const char *name)
118int dso__load(struct dso *self, struct map *map, struct perf_session *session, 139{
119 symbol_filter_t filter); 140 return __dsos__findnew(&dsos__user, name);
141}
142
143int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
144int dso__load_vmlinux_path(struct dso *self, struct map *map,
145 symbol_filter_t filter);
146int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
147 symbol_filter_t filter);
120void dsos__fprintf(FILE *fp); 148void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp); 149size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
122 150
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 151size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 152size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
125char dso__symtab_origin(const struct dso *self); 153char dso__symtab_origin(const struct dso *self);
154void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 155void dso__set_build_id(struct dso *self, void *build_id);
156void dso__read_running_kernel_build_id(struct dso *self);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 157struct 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, 158struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 159 const char *name);
130 160
131int filename__read_build_id(const char *filename, void *bf, size_t size); 161int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size); 162int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 163bool dsos__read_build_ids(bool with_hits);
134int build_id__sprintf(u8 *self, int len, char *bf); 164int build_id__sprintf(const u8 *self, int len, char *bf);
165int kallsyms__parse(const char *filename, void *arg,
166 int (*process_symbol)(void *arg, const char *name,
167 char type, u64 start));
135 168
136int symbol__init(void); 169int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self); 170bool symbol_type__is_a(char symbol_type, enum map_type map_type);
138 171
139extern struct list_head dsos__user, dsos__kernel;
140extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 172#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 4a08dcf50b68..fa968312ee7d 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -31,12 +31,41 @@ static struct thread *thread__new(pid_t pid)
31 return self; 31 return self;
32} 32}
33 33
34static void map_groups__flush(struct map_groups *self)
35{
36 int type;
37
38 for (type = 0; type < MAP__NR_TYPES; type++) {
39 struct rb_root *root = &self->maps[type];
40 struct rb_node *next = rb_first(root);
41
42 while (next) {
43 struct map *pos = rb_entry(next, struct map, rb_node);
44 next = rb_next(&pos->rb_node);
45 rb_erase(&pos->rb_node, root);
46 /*
47 * We may have references to this map, for
48 * instance in some hist_entry instances, so
49 * just move them to a separate list.
50 */
51 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
52 }
53 }
54}
55
34int thread__set_comm(struct thread *self, const char *comm) 56int thread__set_comm(struct thread *self, const char *comm)
35{ 57{
58 int err;
59
36 if (self->comm) 60 if (self->comm)
37 free(self->comm); 61 free(self->comm);
38 self->comm = strdup(comm); 62 self->comm = strdup(comm);
39 return self->comm ? 0 : -ENOMEM; 63 err = self->comm == NULL ? -ENOMEM : 0;
64 if (!err) {
65 self->comm_set = true;
66 map_groups__flush(&self->mg);
67 }
68 return err;
40} 69}
41 70
42int thread__comm_len(struct thread *self) 71int thread__comm_len(struct thread *self)
@@ -50,13 +79,8 @@ int thread__comm_len(struct thread *self)
50 return self->comm_len; 79 return self->comm_len;
51} 80}
52 81
53static const char *map_type__name[MAP__NR_TYPES] = { 82size_t __map_groups__fprintf_maps(struct map_groups *self,
54 [MAP__FUNCTION] = "Functions", 83 enum map_type type, FILE *fp)
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp)
60{ 84{
61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 85 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
62 struct rb_node *nd; 86 struct rb_node *nd;
@@ -65,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self,
65 struct map *pos = rb_entry(nd, struct map, rb_node); 89 struct map *pos = rb_entry(nd, struct map, rb_node);
66 printed += fprintf(fp, "Map:"); 90 printed += fprintf(fp, "Map:");
67 printed += map__fprintf(pos, fp); 91 printed += map__fprintf(pos, fp);
68 if (verbose > 1) { 92 if (verbose > 2) {
69 printed += dso__fprintf(pos->dso, type, fp); 93 printed += dso__fprintf(pos->dso, type, fp);
70 printed += fprintf(fp, "--\n"); 94 printed += fprintf(fp, "--\n");
71 } 95 }
@@ -159,8 +183,8 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
159 return th; 183 return th;
160} 184}
161 185
162static void map_groups__remove_overlappings(struct map_groups *self, 186static int map_groups__fixup_overlappings(struct map_groups *self,
163 struct map *map) 187 struct map *map)
164{ 188{
165 struct rb_root *root = &self->maps[map->type]; 189 struct rb_root *root = &self->maps[map->type];
166 struct rb_node *next = rb_first(root); 190 struct rb_node *next = rb_first(root);
@@ -185,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self,
185 * list. 209 * list.
186 */ 210 */
187 list_add_tail(&pos->node, &self->removed_maps[map->type]); 211 list_add_tail(&pos->node, &self->removed_maps[map->type]);
212 /*
213 * Now check if we need to create new maps for areas not
214 * overlapped by the new map:
215 */
216 if (map->start > pos->start) {
217 struct map *before = map__clone(pos);
218
219 if (before == NULL)
220 return -ENOMEM;
221
222 before->end = map->start - 1;
223 map_groups__insert(self, before);
224 if (verbose >= 2)
225 map__fprintf(before, stderr);
226 }
227
228 if (map->end < pos->end) {
229 struct map *after = map__clone(pos);
230
231 if (after == NULL)
232 return -ENOMEM;
233
234 after->start = map->end + 1;
235 map_groups__insert(self, after);
236 if (verbose >= 2)
237 map__fprintf(after, stderr);
238 }
188 } 239 }
240
241 return 0;
189} 242}
190 243
191void maps__insert(struct rb_root *maps, struct map *map) 244void maps__insert(struct rb_root *maps, struct map *map)
@@ -230,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
230 283
231void thread__insert_map(struct thread *self, struct map *map) 284void thread__insert_map(struct thread *self, struct map *map)
232{ 285{
233 map_groups__remove_overlappings(&self->mg, map); 286 map_groups__fixup_overlappings(&self->mg, map);
234 map_groups__insert(&self->mg, map); 287 map_groups__insert(&self->mg, map);
235} 288}
236 289
@@ -255,11 +308,14 @@ int thread__fork(struct thread *self, struct thread *parent)
255{ 308{
256 int i; 309 int i;
257 310
258 if (self->comm) 311 if (parent->comm_set) {
259 free(self->comm); 312 if (self->comm)
260 self->comm = strdup(parent->comm); 313 free(self->comm);
261 if (!self->comm) 314 self->comm = strdup(parent->comm);
262 return -ENOMEM; 315 if (!self->comm)
316 return -ENOMEM;
317 self->comm_set = true;
318 }
263 319
264 for (i = 0; i < MAP__NR_TYPES; ++i) 320 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 321 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -282,14 +338,13 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
282} 338}
283 339
284struct symbol *map_groups__find_symbol(struct map_groups *self, 340struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr, 341 enum map_type type, u64 addr,
287 symbol_filter_t filter) 342 symbol_filter_t filter)
288{ 343{
289 struct map *map = map_groups__find(self, type, addr); 344 struct map *map = map_groups__find(self, type, addr);
290 345
291 if (map != NULL) 346 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter); 347 return map__find_symbol(map, map->map_ip(map, addr), filter);
293 348
294 return NULL; 349 return NULL;
295} 350}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72c8881..dcf70303e58e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -10,11 +10,15 @@ struct map_groups {
10 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11}; 11};
12 12
13size_t __map_groups__fprintf_maps(struct map_groups *self,
14 enum map_type type, FILE *fp);
15
13struct thread { 16struct thread {
14 struct rb_node rb_node; 17 struct rb_node rb_node;
15 struct map_groups mg; 18 struct map_groups mg;
16 pid_t pid; 19 pid_t pid;
17 char shortname[3]; 20 char shortname[3];
21 bool comm_set;
18 char *comm; 22 char *comm;
19 int comm_len; 23 int comm_len;
20}; 24};
@@ -48,23 +52,36 @@ static inline struct map *thread__find_map(struct thread *self,
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 52 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 53}
50 54
55void thread__find_addr_map(struct thread *self,
56 struct perf_session *session, u8 cpumode,
57 enum map_type type, u64 addr,
58 struct addr_location *al);
59
51void thread__find_addr_location(struct thread *self, 60void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 61 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 62 enum map_type type, u64 addr,
54 struct addr_location *al, 63 struct addr_location *al,
55 symbol_filter_t filter); 64 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self, 65struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr, 66 enum map_type type, u64 addr,
59 symbol_filter_t filter); 67 symbol_filter_t filter);
60 68
61static inline struct symbol * 69static inline struct symbol *map_groups__find_function(struct map_groups *self,
62map_groups__find_function(struct map_groups *self, struct perf_session *session, 70 u64 addr,
63 u64 addr, symbol_filter_t filter) 71 symbol_filter_t filter)
64{ 72{
65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter); 73 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
66} 74}
67 75
68struct map *map_groups__find_by_name(struct map_groups *self, 76struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name); 77 enum map_type type, const char *name);
78
79int __map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES],
81 struct dso *kernel);
82int map_groups__create_kernel_maps(struct map_groups *self,
83 struct map *vmlinux_maps[MAP__NR_TYPES]);
84
85struct map *map_groups__new_module(struct map_groups *self, u64 start,
86 const char *filename);
70#endif /* __PERF_THREAD_H */ 87#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..5ea8973ad331 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -271,6 +253,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 253 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 254 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 255 check_size = copy_file_fd(fd);
256 close(fd);
257
274 if (size != check_size) 258 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 259 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 260 path, size, check_size);
@@ -289,6 +273,7 @@ static void read_header_files(void)
289 if (size != check_size) 273 if (size != check_size)
290 die("wrong size for '%s'", path); 274 die("wrong size for '%s'", path);
291 put_tracing_file(path); 275 put_tracing_file(path);
276 close(fd);
292} 277}
293 278
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 279static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +302,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 302 die("can't read directory '%s'", sys);
318 303
319 while ((dent = readdir(dir))) { 304 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 305 if (dent->d_type != DT_DIR ||
306 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 307 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 308 !name_in_tp_list(dent->d_name, tps))
323 continue; 309 continue;
@@ -334,7 +320,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 320
335 rewinddir(dir); 321 rewinddir(dir);
336 while ((dent = readdir(dir))) { 322 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 323 if (dent->d_type != DT_DIR ||
324 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 325 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 326 !name_in_tp_list(dent->d_name, tps))
340 continue; 327 continue;
@@ -353,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 340
354 free(format); 341 free(format);
355 } 342 }
343 closedir(dir);
356} 344}
357 345
358static void read_ftrace_files(struct tracepoint_path *tps) 346static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +382,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 382 die("can't read directory '%s'", path);
395 383
396 while ((dent = readdir(dir))) { 384 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 385 if (dent->d_type != DT_DIR ||
386 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 387 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 389 !system_in_tp_list(dent->d_name, tps))
401 continue; 390 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 391 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 392 }
411 393
412 write_or_die(&count, 4); 394 write_or_die(&count, 4);
413 395
414 rewinddir(dir); 396 rewinddir(dir);
415 while ((dent = readdir(dir))) { 397 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 398 if (dent->d_type != DT_DIR ||
399 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 400 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 402 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +405,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 405 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 406 ret = stat(sys, &st);
424 if (ret >= 0) { 407 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 410 }
430 free(sys); 411 free(sys);
431 } 412 }
432 413
414 closedir(dir);
433 put_tracing_file(path); 415 put_tracing_file(path);
434} 416}
435 417
@@ -533,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 515 write_or_die(buf, 1);
534 516
535 /* save page_size */ 517 /* save page_size */
536 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
538 520
539 read_header_files(); 521 read_header_files();
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index c5c32be040bf..9b3c20f42f98 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1925,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1925 if (!field) 1925 if (!field)
1926 return NULL; 1926 return NULL;
1927 1927
1928 if (field->flags & FIELD_IS_STRING) {
1929 int offset;
1930
1931 offset = *(int *)(data + field->offset);
1932 offset &= 0xffff;
1933
1934 return data + offset;
1935 }
1936
1928 return data + field->offset; 1937 return data + field->offset;
1929} 1938}
1930 1939
@@ -3277,3 +3286,18 @@ void parse_set_info(int nr_cpus, int long_sz)
3277 cpus = nr_cpus; 3286 cpus = nr_cpus;
3278 long_size = long_sz; 3287 long_size = long_sz;
3279} 3288}
3289
3290int common_pc(struct scripting_context *context)
3291{
3292 return parse_common_pc(context->event_data);
3293}
3294
3295int common_flags(struct scripting_context *context)
3296{
3297 return parse_common_flags(context->event_data);
3298}
3299
3300int common_lock_depth(struct scripting_context *context)
3301{
3302 return parse_common_lock_depth(context->event_data);
3303}
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
deleted file mode 100644
index e88fb26137bb..000000000000
--- a/tools/perf/util/trace-event-perl.h
+++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
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) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1744422cafcb..7cd1193918c7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -83,7 +83,7 @@ static char *read_string(void)
83 char *str = NULL; 83 char *str = NULL;
84 int size = 0; 84 int size = 0;
85 int i; 85 int i;
86 int r; 86 off_t r;
87 87
88 for (;;) { 88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 89 r = read(input_fd, buf, BUFSIZ);
@@ -118,7 +118,7 @@ static char *read_string(void)
118 118
119 /* move the file descriptor to the end of the string */ 119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR); 120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0) 121 if (r == (off_t)-1)
122 die("lseek"); 122 die("lseek");
123 123
124 if (str) { 124 if (str) {
@@ -282,8 +282,8 @@ static void update_cpu_data_index(int cpu)
282 282
283static void get_next_page(int cpu) 283static void get_next_page(int cpu)
284{ 284{
285 off64_t save_seek; 285 off_t save_seek;
286 off64_t ret; 286 off_t ret;
287 287
288 if (!cpu_data[cpu].page) 288 if (!cpu_data[cpu].page)
289 return; 289 return;
@@ -298,17 +298,17 @@ static void get_next_page(int cpu)
298 update_cpu_data_index(cpu); 298 update_cpu_data_index(cpu);
299 299
300 /* other parts of the code may expect the pointer to not move */ 300 /* other parts of the code may expect the pointer to not move */
301 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 save_seek = lseek(input_fd, 0, SEEK_CUR);
302 302
303 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
304 if (ret < 0) 304 if (ret == (off_t)-1)
305 die("failed to lseek"); 305 die("failed to lseek");
306 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 ret = read(input_fd, cpu_data[cpu].page, page_size);
307 if (ret < 0) 307 if (ret < 0)
308 die("failed to read page"); 308 die("failed to read page");
309 309
310 /* reset the file pointer back */ 310 /* reset the file pointer back */
311 lseek64(input_fd, save_seek, SEEK_SET); 311 lseek(input_fd, save_seek, SEEK_SET);
312 312
313 return; 313 return;
314 } 314 }
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..7ea983acfaea
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 6ad405620c9b..c3269b937db4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -279,7 +279,15 @@ struct scripting_ops {
279 279
280int script_spec_register(const char *spec, struct scripting_ops *ops); 280int script_spec_register(const char *spec, struct scripting_ops *ops);
281 281
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 282void setup_perl_scripting(void);
283void setup_python_scripting(void);
284
285struct scripting_context {
286 void *event_data;
287};
288
289int common_pc(struct scripting_context *context);
290int common_flags(struct scripting_context *context);
291int common_lock_depth(struct scripting_context *context);
284 292
285#endif /* __PERF_TRACE_EVENTS_H */ 293#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..f9b890fde681
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,94 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 403#endif
404#endif 404#endif
405 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
406#endif 409#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,