blob: aa8a03120bbd572d76b164fe2ca3856a7516a035 [file] [log] [blame]
Xiao Guangrongb8f46c52010-02-03 11:53:14 +08001#define _LARGEFILE64_SOURCE
2#define _FILE_OFFSET_BITS 64
3
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02004#include <linux/kernel.h>
5
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -02006#include <byteswap.h>
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -02007#include <unistd.h>
8#include <sys/types.h>
9
10#include "session.h"
Arnaldo Carvalho de Meloa3286262009-12-14 14:22:59 -020011#include "sort.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020012#include "util.h"
13
14static int perf_session__open(struct perf_session *self, bool force)
15{
16 struct stat input_stat;
17
Xiao Guangrongb8f46c52010-02-03 11:53:14 +080018 self->fd = open(self->filename, O_RDONLY|O_LARGEFILE);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020019 if (self->fd < 0) {
20 pr_err("failed to open file: %s", self->filename);
21 if (!strcmp(self->filename, "perf.data"))
22 pr_err(" (try 'perf record' first)");
23 pr_err("\n");
24 return -errno;
25 }
26
27 if (fstat(self->fd, &input_stat) < 0)
28 goto out_close;
29
30 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
31 pr_err("file %s not owned by current user or root\n",
32 self->filename);
33 goto out_close;
34 }
35
36 if (!input_stat.st_size) {
37 pr_info("zero-sized file (%s), nothing to do!\n",
38 self->filename);
39 goto out_close;
40 }
41
42 if (perf_header__read(&self->header, self->fd) < 0) {
43 pr_err("incompatible file format");
44 goto out_close;
45 }
46
47 self->size = input_stat.st_size;
48 return 0;
49
50out_close:
51 close(self->fd);
52 self->fd = -1;
53 return -1;
54}
55
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020056static inline int perf_session__create_kernel_maps(struct perf_session *self)
57{
58 return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
59}
60
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020061struct perf_session *perf_session__new(const char *filename, int mode, bool force)
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020062{
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020063 size_t len = filename ? strlen(filename) + 1 : 0;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020064 struct perf_session *self = zalloc(sizeof(*self) + len);
65
66 if (self == NULL)
67 goto out;
68
69 if (perf_header__init(&self->header) < 0)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -020070 goto out_free;
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020071
72 memcpy(self->filename, filename, len);
Arnaldo Carvalho de Melob3165f42009-12-13 19:50:28 -020073 self->threads = RB_ROOT;
74 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 Melod549c7692009-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
120struct symbol **perf_session__resolve_callchain(struct perf_session *self,
121 struct thread *thread,
122 struct ip_callchain *chain,
123 struct symbol **parent)
124{
125 u8 cpumode = PERF_RECORD_MISC_USER;
126 struct symbol **syms = NULL;
127 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;
163 syms[i] = al.sym;
164 }
165 }
166
167 return syms;
168}
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200169
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{
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200179 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;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200197}
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
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200222void 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
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200286static int perf_session__process_event(struct perf_session *self,
287 event_t *event,
288 struct perf_event_ops *ops,
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200289 u64 offset, u64 head)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200290{
291 trace_event(event);
292
293 if (event->header.type < PERF_RECORD_MAX) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200294 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200295 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200296 event__name[event->header.type]);
297 ++event__total[0];
298 ++event__total[event->header.type];
299 }
300
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200301 if (self->header.needs_swap && event__swap_ops[event->header.type])
302 event__swap_ops[event->header.type](event);
303
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200304 switch (event->header.type) {
305 case PERF_RECORD_SAMPLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200306 return ops->sample(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200307 case PERF_RECORD_MMAP:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200308 return ops->mmap(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200309 case PERF_RECORD_COMM:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200310 return ops->comm(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200311 case PERF_RECORD_FORK:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200312 return ops->fork(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200313 case PERF_RECORD_EXIT:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200314 return ops->exit(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200315 case PERF_RECORD_LOST:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200316 return ops->lost(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200317 case PERF_RECORD_READ:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200318 return ops->read(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200319 case PERF_RECORD_THROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200320 return ops->throttle(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200321 case PERF_RECORD_UNTHROTTLE:
Arnaldo Carvalho de Melo55aa6402009-12-27 21:37:05 -0200322 return ops->unthrottle(event, self);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200323 default:
Arnaldo Carvalho de Melo31d337c2009-12-27 21:37:03 -0200324 self->unknown_events++;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200325 return -1;
326 }
327}
328
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200329void 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)
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200338{
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;
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -0200347 struct list_head *head = &dsos__user;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200348
349 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
350 goto out;
351
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200352 if (self->needs_swap)
353 perf_event_header__bswap(&bev.header);
354
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200355 len = bev.header.size - sizeof(bev);
356 if (read(input, filename, len) != len)
357 goto out;
358
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -0200359 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
360 head = &dsos__kernel;
361
362 dso = __dsos__findnew(head, filename);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200363 if (dso != NULL) {
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200364 dso__set_build_id(dso, &bev.build_id);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200365 if (head == &dsos__kernel && filename[0] == '[')
366 dso->kernel = 1;
367 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200368
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 struct perf_event_ops *ops)
390{
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200391 int err, mmap_prot, mmap_flags;
392 u64 head, shift;
393 u64 offset = 0;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200394 size_t page_size;
395 event_t *event;
396 uint32_t size;
397 char *buf;
398
399 if (perf_session__register_idle_thread(self) == NULL)
400 return -ENOMEM;
401
402 perf_event_ops__fill_defaults(ops);
403
Arnaldo Carvalho de Melo1b759622010-01-14 18:30:04 -0200404 page_size = sysconf(_SC_PAGESIZE);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200405
406 head = self->header.data_offset;
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200407
Arnaldo Carvalho de Melof7d87442009-12-27 21:37:04 -0200408 if (!symbol_conf.full_paths) {
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200409 char bf[PATH_MAX];
410
411 if (getcwd(bf, sizeof(bf)) == NULL) {
412 err = -errno;
413out_getcwd_err:
414 pr_err("failed to get the current directory\n");
415 goto out_err;
416 }
417 self->cwd = strdup(bf);
418 if (self->cwd == NULL) {
419 err = -ENOMEM;
420 goto out_getcwd_err;
421 }
422 self->cwdlen = strlen(self->cwd);
423 }
424
425 shift = page_size * (head / page_size);
426 offset += shift;
427 head -= shift;
428
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200429 mmap_prot = PROT_READ;
430 mmap_flags = MAP_SHARED;
431
432 if (self->header.needs_swap) {
433 mmap_prot |= PROT_WRITE;
434 mmap_flags = MAP_PRIVATE;
435 }
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200436remap:
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200437 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
438 mmap_flags, self->fd, offset);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200439 if (buf == MAP_FAILED) {
440 pr_err("failed to mmap file\n");
441 err = -errno;
442 goto out_err;
443 }
444
445more:
446 event = (event_t *)(buf + head);
447
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200448 if (self->header.needs_swap)
449 perf_event_header__bswap(&event->header);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200450 size = event->header.size;
451 if (size == 0)
452 size = 8;
453
454 if (head + event->header.size >= page_size * self->mmap_window) {
455 int munmap_ret;
456
457 shift = page_size * (head / page_size);
458
459 munmap_ret = munmap(buf, page_size * self->mmap_window);
460 assert(munmap_ret == 0);
461
462 offset += shift;
463 head -= shift;
464 goto remap;
465 }
466
467 size = event->header.size;
468
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200469 dump_printf("\n%#Lx [%#x]: event: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200470 offset + head, event->header.size, event->header.type);
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200471
472 if (size == 0 ||
473 perf_session__process_event(self, event, ops, offset, head) < 0) {
Arnaldo Carvalho de Meloba215942010-01-14 12:23:10 -0200474 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
Arnaldo Carvalho de Melo0d755032010-01-14 12:23:09 -0200475 offset + head, event->header.size,
Arnaldo Carvalho de Melo06aae592009-12-27 21:36:59 -0200476 event->header.type);
477 /*
478 * assume we lost track of the stream, check alignment, and
479 * increment a single u64 in the hope to catch on again 'soon'.
480 */
481 if (unlikely(head & 7))
482 head &= ~7ULL;
483
484 size = 8;
485 }
486
487 head += size;
488
489 if (offset + head >= self->header.data_offset + self->header.data_size)
490 goto done;
491
492 if (offset + head < self->size)
493 goto more;
494done:
495 err = 0;
496out_err:
497 return err;
498}
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200499
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200500bool perf_session__has_traces(struct perf_session *self, const char *msg)
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200501{
502 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200503 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
504 return false;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200505 }
506
Arnaldo Carvalho de Melod549c7692009-12-27 21:37:02 -0200507 return true;
Arnaldo Carvalho de Melo27295592009-12-27 21:37:01 -0200508}
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200509
510int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
511 const char *symbol_name,
512 u64 addr)
513{
514 char *bracket;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200515 enum map_type i;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200516
517 self->ref_reloc_sym.name = strdup(symbol_name);
518 if (self->ref_reloc_sym.name == NULL)
519 return -ENOMEM;
520
521 bracket = strchr(self->ref_reloc_sym.name, ']');
522 if (bracket)
523 *bracket = '\0';
524
525 self->ref_reloc_sym.addr = addr;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200526
527 for (i = 0; i < MAP__NR_TYPES; ++i) {
528 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
529 kmap->ref_reloc_sym = &self->ref_reloc_sym;
530 }
531
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200532 return 0;
533}
534
535static u64 map__reloc_map_ip(struct map *map, u64 ip)
536{
537 return ip + (s64)map->pgoff;
538}
539
540static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
541{
542 return ip - (s64)map->pgoff;
543}
544
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200545void map__reloc_vmlinux(struct map *self)
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200546{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200547 struct kmap *kmap = map__kmap(self);
548 s64 reloc;
549
550 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
551 return;
552
553 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
554 kmap->ref_reloc_sym->addr);
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200555
556 if (!reloc)
557 return;
558
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200559 self->map_ip = map__reloc_map_ip;
560 self->unmap_ip = map__reloc_unmap_ip;
561 self->pgoff = reloc;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200562}