1 #include <linux/types.h> 2 #include "event.h" 3 #include "debug.h" 4 #include "session.h" 5 #include "sort.h" 6 #include "string.h" 7 #include "strlist.h" 8 #include "thread.h" 9 10 static pid_t event__synthesize_comm(pid_t pid, int full, 11 event__handler_t process, 12 struct perf_session *session) 13 { 14 event_t ev; 15 char filename[PATH_MAX]; 16 char bf[BUFSIZ]; 17 FILE *fp; 18 size_t size = 0; 19 DIR *tasks; 20 struct dirent dirent, *next; 21 pid_t tgid = 0; 22 23 snprintf(filename, sizeof(filename), "/proc/%d/status", pid); 24 25 fp = fopen(filename, "r"); 26 if (fp == NULL) { 27 out_race: 28 /* 29 * We raced with a task exiting - just return: 30 */ 31 pr_debug("couldn't open %s\n", filename); 32 return 0; 33 } 34 35 memset(&ev.comm, 0, sizeof(ev.comm)); 36 while (!ev.comm.comm[0] || !ev.comm.pid) { 37 if (fgets(bf, sizeof(bf), fp) == NULL) 38 goto out_failure; 39 40 if (memcmp(bf, "Name:", 5) == 0) { 41 char *name = bf + 5; 42 while (*name && isspace(*name)) 43 ++name; 44 size = strlen(name) - 1; 45 memcpy(ev.comm.comm, name, size++); 46 } else if (memcmp(bf, "Tgid:", 5) == 0) { 47 char *tgids = bf + 5; 48 while (*tgids && isspace(*tgids)) 49 ++tgids; 50 tgid = ev.comm.pid = atoi(tgids); 51 } 52 } 53 54 ev.comm.header.type = PERF_RECORD_COMM; 55 size = ALIGN(size, sizeof(u64)); 56 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); 57 58 if (!full) { 59 ev.comm.tid = pid; 60 61 process(&ev, session); 62 goto out_fclose; 63 } 64 65 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 66 67 tasks = opendir(filename); 68 if (tasks == NULL) 69 goto out_race; 70 71 while (!readdir_r(tasks, &dirent, &next) && next) { 72 char *end; 73 pid = strtol(dirent.d_name, &end, 10); 74 if (*end) 75 continue; 76 77 ev.comm.tid = pid; 78 79 process(&ev, session); 80 } 81 closedir(tasks); 82 83 out_fclose: 84 fclose(fp); 85 return tgid; 86 87 out_failure: 88 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); 89 return -1; 90 } 91 92 static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 93 event__handler_t process, 94 struct perf_session *session) 95 { 96 char filename[PATH_MAX]; 97 FILE *fp; 98 99 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 100 101 fp = fopen(filename, "r"); 102 if (fp == NULL) { 103 /* 104 * We raced with a task exiting - just return: 105 */ 106 pr_debug("couldn't open %s\n", filename); 107 return -1; 108 } 109 110 while (1) { 111 char bf[BUFSIZ], *pbf = bf; 112 event_t ev = { 113 .header = { 114 .type = PERF_RECORD_MMAP, 115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */ 116 }, 117 }; 118 int n; 119 size_t size; 120 if (fgets(bf, sizeof(bf), fp) == NULL) 121 break; 122 123 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 124 n = hex2u64(pbf, &ev.mmap.start); 125 if (n < 0) 126 continue; 127 pbf += n + 1; 128 n = hex2u64(pbf, &ev.mmap.len); 129 if (n < 0) 130 continue; 131 pbf += n + 3; 132 if (*pbf == 'x') { /* vm_exec */ 133 char *execname = strchr(bf, '/'); 134 135 /* Catch VDSO */ 136 if (execname == NULL) 137 execname = strstr(bf, "[vdso]"); 138 139 if (execname == NULL) 140 continue; 141 142 size = strlen(execname); 143 execname[size - 1] = '\0'; /* Remove \n */ 144 memcpy(ev.mmap.filename, execname, size); 145 size = ALIGN(size, sizeof(u64)); 146 ev.mmap.len -= ev.mmap.start; 147 ev.mmap.header.size = (sizeof(ev.mmap) - 148 (sizeof(ev.mmap.filename) - size)); 149 ev.mmap.pid = tgid; 150 ev.mmap.tid = pid; 151 152 process(&ev, session); 153 } 154 } 155 156 fclose(fp); 157 return 0; 158 } 159 160 int event__synthesize_modules(event__handler_t process, 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 191 int event__synthesize_thread(pid_t pid, event__handler_t process, 192 struct perf_session *session) 193 { 194 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 195 if (tgid == -1) 196 return -1; 197 return event__synthesize_mmap_events(pid, tgid, process, session); 198 } 199 200 void event__synthesize_threads(event__handler_t process, 201 struct perf_session *session) 202 { 203 DIR *proc; 204 struct dirent dirent, *next; 205 206 proc = opendir("/proc"); 207 208 while (!readdir_r(proc, &dirent, &next) && next) { 209 char *end; 210 pid_t pid = strtol(dirent.d_name, &end, 10); 211 212 if (*end) /* only interested in proper numerical dirents */ 213 continue; 214 215 event__synthesize_thread(pid, process, session); 216 } 217 218 closedir(proc); 219 } 220 221 struct process_symbol_args { 222 const char *name; 223 u64 start; 224 }; 225 226 static 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 242 int 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 274 static void thread__comm_adjust(struct thread *self) 275 { 276 char *comm = self->comm; 277 278 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 279 (!symbol_conf.comm_list || 280 strlist__has_entry(symbol_conf.comm_list, comm))) { 281 unsigned int slen = strlen(comm); 282 283 if (slen > comms__col_width) { 284 comms__col_width = slen; 285 threads__col_width = slen + 6; 286 } 287 } 288 } 289 290 static int thread__set_comm_adjust(struct thread *self, const char *comm) 291 { 292 int ret = thread__set_comm(self, comm); 293 294 if (ret) 295 return ret; 296 297 thread__comm_adjust(self); 298 299 return 0; 300 } 301 302 int event__process_comm(event_t *self, struct perf_session *session) 303 { 304 struct thread *thread = perf_session__findnew(session, self->comm.pid); 305 306 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 307 308 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 309 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 310 return -1; 311 } 312 313 return 0; 314 } 315 316 int event__process_lost(event_t *self, struct perf_session *session) 317 { 318 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 319 session->events_stats.lost += self->lost.lost; 320 return 0; 321 } 322 323 int event__process_mmap(event_t *self, struct perf_session *session) 324 { 325 struct thread *thread; 326 struct map *map; 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 } 394 395 thread = perf_session__findnew(session, self->mmap.pid); 396 map = map__new(&self->mmap, MAP__FUNCTION, 397 session->cwd, session->cwdlen); 398 399 if (thread == NULL || map == NULL) 400 goto out_problem; 401 402 thread__insert_map(thread, map); 403 return 0; 404 405 out_problem: 406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 407 return 0; 408 } 409 410 int event__process_task(event_t *self, struct perf_session *session) 411 { 412 struct thread *thread = perf_session__findnew(session, self->fork.pid); 413 struct thread *parent = perf_session__findnew(session, self->fork.ppid); 414 415 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 416 self->fork.ppid, self->fork.ptid); 417 /* 418 * A thread clone will have the same PID for both parent and child. 419 */ 420 if (thread == parent) 421 return 0; 422 423 if (self->header.type == PERF_RECORD_EXIT) 424 return 0; 425 426 if (thread == NULL || parent == NULL || 427 thread__fork(thread, parent) < 0) { 428 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 429 return -1; 430 } 431 432 return 0; 433 } 434 435 void thread__find_addr_map(struct thread *self, 436 struct perf_session *session, u8 cpumode, 437 enum map_type type, u64 addr, 438 struct addr_location *al) 439 { 440 struct map_groups *mg = &self->mg; 441 442 al->thread = self; 443 al->addr = addr; 444 445 if (cpumode == PERF_RECORD_MISC_KERNEL) { 446 al->level = 'k'; 447 mg = &session->kmaps; 448 } else if (cpumode == PERF_RECORD_MISC_USER) 449 al->level = '.'; 450 else { 451 al->level = 'H'; 452 al->map = NULL; 453 return; 454 } 455 try_again: 456 al->map = map_groups__find(mg, type, al->addr); 457 if (al->map == NULL) { 458 /* 459 * If this is outside of all known maps, and is a negative 460 * address, try to look it up in the kernel dso, as it might be 461 * a vsyscall or vdso (which executes in user-mode). 462 * 463 * XXX This is nasty, we should have a symbol list in the 464 * "[vdso]" dso, but for now lets use the old trick of looking 465 * in the whole kernel symbol list. 466 */ 467 if ((long long)al->addr < 0 && mg != &session->kmaps) { 468 mg = &session->kmaps; 469 goto try_again; 470 } 471 } else 472 al->addr = al->map->map_ip(al->map, al->addr); 473 } 474 475 void 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; 486 } 487 488 static void dso__calc_col_width(struct dso *self) 489 { 490 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 491 (!symbol_conf.dso_list || 492 strlist__has_entry(symbol_conf.dso_list, self->name))) { 493 unsigned int slen = strlen(self->name); 494 if (slen > dsos__col_width) 495 dsos__col_width = slen; 496 } 497 498 self->slen_calculated = 1; 499 } 500 501 int event__preprocess_sample(const event_t *self, struct perf_session *session, 502 struct addr_location *al, symbol_filter_t filter) 503 { 504 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 505 struct thread *thread = perf_session__findnew(session, self->ip.pid); 506 507 if (thread == NULL) 508 return -1; 509 510 if (symbol_conf.comm_list && 511 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 512 goto out_filtered; 513 514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 515 516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 517 self->ip.ip, al, filter); 518 dump_printf(" ...... dso: %s\n", 519 al->map ? al->map->dso->long_name : 520 al->level == 'H' ? "[hypervisor]" : "<not found>"); 521 /* 522 * We have to do this here as we may have a dso with no symbol hit that 523 * has a name longer than the ones with symbols sampled. 524 */ 525 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 526 dso__calc_col_width(al->map->dso); 527 528 if (symbol_conf.dso_list && 529 (!al->map || !al->map->dso || 530 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 531 (al->map->dso->short_name != al->map->dso->long_name && 532 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 533 goto out_filtered; 534 535 if (symbol_conf.sym_list && al->sym && 536 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 537 goto out_filtered; 538 539 al->filtered = false; 540 return 0; 541 542 out_filtered: 543 al->filtered = true; 544 return 0; 545 } 546 547 int event__parse_sample(event_t *event, u64 type, struct sample_data *data) 548 { 549 u64 *array = event->sample.array; 550 551 if (type & PERF_SAMPLE_IP) { 552 data->ip = event->ip.ip; 553 array++; 554 } 555 556 if (type & PERF_SAMPLE_TID) { 557 u32 *p = (u32 *)array; 558 data->pid = p[0]; 559 data->tid = p[1]; 560 array++; 561 } 562 563 if (type & PERF_SAMPLE_TIME) { 564 data->time = *array; 565 array++; 566 } 567 568 if (type & PERF_SAMPLE_ADDR) { 569 data->addr = *array; 570 array++; 571 } 572 573 if (type & PERF_SAMPLE_ID) { 574 data->id = *array; 575 array++; 576 } 577 578 if (type & PERF_SAMPLE_STREAM_ID) { 579 data->stream_id = *array; 580 array++; 581 } 582 583 if (type & PERF_SAMPLE_CPU) { 584 u32 *p = (u32 *)array; 585 data->cpu = *p; 586 array++; 587 } 588 589 if (type & PERF_SAMPLE_PERIOD) { 590 data->period = *array; 591 array++; 592 } 593 594 if (type & PERF_SAMPLE_READ) { 595 pr_debug("PERF_SAMPLE_READ is unsuported for now\n"); 596 return -1; 597 } 598 599 if (type & PERF_SAMPLE_CALLCHAIN) { 600 data->callchain = (struct ip_callchain *)array; 601 array += 1 + data->callchain->nr; 602 } 603 604 if (type & PERF_SAMPLE_RAW) { 605 u32 *p = (u32 *)array; 606 data->raw_size = *p; 607 p++; 608 data->raw_data = p; 609 } 610 611 return 0; 612 } 613