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