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