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