1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * build-id.c 4 * 5 * build-id support 6 * 7 * Copyright (C) 2009, 2010 Red Hat Inc. 8 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com> 9 */ 10 #include "util.h" 11 #include <dirent.h> 12 #include <errno.h> 13 #include <stdio.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include "build-id.h" 17 #include "event.h" 18 #include "namespaces.h" 19 #include "map.h" 20 #include "symbol.h" 21 #include "thread.h" 22 #include <linux/kernel.h> 23 #include "debug.h" 24 #include "session.h" 25 #include "tool.h" 26 #include "header.h" 27 #include "vdso.h" 28 #include "path.h" 29 #include "probe-file.h" 30 #include "strlist.h" 31 32 #include <linux/ctype.h> 33 #include <linux/zalloc.h> 34 35 static bool no_buildid_cache; 36 37 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 38 union perf_event *event, 39 struct perf_sample *sample, 40 struct perf_evsel *evsel __maybe_unused, 41 struct machine *machine) 42 { 43 struct addr_location al; 44 struct thread *thread = machine__findnew_thread(machine, sample->pid, 45 sample->tid); 46 47 if (thread == NULL) { 48 pr_err("problem processing %d event, skipping it.\n", 49 event->header.type); 50 return -1; 51 } 52 53 if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) 54 al.map->dso->hit = 1; 55 56 thread__put(thread); 57 return 0; 58 } 59 60 static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, 61 union perf_event *event, 62 struct perf_sample *sample 63 __maybe_unused, 64 struct machine *machine) 65 { 66 struct thread *thread = machine__findnew_thread(machine, 67 event->fork.pid, 68 event->fork.tid); 69 70 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 71 event->fork.ppid, event->fork.ptid); 72 73 if (thread) { 74 machine__remove_thread(machine, thread); 75 thread__put(thread); 76 } 77 78 return 0; 79 } 80 81 struct perf_tool build_id__mark_dso_hit_ops = { 82 .sample = build_id__mark_dso_hit, 83 .mmap = perf_event__process_mmap, 84 .mmap2 = perf_event__process_mmap2, 85 .fork = perf_event__process_fork, 86 .exit = perf_event__exit_del_thread, 87 .attr = perf_event__process_attr, 88 .build_id = perf_event__process_build_id, 89 .ordered_events = true, 90 }; 91 92 int build_id__sprintf(const u8 *build_id, int len, char *bf) 93 { 94 char *bid = bf; 95 const u8 *raw = build_id; 96 int i; 97 98 for (i = 0; i < len; ++i) { 99 sprintf(bid, "%02x", *raw); 100 ++raw; 101 bid += 2; 102 } 103 104 return (bid - bf) + 1; 105 } 106 107 int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) 108 { 109 char notes[PATH_MAX]; 110 u8 build_id[BUILD_ID_SIZE]; 111 int ret; 112 113 if (!root_dir) 114 root_dir = ""; 115 116 scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir); 117 118 ret = sysfs__read_build_id(notes, build_id, sizeof(build_id)); 119 if (ret < 0) 120 return ret; 121 122 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 123 } 124 125 int filename__sprintf_build_id(const char *pathname, char *sbuild_id) 126 { 127 u8 build_id[BUILD_ID_SIZE]; 128 int ret; 129 130 ret = filename__read_build_id(pathname, build_id, sizeof(build_id)); 131 if (ret < 0) 132 return ret; 133 else if (ret != sizeof(build_id)) 134 return -EINVAL; 135 136 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 137 } 138 139 /* asnprintf consolidates asprintf and snprintf */ 140 static int asnprintf(char **strp, size_t size, const char *fmt, ...) 141 { 142 va_list ap; 143 int ret; 144 145 if (!strp) 146 return -EINVAL; 147 148 va_start(ap, fmt); 149 if (*strp) 150 ret = vsnprintf(*strp, size, fmt, ap); 151 else 152 ret = vasprintf(strp, fmt, ap); 153 va_end(ap); 154 155 return ret; 156 } 157 158 char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf, 159 size_t size) 160 { 161 bool retry_old = true; 162 163 snprintf(bf, size, "%s/%s/%s/kallsyms", 164 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); 165 retry: 166 if (!access(bf, F_OK)) 167 return bf; 168 if (retry_old) { 169 /* Try old style kallsyms cache */ 170 snprintf(bf, size, "%s/%s/%s", 171 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id); 172 retry_old = false; 173 goto retry; 174 } 175 176 return NULL; 177 } 178 179 char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) 180 { 181 char *tmp = bf; 182 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 183 sbuild_id, sbuild_id + 2); 184 if (ret < 0 || (tmp && size < (unsigned int)ret)) 185 return NULL; 186 return bf; 187 } 188 189 /* The caller is responsible to free the returned buffer. */ 190 char *build_id_cache__origname(const char *sbuild_id) 191 { 192 char *linkname; 193 char buf[PATH_MAX]; 194 char *ret = NULL, *p; 195 size_t offs = 5; /* == strlen("../..") */ 196 ssize_t len; 197 198 linkname = build_id_cache__linkname(sbuild_id, NULL, 0); 199 if (!linkname) 200 return NULL; 201 202 len = readlink(linkname, buf, sizeof(buf) - 1); 203 if (len <= 0) 204 goto out; 205 buf[len] = '\0'; 206 207 /* The link should be "../..<origpath>/<sbuild_id>" */ 208 p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */ 209 if (p && (p > buf + offs)) { 210 *p = '\0'; 211 if (buf[offs + 1] == '[') 212 offs++; /* 213 * This is a DSO name, like [kernel.kallsyms]. 214 * Skip the first '/', since this is not the 215 * cache of a regular file. 216 */ 217 ret = strdup(buf + offs); /* Skip "../..[/]" */ 218 } 219 out: 220 free(linkname); 221 return ret; 222 } 223 224 /* Check if the given build_id cache is valid on current running system */ 225 static bool build_id_cache__valid_id(char *sbuild_id) 226 { 227 char real_sbuild_id[SBUILD_ID_SIZE] = ""; 228 char *pathname; 229 int ret = 0; 230 bool result = false; 231 232 pathname = build_id_cache__origname(sbuild_id); 233 if (!pathname) 234 return false; 235 236 if (!strcmp(pathname, DSO__NAME_KALLSYMS)) 237 ret = sysfs__sprintf_build_id("/", real_sbuild_id); 238 else if (pathname[0] == '/') 239 ret = filename__sprintf_build_id(pathname, real_sbuild_id); 240 else 241 ret = -EINVAL; /* Should we support other special DSO cache? */ 242 if (ret >= 0) 243 result = (strcmp(sbuild_id, real_sbuild_id) == 0); 244 free(pathname); 245 246 return result; 247 } 248 249 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso, 250 bool is_debug) 251 { 252 return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : (is_debug ? 253 "debug" : "elf")); 254 } 255 256 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size, 257 bool is_debug) 258 { 259 bool is_kallsyms = dso__is_kallsyms((struct dso *)dso); 260 bool is_vdso = dso__is_vdso((struct dso *)dso); 261 char sbuild_id[SBUILD_ID_SIZE]; 262 char *linkname; 263 bool alloc = (bf == NULL); 264 int ret; 265 266 if (!dso->has_build_id) 267 return NULL; 268 269 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 270 linkname = build_id_cache__linkname(sbuild_id, NULL, 0); 271 if (!linkname) 272 return NULL; 273 274 /* Check if old style build_id cache */ 275 if (is_regular_file(linkname)) 276 ret = asnprintf(&bf, size, "%s", linkname); 277 else 278 ret = asnprintf(&bf, size, "%s/%s", linkname, 279 build_id_cache__basename(is_kallsyms, is_vdso, 280 is_debug)); 281 if (ret < 0 || (!alloc && size < (unsigned int)ret)) 282 bf = NULL; 283 free(linkname); 284 285 return bf; 286 } 287 288 #define dsos__for_each_with_build_id(pos, head) \ 289 list_for_each_entry(pos, head, node) \ 290 if (!pos->has_build_id) \ 291 continue; \ 292 else 293 294 static int write_buildid(const char *name, size_t name_len, u8 *build_id, 295 pid_t pid, u16 misc, struct feat_fd *fd) 296 { 297 int err; 298 struct build_id_event b; 299 size_t len; 300 301 len = name_len + 1; 302 len = PERF_ALIGN(len, NAME_ALIGN); 303 304 memset(&b, 0, sizeof(b)); 305 memcpy(&b.build_id, build_id, BUILD_ID_SIZE); 306 b.pid = pid; 307 b.header.misc = misc; 308 b.header.size = sizeof(b) + len; 309 310 err = do_write(fd, &b, sizeof(b)); 311 if (err < 0) 312 return err; 313 314 return write_padded(fd, name, name_len + 1, len); 315 } 316 317 static int machine__write_buildid_table(struct machine *machine, 318 struct feat_fd *fd) 319 { 320 int err = 0; 321 struct dso *pos; 322 u16 kmisc = PERF_RECORD_MISC_KERNEL, 323 umisc = PERF_RECORD_MISC_USER; 324 325 if (!machine__is_host(machine)) { 326 kmisc = PERF_RECORD_MISC_GUEST_KERNEL; 327 umisc = PERF_RECORD_MISC_GUEST_USER; 328 } 329 330 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 331 const char *name; 332 size_t name_len; 333 bool in_kernel = false; 334 335 if (!pos->hit && !dso__is_vdso(pos)) 336 continue; 337 338 if (dso__is_vdso(pos)) { 339 name = pos->short_name; 340 name_len = pos->short_name_len; 341 } else if (dso__is_kcore(pos)) { 342 name = machine->mmap_name; 343 name_len = strlen(name); 344 } else { 345 name = pos->long_name; 346 name_len = pos->long_name_len; 347 } 348 349 in_kernel = pos->kernel || 350 is_kernel_module(name, 351 PERF_RECORD_MISC_CPUMODE_UNKNOWN); 352 err = write_buildid(name, name_len, pos->build_id, machine->pid, 353 in_kernel ? kmisc : umisc, fd); 354 if (err) 355 break; 356 } 357 358 return err; 359 } 360 361 int perf_session__write_buildid_table(struct perf_session *session, 362 struct feat_fd *fd) 363 { 364 struct rb_node *nd; 365 int err = machine__write_buildid_table(&session->machines.host, fd); 366 367 if (err) 368 return err; 369 370 for (nd = rb_first_cached(&session->machines.guests); nd; 371 nd = rb_next(nd)) { 372 struct machine *pos = rb_entry(nd, struct machine, rb_node); 373 err = machine__write_buildid_table(pos, fd); 374 if (err) 375 break; 376 } 377 return err; 378 } 379 380 static int __dsos__hit_all(struct list_head *head) 381 { 382 struct dso *pos; 383 384 list_for_each_entry(pos, head, node) 385 pos->hit = true; 386 387 return 0; 388 } 389 390 static int machine__hit_all_dsos(struct machine *machine) 391 { 392 return __dsos__hit_all(&machine->dsos.head); 393 } 394 395 int dsos__hit_all(struct perf_session *session) 396 { 397 struct rb_node *nd; 398 int err; 399 400 err = machine__hit_all_dsos(&session->machines.host); 401 if (err) 402 return err; 403 404 for (nd = rb_first_cached(&session->machines.guests); nd; 405 nd = rb_next(nd)) { 406 struct machine *pos = rb_entry(nd, struct machine, rb_node); 407 408 err = machine__hit_all_dsos(pos); 409 if (err) 410 return err; 411 } 412 413 return 0; 414 } 415 416 void disable_buildid_cache(void) 417 { 418 no_buildid_cache = true; 419 } 420 421 static bool lsdir_bid_head_filter(const char *name __maybe_unused, 422 struct dirent *d) 423 { 424 return (strlen(d->d_name) == 2) && 425 isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]); 426 } 427 428 static bool lsdir_bid_tail_filter(const char *name __maybe_unused, 429 struct dirent *d) 430 { 431 int i = 0; 432 while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3) 433 i++; 434 return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); 435 } 436 437 struct strlist *build_id_cache__list_all(bool validonly) 438 { 439 struct strlist *toplist, *linklist = NULL, *bidlist; 440 struct str_node *nd, *nd2; 441 char *topdir, *linkdir = NULL; 442 char sbuild_id[SBUILD_ID_SIZE]; 443 444 /* for filename__ functions */ 445 if (validonly) 446 symbol__init(NULL); 447 448 /* Open the top-level directory */ 449 if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) 450 return NULL; 451 452 bidlist = strlist__new(NULL, NULL); 453 if (!bidlist) 454 goto out; 455 456 toplist = lsdir(topdir, lsdir_bid_head_filter); 457 if (!toplist) { 458 pr_debug("Error in lsdir(%s): %d\n", topdir, errno); 459 /* If there is no buildid cache, return an empty list */ 460 if (errno == ENOENT) 461 goto out; 462 goto err_out; 463 } 464 465 strlist__for_each_entry(nd, toplist) { 466 if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) 467 goto err_out; 468 /* Open the lower-level directory */ 469 linklist = lsdir(linkdir, lsdir_bid_tail_filter); 470 if (!linklist) { 471 pr_debug("Error in lsdir(%s): %d\n", linkdir, errno); 472 goto err_out; 473 } 474 strlist__for_each_entry(nd2, linklist) { 475 if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", 476 nd->s, nd2->s) != SBUILD_ID_SIZE - 1) 477 goto err_out; 478 if (validonly && !build_id_cache__valid_id(sbuild_id)) 479 continue; 480 if (strlist__add(bidlist, sbuild_id) < 0) 481 goto err_out; 482 } 483 strlist__delete(linklist); 484 zfree(&linkdir); 485 } 486 487 out_free: 488 strlist__delete(toplist); 489 out: 490 free(topdir); 491 492 return bidlist; 493 494 err_out: 495 strlist__delete(linklist); 496 zfree(&linkdir); 497 strlist__delete(bidlist); 498 bidlist = NULL; 499 goto out_free; 500 } 501 502 static bool str_is_build_id(const char *maybe_sbuild_id, size_t len) 503 { 504 size_t i; 505 506 for (i = 0; i < len; i++) { 507 if (!isxdigit(maybe_sbuild_id[i])) 508 return false; 509 } 510 return true; 511 } 512 513 /* Return the valid complete build-id */ 514 char *build_id_cache__complement(const char *incomplete_sbuild_id) 515 { 516 struct strlist *bidlist; 517 struct str_node *nd, *cand = NULL; 518 char *sbuild_id = NULL; 519 size_t len = strlen(incomplete_sbuild_id); 520 521 if (len >= SBUILD_ID_SIZE || 522 !str_is_build_id(incomplete_sbuild_id, len)) 523 return NULL; 524 525 bidlist = build_id_cache__list_all(true); 526 if (!bidlist) 527 return NULL; 528 529 strlist__for_each_entry(nd, bidlist) { 530 if (strncmp(nd->s, incomplete_sbuild_id, len) != 0) 531 continue; 532 if (cand) { /* Error: There are more than 2 candidates. */ 533 cand = NULL; 534 break; 535 } 536 cand = nd; 537 } 538 if (cand) 539 sbuild_id = strdup(cand->s); 540 strlist__delete(bidlist); 541 542 return sbuild_id; 543 } 544 545 char *build_id_cache__cachedir(const char *sbuild_id, const char *name, 546 struct nsinfo *nsi, bool is_kallsyms, 547 bool is_vdso) 548 { 549 char *realname = (char *)name, *filename; 550 bool slash = is_kallsyms || is_vdso; 551 552 if (!slash) { 553 realname = nsinfo__realpath(name, nsi); 554 if (!realname) 555 return NULL; 556 } 557 558 if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "", 559 is_vdso ? DSO__NAME_VDSO : realname, 560 sbuild_id ? "/" : "", sbuild_id ?: "") < 0) 561 filename = NULL; 562 563 if (!slash) 564 free(realname); 565 566 return filename; 567 } 568 569 int build_id_cache__list_build_ids(const char *pathname, struct nsinfo *nsi, 570 struct strlist **result) 571 { 572 char *dir_name; 573 int ret = 0; 574 575 dir_name = build_id_cache__cachedir(NULL, pathname, nsi, false, false); 576 if (!dir_name) 577 return -ENOMEM; 578 579 *result = lsdir(dir_name, lsdir_no_dot_filter); 580 if (!*result) 581 ret = -errno; 582 free(dir_name); 583 584 return ret; 585 } 586 587 #if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT) 588 static int build_id_cache__add_sdt_cache(const char *sbuild_id, 589 const char *realname, 590 struct nsinfo *nsi) 591 { 592 struct probe_cache *cache; 593 int ret; 594 struct nscookie nsc; 595 596 cache = probe_cache__new(sbuild_id, nsi); 597 if (!cache) 598 return -1; 599 600 nsinfo__mountns_enter(nsi, &nsc); 601 ret = probe_cache__scan_sdt(cache, realname); 602 nsinfo__mountns_exit(&nsc); 603 if (ret >= 0) { 604 pr_debug4("Found %d SDTs in %s\n", ret, realname); 605 if (probe_cache__commit(cache) < 0) 606 ret = -1; 607 } 608 probe_cache__delete(cache); 609 return ret; 610 } 611 #else 612 #define build_id_cache__add_sdt_cache(sbuild_id, realname, nsi) (0) 613 #endif 614 615 static char *build_id_cache__find_debug(const char *sbuild_id, 616 struct nsinfo *nsi) 617 { 618 char *realname = NULL; 619 char *debugfile; 620 struct nscookie nsc; 621 size_t len = 0; 622 623 debugfile = calloc(1, PATH_MAX); 624 if (!debugfile) 625 goto out; 626 627 len = __symbol__join_symfs(debugfile, PATH_MAX, 628 "/usr/lib/debug/.build-id/"); 629 snprintf(debugfile + len, PATH_MAX - len, "%.2s/%s.debug", sbuild_id, 630 sbuild_id + 2); 631 632 nsinfo__mountns_enter(nsi, &nsc); 633 realname = realpath(debugfile, NULL); 634 if (realname && access(realname, R_OK)) 635 zfree(&realname); 636 nsinfo__mountns_exit(&nsc); 637 out: 638 free(debugfile); 639 return realname; 640 } 641 642 int build_id_cache__add_s(const char *sbuild_id, const char *name, 643 struct nsinfo *nsi, bool is_kallsyms, bool is_vdso) 644 { 645 const size_t size = PATH_MAX; 646 char *realname = NULL, *filename = NULL, *dir_name = NULL, 647 *linkname = zalloc(size), *tmp; 648 char *debugfile = NULL; 649 int err = -1; 650 651 if (!is_kallsyms) { 652 if (!is_vdso) 653 realname = nsinfo__realpath(name, nsi); 654 else 655 realname = realpath(name, NULL); 656 if (!realname) 657 goto out_free; 658 } 659 660 dir_name = build_id_cache__cachedir(sbuild_id, name, nsi, is_kallsyms, 661 is_vdso); 662 if (!dir_name) 663 goto out_free; 664 665 /* Remove old style build-id cache */ 666 if (is_regular_file(dir_name)) 667 if (unlink(dir_name)) 668 goto out_free; 669 670 if (mkdir_p(dir_name, 0755)) 671 goto out_free; 672 673 /* Save the allocated buildid dirname */ 674 if (asprintf(&filename, "%s/%s", dir_name, 675 build_id_cache__basename(is_kallsyms, is_vdso, 676 false)) < 0) { 677 filename = NULL; 678 goto out_free; 679 } 680 681 if (access(filename, F_OK)) { 682 if (is_kallsyms) { 683 if (copyfile("/proc/kallsyms", filename)) 684 goto out_free; 685 } else if (nsi && nsi->need_setns) { 686 if (copyfile_ns(name, filename, nsi)) 687 goto out_free; 688 } else if (link(realname, filename) && errno != EEXIST && 689 copyfile(name, filename)) 690 goto out_free; 691 } 692 693 /* Some binaries are stripped, but have .debug files with their symbol 694 * table. Check to see if we can locate one of those, since the elf 695 * file itself may not be very useful to users of our tools without a 696 * symtab. 697 */ 698 if (!is_kallsyms && !is_vdso && 699 strncmp(".ko", name + strlen(name) - 3, 3)) { 700 debugfile = build_id_cache__find_debug(sbuild_id, nsi); 701 if (debugfile) { 702 zfree(&filename); 703 if (asprintf(&filename, "%s/%s", dir_name, 704 build_id_cache__basename(false, false, true)) < 0) { 705 filename = NULL; 706 goto out_free; 707 } 708 if (access(filename, F_OK)) { 709 if (nsi && nsi->need_setns) { 710 if (copyfile_ns(debugfile, filename, 711 nsi)) 712 goto out_free; 713 } else if (link(debugfile, filename) && 714 errno != EEXIST && 715 copyfile(debugfile, filename)) 716 goto out_free; 717 } 718 } 719 } 720 721 if (!build_id_cache__linkname(sbuild_id, linkname, size)) 722 goto out_free; 723 tmp = strrchr(linkname, '/'); 724 *tmp = '\0'; 725 726 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 727 goto out_free; 728 729 *tmp = '/'; 730 tmp = dir_name + strlen(buildid_dir) - 5; 731 memcpy(tmp, "../..", 5); 732 733 if (symlink(tmp, linkname) == 0) 734 err = 0; 735 736 /* Update SDT cache : error is just warned */ 737 if (realname && 738 build_id_cache__add_sdt_cache(sbuild_id, realname, nsi) < 0) 739 pr_debug4("Failed to update/scan SDT cache for %s\n", realname); 740 741 out_free: 742 if (!is_kallsyms) 743 free(realname); 744 free(filename); 745 free(debugfile); 746 free(dir_name); 747 free(linkname); 748 return err; 749 } 750 751 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, 752 const char *name, struct nsinfo *nsi, 753 bool is_kallsyms, bool is_vdso) 754 { 755 char sbuild_id[SBUILD_ID_SIZE]; 756 757 build_id__sprintf(build_id, build_id_size, sbuild_id); 758 759 return build_id_cache__add_s(sbuild_id, name, nsi, is_kallsyms, 760 is_vdso); 761 } 762 763 bool build_id_cache__cached(const char *sbuild_id) 764 { 765 bool ret = false; 766 char *filename = build_id_cache__linkname(sbuild_id, NULL, 0); 767 768 if (filename && !access(filename, F_OK)) 769 ret = true; 770 free(filename); 771 772 return ret; 773 } 774 775 int build_id_cache__remove_s(const char *sbuild_id) 776 { 777 const size_t size = PATH_MAX; 778 char *filename = zalloc(size), 779 *linkname = zalloc(size), *tmp; 780 int err = -1; 781 782 if (filename == NULL || linkname == NULL) 783 goto out_free; 784 785 if (!build_id_cache__linkname(sbuild_id, linkname, size)) 786 goto out_free; 787 788 if (access(linkname, F_OK)) 789 goto out_free; 790 791 if (readlink(linkname, filename, size - 1) < 0) 792 goto out_free; 793 794 if (unlink(linkname)) 795 goto out_free; 796 797 /* 798 * Since the link is relative, we must make it absolute: 799 */ 800 tmp = strrchr(linkname, '/') + 1; 801 snprintf(tmp, size - (tmp - linkname), "%s", filename); 802 803 if (rm_rf(linkname)) 804 goto out_free; 805 806 err = 0; 807 out_free: 808 free(filename); 809 free(linkname); 810 return err; 811 } 812 813 static int dso__cache_build_id(struct dso *dso, struct machine *machine) 814 { 815 bool is_kallsyms = dso__is_kallsyms(dso); 816 bool is_vdso = dso__is_vdso(dso); 817 const char *name = dso->long_name; 818 819 if (dso__is_kcore(dso)) { 820 is_kallsyms = true; 821 name = machine->mmap_name; 822 } 823 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name, 824 dso->nsinfo, is_kallsyms, is_vdso); 825 } 826 827 static int __dsos__cache_build_ids(struct list_head *head, 828 struct machine *machine) 829 { 830 struct dso *pos; 831 int err = 0; 832 833 dsos__for_each_with_build_id(pos, head) 834 if (dso__cache_build_id(pos, machine)) 835 err = -1; 836 837 return err; 838 } 839 840 static int machine__cache_build_ids(struct machine *machine) 841 { 842 return __dsos__cache_build_ids(&machine->dsos.head, machine); 843 } 844 845 int perf_session__cache_build_ids(struct perf_session *session) 846 { 847 struct rb_node *nd; 848 int ret; 849 850 if (no_buildid_cache) 851 return 0; 852 853 if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST) 854 return -1; 855 856 ret = machine__cache_build_ids(&session->machines.host); 857 858 for (nd = rb_first_cached(&session->machines.guests); nd; 859 nd = rb_next(nd)) { 860 struct machine *pos = rb_entry(nd, struct machine, rb_node); 861 ret |= machine__cache_build_ids(pos); 862 } 863 return ret ? -1 : 0; 864 } 865 866 static bool machine__read_build_ids(struct machine *machine, bool with_hits) 867 { 868 return __dsos__read_build_ids(&machine->dsos.head, with_hits); 869 } 870 871 bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 872 { 873 struct rb_node *nd; 874 bool ret = machine__read_build_ids(&session->machines.host, with_hits); 875 876 for (nd = rb_first_cached(&session->machines.guests); nd; 877 nd = rb_next(nd)) { 878 struct machine *pos = rb_entry(nd, struct machine, rb_node); 879 ret |= machine__read_build_ids(pos, with_hits); 880 } 881 882 return ret; 883 } 884