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 "util.h" 10 #include <stdio.h> 11 #include "build-id.h" 12 #include "event.h" 13 #include "symbol.h" 14 #include <linux/kernel.h> 15 #include "debug.h" 16 #include "session.h" 17 #include "tool.h" 18 #include "header.h" 19 #include "vdso.h" 20 21 22 static bool no_buildid_cache; 23 24 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 25 union perf_event *event, 26 struct perf_sample *sample, 27 struct perf_evsel *evsel __maybe_unused, 28 struct machine *machine) 29 { 30 struct addr_location al; 31 struct thread *thread = machine__findnew_thread(machine, sample->pid, 32 sample->tid); 33 34 if (thread == NULL) { 35 pr_err("problem processing %d event, skipping it.\n", 36 event->header.type); 37 return -1; 38 } 39 40 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al); 41 42 if (al.map != NULL) 43 al.map->dso->hit = 1; 44 45 thread__put(thread); 46 return 0; 47 } 48 49 static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, 50 union perf_event *event, 51 struct perf_sample *sample 52 __maybe_unused, 53 struct machine *machine) 54 { 55 struct thread *thread = machine__findnew_thread(machine, 56 event->fork.pid, 57 event->fork.tid); 58 59 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 60 event->fork.ppid, event->fork.ptid); 61 62 if (thread) { 63 machine__remove_thread(machine, thread); 64 thread__put(thread); 65 } 66 67 return 0; 68 } 69 70 struct perf_tool build_id__mark_dso_hit_ops = { 71 .sample = build_id__mark_dso_hit, 72 .mmap = perf_event__process_mmap, 73 .mmap2 = perf_event__process_mmap2, 74 .fork = perf_event__process_fork, 75 .exit = perf_event__exit_del_thread, 76 .attr = perf_event__process_attr, 77 .build_id = perf_event__process_build_id, 78 .ordered_events = true, 79 }; 80 81 int build_id__sprintf(const u8 *build_id, int len, char *bf) 82 { 83 char *bid = bf; 84 const u8 *raw = build_id; 85 int i; 86 87 for (i = 0; i < len; ++i) { 88 sprintf(bid, "%02x", *raw); 89 ++raw; 90 bid += 2; 91 } 92 93 return (bid - bf) + 1; 94 } 95 96 int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) 97 { 98 char notes[PATH_MAX]; 99 u8 build_id[BUILD_ID_SIZE]; 100 int ret; 101 102 if (!root_dir) 103 root_dir = ""; 104 105 scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir); 106 107 ret = sysfs__read_build_id(notes, build_id, sizeof(build_id)); 108 if (ret < 0) 109 return ret; 110 111 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 112 } 113 114 int filename__sprintf_build_id(const char *pathname, char *sbuild_id) 115 { 116 u8 build_id[BUILD_ID_SIZE]; 117 int ret; 118 119 ret = filename__read_build_id(pathname, build_id, sizeof(build_id)); 120 if (ret < 0) 121 return ret; 122 else if (ret != sizeof(build_id)) 123 return -EINVAL; 124 125 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 126 } 127 128 /* asnprintf consolidates asprintf and snprintf */ 129 static int asnprintf(char **strp, size_t size, const char *fmt, ...) 130 { 131 va_list ap; 132 int ret; 133 134 if (!strp) 135 return -EINVAL; 136 137 va_start(ap, fmt); 138 if (*strp) 139 ret = vsnprintf(*strp, size, fmt, ap); 140 else 141 ret = vasprintf(strp, fmt, ap); 142 va_end(ap); 143 144 return ret; 145 } 146 147 char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, 148 size_t size) 149 { 150 bool retry_old = true; 151 152 snprintf(bf, size, "%s/%s/%s/kallsyms", 153 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); 154 retry: 155 if (!access(bf, F_OK)) 156 return bf; 157 if (retry_old) { 158 /* Try old style kallsyms cache */ 159 snprintf(bf, size, "%s/%s/%s", 160 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); 161 retry_old = false; 162 goto retry; 163 } 164 165 return NULL; 166 } 167 168 static char *build_id_cache__linkname(const char *sbuild_id, char *bf, 169 size_t size) 170 { 171 char *tmp = bf; 172 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 173 sbuild_id, sbuild_id + 2); 174 if (ret < 0 || (tmp && size < (unsigned int)ret)) 175 return NULL; 176 return bf; 177 } 178 179 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) 180 { 181 return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); 182 } 183 184 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) 185 { 186 bool is_kallsyms = dso__is_kallsyms((struct dso *)dso); 187 bool is_vdso = dso__is_vdso((struct dso *)dso); 188 char sbuild_id[SBUILD_ID_SIZE]; 189 char *linkname; 190 bool alloc = (bf == NULL); 191 int ret; 192 193 if (!dso->has_build_id) 194 return NULL; 195 196 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 197 linkname = build_id_cache__linkname(sbuild_id, NULL, 0); 198 if (!linkname) 199 return NULL; 200 201 /* Check if old style build_id cache */ 202 if (is_regular_file(linkname)) 203 ret = asnprintf(&bf, size, "%s", linkname); 204 else 205 ret = asnprintf(&bf, size, "%s/%s", linkname, 206 build_id_cache__basename(is_kallsyms, is_vdso)); 207 if (ret < 0 || (!alloc && size < (unsigned int)ret)) 208 bf = NULL; 209 free(linkname); 210 211 return bf; 212 } 213 214 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size) 215 { 216 char *id_name = NULL, *ch; 217 struct stat sb; 218 char sbuild_id[SBUILD_ID_SIZE]; 219 220 if (!dso->has_build_id) 221 goto err; 222 223 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 224 id_name = build_id_cache__linkname(sbuild_id, NULL, 0); 225 if (!id_name) 226 goto err; 227 if (access(id_name, F_OK)) 228 goto err; 229 if (lstat(id_name, &sb) == -1) 230 goto err; 231 if ((size_t)sb.st_size > size - 1) 232 goto err; 233 if (readlink(id_name, bf, size - 1) < 0) 234 goto err; 235 236 bf[sb.st_size] = '\0'; 237 238 /* 239 * link should be: 240 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92 241 */ 242 ch = strrchr(bf, '/'); 243 if (!ch) 244 goto err; 245 if (ch - 3 < bf) 246 goto err; 247 248 free(id_name); 249 return strncmp(".ko", ch - 3, 3) == 0; 250 err: 251 pr_err("Invalid build id: %s\n", id_name ? : 252 dso->long_name ? : 253 dso->short_name ? : 254 "[unknown]"); 255 free(id_name); 256 return false; 257 } 258 259 #define dsos__for_each_with_build_id(pos, head) \ 260 list_for_each_entry(pos, head, node) \ 261 if (!pos->has_build_id) \ 262 continue; \ 263 else 264 265 static int write_buildid(const char *name, size_t name_len, u8 *build_id, 266 pid_t pid, u16 misc, int fd) 267 { 268 int err; 269 struct build_id_event b; 270 size_t len; 271 272 len = name_len + 1; 273 len = PERF_ALIGN(len, NAME_ALIGN); 274 275 memset(&b, 0, sizeof(b)); 276 memcpy(&b.build_id, build_id, BUILD_ID_SIZE); 277 b.pid = pid; 278 b.header.misc = misc; 279 b.header.size = sizeof(b) + len; 280 281 err = writen(fd, &b, sizeof(b)); 282 if (err < 0) 283 return err; 284 285 return write_padded(fd, name, name_len + 1, len); 286 } 287 288 static int machine__write_buildid_table(struct machine *machine, int fd) 289 { 290 int err = 0; 291 char nm[PATH_MAX]; 292 struct dso *pos; 293 u16 kmisc = PERF_RECORD_MISC_KERNEL, 294 umisc = PERF_RECORD_MISC_USER; 295 296 if (!machine__is_host(machine)) { 297 kmisc = PERF_RECORD_MISC_GUEST_KERNEL; 298 umisc = PERF_RECORD_MISC_GUEST_USER; 299 } 300 301 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 302 const char *name; 303 size_t name_len; 304 bool in_kernel = false; 305 306 if (!pos->hit && !dso__is_vdso(pos)) 307 continue; 308 309 if (dso__is_vdso(pos)) { 310 name = pos->short_name; 311 name_len = pos->short_name_len; 312 } else if (dso__is_kcore(pos)) { 313 machine__mmap_name(machine, nm, sizeof(nm)); 314 name = nm; 315 name_len = strlen(nm); 316 } else { 317 name = pos->long_name; 318 name_len = pos->long_name_len; 319 } 320 321 in_kernel = pos->kernel || 322 is_kernel_module(name, 323 PERF_RECORD_MISC_CPUMODE_UNKNOWN); 324 err = write_buildid(name, name_len, pos->build_id, machine->pid, 325 in_kernel ? kmisc : umisc, fd); 326 if (err) 327 break; 328 } 329 330 return err; 331 } 332 333 int perf_session__write_buildid_table(struct perf_session *session, int fd) 334 { 335 struct rb_node *nd; 336 int err = machine__write_buildid_table(&session->machines.host, fd); 337 338 if (err) 339 return err; 340 341 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 342 struct machine *pos = rb_entry(nd, struct machine, rb_node); 343 err = machine__write_buildid_table(pos, fd); 344 if (err) 345 break; 346 } 347 return err; 348 } 349 350 static int __dsos__hit_all(struct list_head *head) 351 { 352 struct dso *pos; 353 354 list_for_each_entry(pos, head, node) 355 pos->hit = true; 356 357 return 0; 358 } 359 360 static int machine__hit_all_dsos(struct machine *machine) 361 { 362 return __dsos__hit_all(&machine->dsos.head); 363 } 364 365 int dsos__hit_all(struct perf_session *session) 366 { 367 struct rb_node *nd; 368 int err; 369 370 err = machine__hit_all_dsos(&session->machines.host); 371 if (err) 372 return err; 373 374 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 375 struct machine *pos = rb_entry(nd, struct machine, rb_node); 376 377 err = machine__hit_all_dsos(pos); 378 if (err) 379 return err; 380 } 381 382 return 0; 383 } 384 385 void disable_buildid_cache(void) 386 { 387 no_buildid_cache = true; 388 } 389 390 static char *build_id_cache__dirname_from_path(const char *name, 391 bool is_kallsyms, bool is_vdso, 392 const char *sbuild_id) 393 { 394 char *realname = (char *)name, *filename; 395 bool slash = is_kallsyms || is_vdso; 396 397 if (!slash) { 398 realname = realpath(name, NULL); 399 if (!realname) 400 return NULL; 401 } 402 403 if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "", 404 is_vdso ? DSO__NAME_VDSO : realname, 405 sbuild_id ? "/" : "", sbuild_id ?: "") < 0) 406 filename = NULL; 407 408 if (!slash) 409 free(realname); 410 411 return filename; 412 } 413 414 int build_id_cache__list_build_ids(const char *pathname, 415 struct strlist **result) 416 { 417 char *dir_name; 418 int ret = 0; 419 420 dir_name = build_id_cache__dirname_from_path(pathname, false, false, 421 NULL); 422 if (!dir_name) 423 return -ENOMEM; 424 425 *result = lsdir(dir_name, lsdir_no_dot_filter); 426 if (!*result) 427 ret = -errno; 428 free(dir_name); 429 430 return ret; 431 } 432 433 int build_id_cache__add_s(const char *sbuild_id, const char *name, 434 bool is_kallsyms, bool is_vdso) 435 { 436 const size_t size = PATH_MAX; 437 char *realname = NULL, *filename = NULL, *dir_name = NULL, 438 *linkname = zalloc(size), *tmp; 439 int err = -1; 440 441 if (!is_kallsyms) { 442 realname = realpath(name, NULL); 443 if (!realname) 444 goto out_free; 445 } 446 447 dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, 448 is_vdso, sbuild_id); 449 if (!dir_name) 450 goto out_free; 451 452 /* Remove old style build-id cache */ 453 if (is_regular_file(dir_name)) 454 if (unlink(dir_name)) 455 goto out_free; 456 457 if (mkdir_p(dir_name, 0755)) 458 goto out_free; 459 460 /* Save the allocated buildid dirname */ 461 if (asprintf(&filename, "%s/%s", dir_name, 462 build_id_cache__basename(is_kallsyms, is_vdso)) < 0) { 463 filename = NULL; 464 goto out_free; 465 } 466 467 if (access(filename, F_OK)) { 468 if (is_kallsyms) { 469 if (copyfile("/proc/kallsyms", filename)) 470 goto out_free; 471 } else if (link(realname, filename) && errno != EEXIST && 472 copyfile(name, filename)) 473 goto out_free; 474 } 475 476 if (!build_id_cache__linkname(sbuild_id, linkname, size)) 477 goto out_free; 478 tmp = strrchr(linkname, '/'); 479 *tmp = '\0'; 480 481 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 482 goto out_free; 483 484 *tmp = '/'; 485 tmp = dir_name + strlen(buildid_dir) - 5; 486 memcpy(tmp, "../..", 5); 487 488 if (symlink(tmp, linkname) == 0) 489 err = 0; 490 out_free: 491 if (!is_kallsyms) 492 free(realname); 493 free(filename); 494 free(dir_name); 495 free(linkname); 496 return err; 497 } 498 499 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, 500 const char *name, bool is_kallsyms, 501 bool is_vdso) 502 { 503 char sbuild_id[SBUILD_ID_SIZE]; 504 505 build_id__sprintf(build_id, build_id_size, sbuild_id); 506 507 return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso); 508 } 509 510 bool build_id_cache__cached(const char *sbuild_id) 511 { 512 bool ret = false; 513 char *filename = build_id_cache__linkname(sbuild_id, NULL, 0); 514 515 if (filename && !access(filename, F_OK)) 516 ret = true; 517 free(filename); 518 519 return ret; 520 } 521 522 int build_id_cache__remove_s(const char *sbuild_id) 523 { 524 const size_t size = PATH_MAX; 525 char *filename = zalloc(size), 526 *linkname = zalloc(size), *tmp; 527 int err = -1; 528 529 if (filename == NULL || linkname == NULL) 530 goto out_free; 531 532 if (!build_id_cache__linkname(sbuild_id, linkname, size)) 533 goto out_free; 534 535 if (access(linkname, F_OK)) 536 goto out_free; 537 538 if (readlink(linkname, filename, size - 1) < 0) 539 goto out_free; 540 541 if (unlink(linkname)) 542 goto out_free; 543 544 /* 545 * Since the link is relative, we must make it absolute: 546 */ 547 tmp = strrchr(linkname, '/') + 1; 548 snprintf(tmp, size - (tmp - linkname), "%s", filename); 549 550 if (rm_rf(linkname)) 551 goto out_free; 552 553 err = 0; 554 out_free: 555 free(filename); 556 free(linkname); 557 return err; 558 } 559 560 static int dso__cache_build_id(struct dso *dso, struct machine *machine) 561 { 562 bool is_kallsyms = dso__is_kallsyms(dso); 563 bool is_vdso = dso__is_vdso(dso); 564 const char *name = dso->long_name; 565 char nm[PATH_MAX]; 566 567 if (dso__is_kcore(dso)) { 568 is_kallsyms = true; 569 machine__mmap_name(machine, nm, sizeof(nm)); 570 name = nm; 571 } 572 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, 573 is_kallsyms, is_vdso); 574 } 575 576 static int __dsos__cache_build_ids(struct list_head *head, 577 struct machine *machine) 578 { 579 struct dso *pos; 580 int err = 0; 581 582 dsos__for_each_with_build_id(pos, head) 583 if (dso__cache_build_id(pos, machine)) 584 err = -1; 585 586 return err; 587 } 588 589 static int machine__cache_build_ids(struct machine *machine) 590 { 591 return __dsos__cache_build_ids(&machine->dsos.head, machine); 592 } 593 594 int perf_session__cache_build_ids(struct perf_session *session) 595 { 596 struct rb_node *nd; 597 int ret; 598 599 if (no_buildid_cache) 600 return 0; 601 602 if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST) 603 return -1; 604 605 ret = machine__cache_build_ids(&session->machines.host); 606 607 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 608 struct machine *pos = rb_entry(nd, struct machine, rb_node); 609 ret |= machine__cache_build_ids(pos); 610 } 611 return ret ? -1 : 0; 612 } 613 614 static bool machine__read_build_ids(struct machine *machine, bool with_hits) 615 { 616 return __dsos__read_build_ids(&machine->dsos.head, with_hits); 617 } 618 619 bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 620 { 621 struct rb_node *nd; 622 bool ret = machine__read_build_ids(&session->machines.host, with_hits); 623 624 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { 625 struct machine *pos = rb_entry(nd, struct machine, rb_node); 626 ret |= machine__read_build_ids(pos, with_hits); 627 } 628 629 return ret; 630 } 631