linux/tools/perf/util/build-id.c
<<
>>
Prefs
   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
  32static bool no_buildid_cache;
  33
  34int 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
  57static 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
  78struct 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
  89int 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
 104int 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
 122int 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 */
 137static 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
 155char *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);
 162retry:
 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
 176char *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
 186char *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        }
 215out:
 216        free(linkname);
 217        return ret;
 218}
 219
 220/* Check if the given build_id cache is valid on current running system */
 221static 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
 245static 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
 252char *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
 290static 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
 313static 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
 357int 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
 375static 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
 385static int machine__hit_all_dsos(struct machine *machine)
 386{
 387        return __dsos__hit_all(&machine->dsos.head);
 388}
 389
 390int 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
 410void disable_buildid_cache(void)
 411{
 412        no_buildid_cache = true;
 413}
 414
 415static 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
 422static 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
 431struct 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
 481out_free:
 482        strlist__delete(toplist);
 483out:
 484        free(topdir);
 485
 486        return bidlist;
 487
 488err_out:
 489        strlist__delete(linklist);
 490        zfree(&linkdir);
 491        strlist__delete(bidlist);
 492        bidlist = NULL;
 493        goto out_free;
 494}
 495
 496static 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 */
 508char *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
 539char *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
 563int 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)
 582static 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
 609static 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);
 631out:
 632        free(debugfile);
 633        return realname;
 634}
 635
 636int 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
 735out_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
 745static 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
 757bool 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
 769int 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;
 801out_free:
 802        free(filename);
 803        free(linkname);
 804        return err;
 805}
 806
 807static 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
 821static 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
 834static int machine__cache_build_ids(struct machine *machine)
 835{
 836        return __dsos__cache_build_ids(&machine->dsos.head, machine);
 837}
 838
 839int 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
 859static 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
 864bool 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