aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r--tools/perf/util/event.c324
1 files changed, 236 insertions, 88 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 705ec63548b4..e3fa8d3d11b4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -112,7 +112,11 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 event_t ev = { 112 event_t ev = {
113 .header = { 113 .header = {
114 .type = PERF_RECORD_MMAP, 114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */ 115 /*
116 * Just like the kernel, see __perf_event_mmap
117 * in kernel/perf_event.c
118 */
119 .misc = PERF_RECORD_MISC_USER,
116 }, 120 },
117 }; 121 };
118 int n; 122 int n;
@@ -130,6 +134,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
130 continue; 134 continue;
131 pbf += n + 3; 135 pbf += n + 3;
132 if (*pbf == 'x') { /* vm_exec */ 136 if (*pbf == 'x') { /* vm_exec */
137 u64 vm_pgoff;
133 char *execname = strchr(bf, '/'); 138 char *execname = strchr(bf, '/');
134 139
135 /* Catch VDSO */ 140 /* Catch VDSO */
@@ -139,6 +144,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
139 if (execname == NULL) 144 if (execname == NULL)
140 continue; 145 continue;
141 146
147 pbf += 3;
148 n = hex2u64(pbf, &vm_pgoff);
149 /* pgoff is in bytes, not pages */
150 if (n >= 0)
151 ev.mmap.pgoff = vm_pgoff << getpagesize();
152 else
153 ev.mmap.pgoff = 0;
154
142 size = strlen(execname); 155 size = strlen(execname);
143 execname[size - 1] = '\0'; /* Remove \n */ 156 execname[size - 1] = '\0'; /* Remove \n */
144 memcpy(ev.mmap.filename, execname, size); 157 memcpy(ev.mmap.filename, execname, size);
@@ -158,11 +171,23 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
158} 171}
159 172
160int event__synthesize_modules(event__handler_t process, 173int event__synthesize_modules(event__handler_t process,
161 struct perf_session *session) 174 struct perf_session *session,
175 struct kernel_info *kerninfo)
162{ 176{
163 struct rb_node *nd; 177 struct rb_node *nd;
178 struct map_groups *kmaps = &kerninfo->kmaps;
179 u16 misc;
180
181 /*
182 * kernel uses 0 for user space maps, see kernel/perf_event.c
183 * __perf_event_mmap
184 */
185 if (is_host_kernel(kerninfo))
186 misc = PERF_RECORD_MISC_KERNEL;
187 else
188 misc = PERF_RECORD_MISC_GUEST_KERNEL;
164 189
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]); 190 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) { 191 nd; nd = rb_next(nd)) {
167 event_t ev; 192 event_t ev;
168 size_t size; 193 size_t size;
@@ -173,12 +198,13 @@ int event__synthesize_modules(event__handler_t process,
173 198
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 199 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev)); 200 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 */ 201 ev.mmap.header.misc = misc;
177 ev.mmap.header.type = PERF_RECORD_MMAP; 202 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) - 203 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size)); 204 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start; 205 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start; 206 ev.mmap.len = pos->end - pos->start;
207 ev.mmap.pid = kerninfo->pid;
182 208
183 memcpy(ev.mmap.filename, pos->dso->long_name, 209 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1); 210 pos->dso->long_name_len + 1);
@@ -241,13 +267,18 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
241 267
242int event__synthesize_kernel_mmap(event__handler_t process, 268int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session, 269 struct perf_session *session,
270 struct kernel_info *kerninfo,
244 const char *symbol_name) 271 const char *symbol_name)
245{ 272{
246 size_t size; 273 size_t size;
274 const char *filename, *mmap_name;
275 char path[PATH_MAX];
276 char name_buff[PATH_MAX];
277 struct map *map;
278
247 event_t ev = { 279 event_t ev = {
248 .header = { 280 .header = {
249 .type = PERF_RECORD_MMAP, 281 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 }, 282 },
252 }; 283 };
253 /* 284 /*
@@ -257,16 +288,37 @@ int event__synthesize_kernel_mmap(event__handler_t process,
257 */ 288 */
258 struct process_symbol_args args = { .name = symbol_name, }; 289 struct process_symbol_args args = { .name = symbol_name, };
259 290
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0) 291 mmap_name = kern_mmap_name(kerninfo, name_buff);
292 if (is_host_kernel(kerninfo)) {
293 /*
294 * kernel uses PERF_RECORD_MISC_USER for user space maps,
295 * see kernel/perf_event.c __perf_event_mmap
296 */
297 ev.header.misc = PERF_RECORD_MISC_KERNEL;
298 filename = "/proc/kallsyms";
299 } else {
300 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
301 if (is_default_guest(kerninfo))
302 filename = (char *) symbol_conf.default_guest_kallsyms;
303 else {
304 sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
305 filename = path;
306 }
307 }
308
309 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
261 return -ENOENT; 310 return -ENOENT;
262 311
312 map = kerninfo->vmlinux_maps[MAP__FUNCTION];
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 313 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1; 314 "%s%s", mmap_name, symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64)); 315 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); 316 ev.mmap.header.size = (sizeof(ev.mmap) -
317 (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start; 318 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start; 319 ev.mmap.start = map->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ; 320 ev.mmap.len = map->end - ev.mmap.start;
321 ev.mmap.pid = kerninfo->pid;
270 322
271 return process(&ev, session); 323 return process(&ev, session);
272} 324}
@@ -320,22 +372,50 @@ int event__process_lost(event_t *self, struct perf_session *session)
320 return 0; 372 return 0;
321} 373}
322 374
323int event__process_mmap(event_t *self, struct perf_session *session) 375static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
376{
377 maps[MAP__FUNCTION]->start = self->mmap.start;
378 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
379 /*
380 * Be a bit paranoid here, some perf.data file came with
381 * a zero sized synthesized MMAP event for the kernel.
382 */
383 if (maps[MAP__FUNCTION]->end == 0)
384 maps[MAP__FUNCTION]->end = ~0UL;
385}
386
387static int event__process_kernel_mmap(event_t *self,
388 struct perf_session *session)
324{ 389{
325 struct thread *thread;
326 struct map *map; 390 struct map *map;
391 char kmmap_prefix[PATH_MAX];
392 struct kernel_info *kerninfo;
393 enum dso_kernel_type kernel_type;
394 bool is_kernel_mmap;
395
396 kerninfo = kerninfo__findnew(&session->kerninfo_root, self->mmap.pid);
397 if (!kerninfo) {
398 pr_err("Can't find id %d's kerninfo\n", self->mmap.pid);
399 goto out_problem;
400 }
327 401
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", 402 kern_mmap_name(kerninfo, kmmap_prefix);
329 self->mmap.pid, self->mmap.tid, self->mmap.start, 403 if (is_host_kernel(kerninfo))
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 404 kernel_type = DSO_TYPE_KERNEL;
405 else
406 kernel_type = DSO_TYPE_GUEST_KERNEL;
331 407
332 if (self->mmap.pid == 0) { 408 is_kernel_mmap = memcmp(self->mmap.filename,
333 static const char kmmap_prefix[] = "[kernel.kallsyms."; 409 kmmap_prefix,
410 strlen(kmmap_prefix)) == 0;
411 if (self->mmap.filename[0] == '/' ||
412 (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
334 413
335 if (self->mmap.filename[0] == '/') { 414 char short_module_name[1024];
336 char short_module_name[1024]; 415 char *name, *dot;
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338 416
417 if (self->mmap.filename[0] == '/') {
418 name = strrchr(self->mmap.filename, '/');
339 if (name == NULL) 419 if (name == NULL)
340 goto out_problem; 420 goto out_problem;
341 421
@@ -343,58 +423,86 @@ int event__process_mmap(event_t *self, struct perf_session *session)
343 dot = strrchr(name, '.'); 423 dot = strrchr(name, '.');
344 if (dot == NULL) 424 if (dot == NULL)
345 goto out_problem; 425 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name), 426 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name); 427 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_'); 428 strxfrchar(short_module_name, '-', '_');
350 429 } else
351 map = perf_session__new_module_map(session, 430 strcpy(short_module_name, self->mmap.filename);
352 self->mmap.start, 431
353 self->mmap.filename); 432 map = map_groups__new_module(&kerninfo->kmaps,
354 if (map == NULL) 433 self->mmap.start,
355 goto out_problem; 434 self->mmap.filename,
356 435 kerninfo);
357 name = strdup(short_module_name); 436 if (map == NULL)
358 if (name == NULL) 437 goto out_problem;
359 goto out_problem; 438
360 439 name = strdup(short_module_name);
361 map->dso->short_name = name; 440 if (name == NULL)
362 map->end = map->start + self->mmap.len; 441 goto out_problem;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix, 442
364 sizeof(kmmap_prefix) - 1) == 0) { 443 map->dso->short_name = name;
365 const char *symbol_name = (self->mmap.filename + 444 map->end = map->start + self->mmap.len;
366 sizeof(kmmap_prefix) - 1); 445 } else if (is_kernel_mmap) {
446 const char *symbol_name = (self->mmap.filename +
447 strlen(kmmap_prefix));
448 /*
449 * Should be there already, from the build-id table in
450 * the header.
451 */
452 struct dso *kernel = __dsos__findnew(&kerninfo->dsos__kernel,
453 kmmap_prefix);
454 if (kernel == NULL)
455 goto out_problem;
456
457 kernel->kernel = kernel_type;
458 if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
459 kerninfo->vmlinux_maps, kernel) < 0)
460 goto out_problem;
461
462 event_set_kernel_mmap_len(kerninfo->vmlinux_maps, self);
463 perf_session__set_kallsyms_ref_reloc_sym(kerninfo->vmlinux_maps,
464 symbol_name,
465 self->mmap.pgoff);
466 if (is_default_guest(kerninfo)) {
367 /* 467 /*
368 * Should be there already, from the build-id table in 468 * preload dso of guest kernel and modules
369 * the header.
370 */ 469 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel, 470 dso__load(kernel,
372 "[kernel.kallsyms]"); 471 kerninfo->vmlinux_maps[MAP__FUNCTION],
373 if (kernel == NULL) 472 NULL);
374 goto out_problem; 473 }
375 474 }
376 kernel->kernel = 1; 475 return 0;
377 if (__perf_session__create_kernel_maps(session, kernel) < 0) 476out_problem:
378 goto out_problem; 477 return -1;
478}
379 479
380 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; 480int event__process_mmap(event_t *self, struct perf_session *session)
381 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 481{
382 /* 482 struct kernel_info *kerninfo;
383 * Be a bit paranoid here, some perf.data file came with 483 struct thread *thread;
384 * a zero sized synthesized MMAP event for the kernel. 484 struct map *map;
385 */ 485 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
386 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0) 486 int ret = 0;
387 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
388 487
389 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, 488 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
390 self->mmap.pgoff); 489 self->mmap.pid, self->mmap.tid, self->mmap.start,
391 } 490 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
491
492 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
493 cpumode == PERF_RECORD_MISC_KERNEL) {
494 ret = event__process_kernel_mmap(self, session);
495 if (ret < 0)
496 goto out_problem;
392 return 0; 497 return 0;
393 } 498 }
394 499
395 thread = perf_session__findnew(session, self->mmap.pid); 500 thread = perf_session__findnew(session, self->mmap.pid);
396 map = map__new(&self->mmap, MAP__FUNCTION, 501 kerninfo = kerninfo__findhost(&session->kerninfo_root);
397 session->cwd, session->cwdlen); 502 map = map__new(&kerninfo->dsos__user, self->mmap.start,
503 self->mmap.len, self->mmap.pgoff,
504 self->mmap.pid, self->mmap.filename,
505 MAP__FUNCTION, session->cwd, session->cwdlen);
398 506
399 if (thread == NULL || map == NULL) 507 if (thread == NULL || map == NULL)
400 goto out_problem; 508 goto out_problem;
@@ -434,22 +542,52 @@ int event__process_task(event_t *self, struct perf_session *session)
434 542
435void thread__find_addr_map(struct thread *self, 543void thread__find_addr_map(struct thread *self,
436 struct perf_session *session, u8 cpumode, 544 struct perf_session *session, u8 cpumode,
437 enum map_type type, u64 addr, 545 enum map_type type, pid_t pid, u64 addr,
438 struct addr_location *al) 546 struct addr_location *al)
439{ 547{
440 struct map_groups *mg = &self->mg; 548 struct map_groups *mg = &self->mg;
549 struct kernel_info *kerninfo = NULL;
441 550
442 al->thread = self; 551 al->thread = self;
443 al->addr = addr; 552 al->addr = addr;
553 al->cpumode = cpumode;
554 al->filtered = false;
444 555
445 if (cpumode == PERF_RECORD_MISC_KERNEL) { 556 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
446 al->level = 'k'; 557 al->level = 'k';
447 mg = &session->kmaps; 558 kerninfo = kerninfo__findhost(&session->kerninfo_root);
448 } else if (cpumode == PERF_RECORD_MISC_USER) 559 mg = &kerninfo->kmaps;
560 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
449 al->level = '.'; 561 al->level = '.';
450 else { 562 kerninfo = kerninfo__findhost(&session->kerninfo_root);
451 al->level = 'H'; 563 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
564 al->level = 'g';
565 kerninfo = kerninfo__find(&session->kerninfo_root, pid);
566 if (!kerninfo) {
567 al->map = NULL;
568 return;
569 }
570 mg = &kerninfo->kmaps;
571 } else {
572 /*
573 * 'u' means guest os user space.
574 * TODO: We don't support guest user space. Might support late.
575 */
576 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
577 al->level = 'u';
578 else
579 al->level = 'H';
452 al->map = NULL; 580 al->map = NULL;
581
582 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
583 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
584 !perf_guest)
585 al->filtered = true;
586 if ((cpumode == PERF_RECORD_MISC_USER ||
587 cpumode == PERF_RECORD_MISC_KERNEL) &&
588 !perf_host)
589 al->filtered = true;
590
453 return; 591 return;
454 } 592 }
455try_again: 593try_again:
@@ -464,8 +602,11 @@ try_again:
464 * "[vdso]" dso, but for now lets use the old trick of looking 602 * "[vdso]" dso, but for now lets use the old trick of looking
465 * in the whole kernel symbol list. 603 * in the whole kernel symbol list.
466 */ 604 */
467 if ((long long)al->addr < 0 && mg != &session->kmaps) { 605 if ((long long)al->addr < 0 &&
468 mg = &session->kmaps; 606 cpumode == PERF_RECORD_MISC_KERNEL &&
607 kerninfo &&
608 mg != &kerninfo->kmaps) {
609 mg = &kerninfo->kmaps;
469 goto try_again; 610 goto try_again;
470 } 611 }
471 } else 612 } else
@@ -474,11 +615,11 @@ try_again:
474 615
475void thread__find_addr_location(struct thread *self, 616void thread__find_addr_location(struct thread *self,
476 struct perf_session *session, u8 cpumode, 617 struct perf_session *session, u8 cpumode,
477 enum map_type type, u64 addr, 618 enum map_type type, pid_t pid, u64 addr,
478 struct addr_location *al, 619 struct addr_location *al,
479 symbol_filter_t filter) 620 symbol_filter_t filter)
480{ 621{
481 thread__find_addr_map(self, session, cpumode, type, addr, al); 622 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
482 if (al->map != NULL) 623 if (al->map != NULL)
483 al->sym = map__find_symbol(al->map, al->addr, filter); 624 al->sym = map__find_symbol(al->map, al->addr, filter);
484 else 625 else
@@ -513,30 +654,37 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
513 654
514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 655 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
515 656
516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 657 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
517 self->ip.ip, al, filter); 658 self->ip.pid, self->ip.ip, al);
518 dump_printf(" ...... dso: %s\n", 659 dump_printf(" ...... dso: %s\n",
519 al->map ? al->map->dso->long_name : 660 al->map ? al->map->dso->long_name :
520 al->level == 'H' ? "[hypervisor]" : "<not found>"); 661 al->level == 'H' ? "[hypervisor]" : "<not found>");
521 /* 662 al->sym = NULL;
522 * We have to do this here as we may have a dso with no symbol hit that 663
523 * has a name longer than the ones with symbols sampled. 664 if (al->map) {
524 */ 665 if (symbol_conf.dso_list &&
525 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 666 (!al->map || !al->map->dso ||
526 dso__calc_col_width(al->map->dso); 667 !(strlist__has_entry(symbol_conf.dso_list,
527 668 al->map->dso->short_name) ||
528 if (symbol_conf.dso_list && 669 (al->map->dso->short_name != al->map->dso->long_name &&
529 (!al->map || !al->map->dso || 670 strlist__has_entry(symbol_conf.dso_list,
530 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 671 al->map->dso->long_name)))))
531 (al->map->dso->short_name != al->map->dso->long_name && 672 goto out_filtered;
532 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 673 /*
533 goto out_filtered; 674 * We have to do this here as we may have a dso with no symbol
675 * hit that has a name longer than the ones with symbols
676 * sampled.
677 */
678 if (!sort_dso.elide && !al->map->dso->slen_calculated)
679 dso__calc_col_width(al->map->dso);
680
681 al->sym = map__find_symbol(al->map, al->addr, filter);
682 }
534 683
535 if (symbol_conf.sym_list && al->sym && 684 if (symbol_conf.sym_list && al->sym &&
536 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 685 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
537 goto out_filtered; 686 goto out_filtered;
538 687
539 al->filtered = false;
540 return 0; 688 return 0;
541 689
542out_filtered: 690out_filtered: