blob: 2cef3730cd990dfb14fc3c6680c907828ed154eb [file] [log] [blame]
Xiao Guangrongb8f46c52010-02-03 11:53:14 +08001#define _FILE_OFFSET_BITS 64
2
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02003#include <linux/kernel.h>
4
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -02005#include <byteswap.h>
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02006#include <unistd.h>
7#include <sys/types.h>
8
9#include "session.h"
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -020010#include "sort.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020011#include "util.h"
12
13static int perf_session__open(struct perf_session *self, bool force)
14{
15 struct stat input_stat;
16
Xiao Guangrongf887f302010-02-04 16:46:42 +080017 self->fd = open(self->filename, O_RDONLY);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020018 if (self->fd < 0) {
19 pr_err("failed to open file: %s", self->filename);
20 if (!strcmp(self->filename, "perf.data"))
21 pr_err(" (try 'perf record' first)");
22 pr_err("\n");
23 return -errno;
24 }
25
26 if (fstat(self->fd, &input_stat) < 0)
27 goto out_close;
28
29 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
30 pr_err("file %s not owned by current user or root\n",
31 self->filename);
32 goto out_close;
33 }
34
35 if (!input_stat.st_size) {
36 pr_info("zero-sized file (%s), nothing to do!\n",
37 self->filename);
38 goto out_close;
39 }
40
41 if (perf_header__read(&self->header, self->fd) < 0) {
42 pr_err("incompatible file format");
43 goto out_close;
44 }
45
46 self->size = input_stat.st_size;
47 return 0;
48
49out_close:
50 close(self->fd);
51 self->fd = -1;
52 return -1;
53}
54
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020055static 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
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020060struct perf_session *perf_session__new(const char *filename, int mode, bool force)
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020061{
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020062 size_t len = filename ? strlen(filename) + 1 : 0;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020063 struct perf_session *self = zalloc(sizeof(*self) + len);
64
65 if (self == NULL)
66 goto out;
67
68 if (perf_header__init(&self->header) < 0)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020069 goto out_free;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020070
71 memcpy(self->filename, filename, len);
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020072 self->threads = RB_ROOT;
Eric B Munsoncb8f0932010-03-05 12:51:07 -030073 self->stats_by_id = RB_ROOT;
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020074 self->last_match = NULL;
Arnaldo Carvalho de Meloec913362009-12-13 19:50:27 -020075 self->mmap_window = 32;
76 self->cwd = NULL;
77 self->cwdlen = 0;
Arnaldo Carvalho de Melo31d337c2009-12-27 21:37:03 -020078 self->unknown_events = 0;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020079 map_groups__init(&self->kmaps);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020080
Arnaldo Carvalho de Melo64abebf2010-01-27 21:05:52 -020081 if (mode == O_RDONLY) {
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 }
Arnaldo Carvalho de Melod549c762009-12-27 21:37:02 -020092
93 self->sample_type = perf_header__sample_type(&self->header);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020094out:
95 return self;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020096out_free:
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020097 free(self);
98 return NULL;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020099out_delete:
100 perf_session__delete(self);
101 return NULL;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200102}
103
104void perf_session__delete(struct perf_session *self)
105{
106 perf_header__exit(&self->header);
107 close(self->fd);
Arnaldo Carvalho de Meloec913362009-12-13 19:50:27 -0200108 free(self->cwd);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200109 free(self);
110}
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200111
112static bool symbol__match_parent_regex(struct symbol *sym)
113{
114 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
115 return 1;
116
117 return 0;
118}
119
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300120struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
121 struct thread *thread,
122 struct ip_callchain *chain,
123 struct symbol **parent)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200124{
125 u8 cpumode = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300126 struct map_symbol *syms = NULL;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200127 unsigned int i;
128
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200129 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200130 syms = calloc(chain->nr, sizeof(*syms));
131 if (!syms) {
132 fprintf(stderr, "Can't allocate memory for symbols\n");
133 exit(-1);
134 }
135 }
136
137 for (i = 0; i < chain->nr; i++) {
138 u64 ip = chain->ips[i];
139 struct addr_location al;
140
141 if (ip >= PERF_CONTEXT_MAX) {
142 switch (ip) {
143 case PERF_CONTEXT_HV:
144 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
145 case PERF_CONTEXT_KERNEL:
146 cpumode = PERF_RECORD_MISC_KERNEL; break;
147 case PERF_CONTEXT_USER:
148 cpumode = PERF_RECORD_MISC_USER; break;
149 default:
150 break;
151 }
152 continue;
153 }
154
155 thread__find_addr_location(thread, self, cpumode,
156 MAP__FUNCTION, ip, &al, NULL);
157 if (al.sym != NULL) {
158 if (sort__has_parent && !*parent &&
159 symbol__match_parent_regex(al.sym))
160 *parent = al.sym;
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200161 if (!symbol_conf.use_callchain)
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200162 break;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300163 syms[i].map = al.map;
164 syms[i].sym = al.sym;
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -0200165 }
166 }
167
168 return syms;
169}
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200170
171static int process_event_stub(event_t *event __used,
172 struct perf_session *session __used)
173{
174 dump_printf(": unhandled!\n");
175 return 0;
176}
177
178static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
179{
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200180 if (handler->sample == NULL)
181 handler->sample = process_event_stub;
182 if (handler->mmap == NULL)
183 handler->mmap = process_event_stub;
184 if (handler->comm == NULL)
185 handler->comm = process_event_stub;
186 if (handler->fork == NULL)
187 handler->fork = process_event_stub;
188 if (handler->exit == NULL)
189 handler->exit = process_event_stub;
190 if (handler->lost == NULL)
191 handler->lost = process_event_stub;
192 if (handler->read == NULL)
193 handler->read = process_event_stub;
194 if (handler->throttle == NULL)
195 handler->throttle = process_event_stub;
196 if (handler->unthrottle == NULL)
197 handler->unthrottle = process_event_stub;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200198}
199
200static const char *event__name[] = {
201 [0] = "TOTAL",
202 [PERF_RECORD_MMAP] = "MMAP",
203 [PERF_RECORD_LOST] = "LOST",
204 [PERF_RECORD_COMM] = "COMM",
205 [PERF_RECORD_EXIT] = "EXIT",
206 [PERF_RECORD_THROTTLE] = "THROTTLE",
207 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
208 [PERF_RECORD_FORK] = "FORK",
209 [PERF_RECORD_READ] = "READ",
210 [PERF_RECORD_SAMPLE] = "SAMPLE",
211};
212
213unsigned long event__total[PERF_RECORD_MAX];
214
215void event__print_totals(void)
216{
217 int i;
218 for (i = 0; i < PERF_RECORD_MAX; ++i)
219 pr_info("%10s events: %10ld\n",
220 event__name[i], event__total[i]);
221}
222
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200223void mem_bswap_64(void *src, int byte_size)
224{
225 u64 *m = src;
226
227 while (byte_size > 0) {
228 *m = bswap_64(*m);
229 byte_size -= sizeof(u64);
230 ++m;
231 }
232}
233
234static void event__all64_swap(event_t *self)
235{
236 struct perf_event_header *hdr = &self->header;
237 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
238}
239
240static void event__comm_swap(event_t *self)
241{
242 self->comm.pid = bswap_32(self->comm.pid);
243 self->comm.tid = bswap_32(self->comm.tid);
244}
245
246static void event__mmap_swap(event_t *self)
247{
248 self->mmap.pid = bswap_32(self->mmap.pid);
249 self->mmap.tid = bswap_32(self->mmap.tid);
250 self->mmap.start = bswap_64(self->mmap.start);
251 self->mmap.len = bswap_64(self->mmap.len);
252 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
253}
254
255static void event__task_swap(event_t *self)
256{
257 self->fork.pid = bswap_32(self->fork.pid);
258 self->fork.tid = bswap_32(self->fork.tid);
259 self->fork.ppid = bswap_32(self->fork.ppid);
260 self->fork.ptid = bswap_32(self->fork.ptid);
261 self->fork.time = bswap_64(self->fork.time);
262}
263
264static void event__read_swap(event_t *self)
265{
266 self->read.pid = bswap_32(self->read.pid);
267 self->read.tid = bswap_32(self->read.tid);
268 self->read.value = bswap_64(self->read.value);
269 self->read.time_enabled = bswap_64(self->read.time_enabled);
270 self->read.time_running = bswap_64(self->read.time_running);
271 self->read.id = bswap_64(self->read.id);
272}
273
274typedef void (*event__swap_op)(event_t *self);
275
276static event__swap_op event__swap_ops[] = {
277 [PERF_RECORD_MMAP] = event__mmap_swap,
278 [PERF_RECORD_COMM] = event__comm_swap,
279 [PERF_RECORD_FORK] = event__task_swap,
280 [PERF_RECORD_EXIT] = event__task_swap,
281 [PERF_RECORD_LOST] = event__all64_swap,
282 [PERF_RECORD_READ] = event__read_swap,
283 [PERF_RECORD_SAMPLE] = event__all64_swap,
284 [PERF_RECORD_MAX] = NULL,
285};
286
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200287static int perf_session__process_event(struct perf_session *self,
288 event_t *event,
289 struct perf_event_ops *ops,
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200290 u64 offset, u64 head)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200291{
292 trace_event(event);
293
294 if (event->header.type < PERF_RECORD_MAX) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200295 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200296 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200297 event__name[event->header.type]);
298 ++event__total[0];
299 ++event__total[event->header.type];
300 }
301
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200302 if (self->header.needs_swap && event__swap_ops[event->header.type])
303 event__swap_ops[event->header.type](event);
304
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200305 switch (event->header.type) {
306 case PERF_RECORD_SAMPLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200307 return ops->sample(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200308 case PERF_RECORD_MMAP:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200309 return ops->mmap(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200310 case PERF_RECORD_COMM:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200311 return ops->comm(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200312 case PERF_RECORD_FORK:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200313 return ops->fork(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200314 case PERF_RECORD_EXIT:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200315 return ops->exit(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200316 case PERF_RECORD_LOST:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200317 return ops->lost(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200318 case PERF_RECORD_READ:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200319 return ops->read(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200320 case PERF_RECORD_THROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200321 return ops->throttle(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200322 case PERF_RECORD_UNTHROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200323 return ops->unthrottle(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200324 default:
Arnaldo Carvalho de Melo31d337c2009-12-27 21:37:03 -0200325 self->unknown_events++;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200326 return -1;
327 }
328}
329
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200330void perf_event_header__bswap(struct perf_event_header *self)
331{
332 self->type = bswap_32(self->type);
333 self->misc = bswap_16(self->misc);
334 self->size = bswap_16(self->size);
335}
336
337int perf_header__read_build_ids(struct perf_header *self,
338 int input, u64 offset, u64 size)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200339{
340 struct build_id_event bev;
341 char filename[PATH_MAX];
342 u64 limit = offset + size;
343 int err = -1;
344
345 while (offset < limit) {
346 struct dso *dso;
347 ssize_t len;
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -0200348 struct list_head *head = &dsos__user;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200349
350 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
351 goto out;
352
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200353 if (self->needs_swap)
354 perf_event_header__bswap(&bev.header);
355
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200356 len = bev.header.size - sizeof(bev);
357 if (read(input, filename, len) != len)
358 goto out;
359
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -0200360 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
361 head = &dsos__kernel;
362
363 dso = __dsos__findnew(head, filename);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200364 if (dso != NULL) {
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200365 dso__set_build_id(dso, &bev.build_id);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200366 if (head == &dsos__kernel && filename[0] == '[')
367 dso->kernel = 1;
368 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200369
370 offset += bev.header.size;
371 }
372 err = 0;
373out:
374 return err;
375}
376
377static struct thread *perf_session__register_idle_thread(struct perf_session *self)
378{
379 struct thread *thread = perf_session__findnew(self, 0);
380
381 if (thread == NULL || thread__set_comm(thread, "swapper")) {
382 pr_err("problem inserting idle task.\n");
383 thread = NULL;
384 }
385
386 return thread;
387}
388
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200389int __perf_session__process_events(struct perf_session *self,
390 u64 data_offset, u64 data_size,
391 u64 file_size, struct perf_event_ops *ops)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200392{
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200393 int err, mmap_prot, mmap_flags;
394 u64 head, shift;
395 u64 offset = 0;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200396 size_t page_size;
397 event_t *event;
398 uint32_t size;
399 char *buf;
400
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200401 perf_event_ops__fill_defaults(ops);
402
Arnaldo Carvalho de Melo1b759622010-01-14 18:30:04 -0200403 page_size = sysconf(_SC_PAGESIZE);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200404
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200405 head = data_offset;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200406 shift = page_size * (head / page_size);
407 offset += shift;
408 head -= shift;
409
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200410 mmap_prot = PROT_READ;
411 mmap_flags = MAP_SHARED;
412
413 if (self->header.needs_swap) {
414 mmap_prot |= PROT_WRITE;
415 mmap_flags = MAP_PRIVATE;
416 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200417remap:
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200418 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
419 mmap_flags, self->fd, offset);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200420 if (buf == MAP_FAILED) {
421 pr_err("failed to mmap file\n");
422 err = -errno;
423 goto out_err;
424 }
425
426more:
427 event = (event_t *)(buf + head);
428
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200429 if (self->header.needs_swap)
430 perf_event_header__bswap(&event->header);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200431 size = event->header.size;
432 if (size == 0)
433 size = 8;
434
435 if (head + event->header.size >= page_size * self->mmap_window) {
436 int munmap_ret;
437
438 shift = page_size * (head / page_size);
439
440 munmap_ret = munmap(buf, page_size * self->mmap_window);
441 assert(munmap_ret == 0);
442
443 offset += shift;
444 head -= shift;
445 goto remap;
446 }
447
448 size = event->header.size;
449
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200450 dump_printf("\n%#Lx [%#x]: event: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200451 offset + head, event->header.size, event->header.type);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200452
453 if (size == 0 ||
454 perf_session__process_event(self, event, ops, offset, head) < 0) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200455 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200456 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200457 event->header.type);
458 /*
459 * assume we lost track of the stream, check alignment, and
460 * increment a single u64 in the hope to catch on again 'soon'.
461 */
462 if (unlikely(head & 7))
463 head &= ~7ULL;
464
465 size = 8;
466 }
467
468 head += size;
469
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200470 if (offset + head >= data_offset + data_size)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200471 goto done;
472
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200473 if (offset + head < file_size)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200474 goto more;
475done:
476 err = 0;
477out_err:
478 return err;
479}
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200480
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200481int perf_session__process_events(struct perf_session *self,
482 struct perf_event_ops *ops)
483{
484 int err;
485
486 if (perf_session__register_idle_thread(self) == NULL)
487 return -ENOMEM;
488
489 if (!symbol_conf.full_paths) {
490 char bf[PATH_MAX];
491
492 if (getcwd(bf, sizeof(bf)) == NULL) {
493 err = -errno;
494out_getcwd_err:
495 pr_err("failed to get the current directory\n");
496 goto out_err;
497 }
498 self->cwd = strdup(bf);
499 if (self->cwd == NULL) {
500 err = -ENOMEM;
501 goto out_getcwd_err;
502 }
503 self->cwdlen = strlen(self->cwd);
504 }
505
506 err = __perf_session__process_events(self, self->header.data_offset,
507 self->header.data_size,
508 self->size, ops);
509out_err:
510 return err;
511}
512
Arnaldo Carvalho de Melod549c762009-12-27 21:37:02 -0200513bool perf_session__has_traces(struct perf_session *self, const char *msg)
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200514{
515 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
Arnaldo Carvalho de Melod549c762009-12-27 21:37:02 -0200516 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
517 return false;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200518 }
519
Arnaldo Carvalho de Melod549c762009-12-27 21:37:02 -0200520 return true;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200521}
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200522
523int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
524 const char *symbol_name,
525 u64 addr)
526{
527 char *bracket;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200528 enum map_type i;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200529
530 self->ref_reloc_sym.name = strdup(symbol_name);
531 if (self->ref_reloc_sym.name == NULL)
532 return -ENOMEM;
533
534 bracket = strchr(self->ref_reloc_sym.name, ']');
535 if (bracket)
536 *bracket = '\0';
537
538 self->ref_reloc_sym.addr = addr;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200539
540 for (i = 0; i < MAP__NR_TYPES; ++i) {
541 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
542 kmap->ref_reloc_sym = &self->ref_reloc_sym;
543 }
544
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200545 return 0;
546}
547
548static u64 map__reloc_map_ip(struct map *map, u64 ip)
549{
550 return ip + (s64)map->pgoff;
551}
552
553static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
554{
555 return ip - (s64)map->pgoff;
556}
557
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200558void map__reloc_vmlinux(struct map *self)
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200559{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200560 struct kmap *kmap = map__kmap(self);
561 s64 reloc;
562
563 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
564 return;
565
566 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
567 kmap->ref_reloc_sym->addr);
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200568
569 if (!reloc)
570 return;
571
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200572 self->map_ip = map__reloc_map_ip;
573 self->unmap_ip = map__reloc_unmap_ip;
574 self->pgoff = reloc;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200575}