GNU Linux-libre 4.9.309-gnu1
[releases.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 /* The caller is responsible to free the returned buffer. */
180 char *build_id_cache__origname(const char *sbuild_id)
181 {
182         char *linkname;
183         char buf[PATH_MAX];
184         char *ret = NULL, *p;
185         size_t offs = 5;        /* == strlen("../..") */
186         ssize_t len;
187
188         linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
189         if (!linkname)
190                 return NULL;
191
192         len = readlink(linkname, buf, sizeof(buf) - 1);
193         if (len <= 0)
194                 goto out;
195         buf[len] = '\0';
196
197         /* The link should be "../..<origpath>/<sbuild_id>" */
198         p = strrchr(buf, '/');  /* Cut off the "/<sbuild_id>" */
199         if (p && (p > buf + offs)) {
200                 *p = '\0';
201                 if (buf[offs + 1] == '[')
202                         offs++; /*
203                                  * This is a DSO name, like [kernel.kallsyms].
204                                  * Skip the first '/', since this is not the
205                                  * cache of a regular file.
206                                  */
207                 ret = strdup(buf + offs);       /* Skip "../..[/]" */
208         }
209 out:
210         free(linkname);
211         return ret;
212 }
213
214 /* Check if the given build_id cache is valid on current running system */
215 static bool build_id_cache__valid_id(char *sbuild_id)
216 {
217         char real_sbuild_id[SBUILD_ID_SIZE] = "";
218         char *pathname;
219         int ret = 0;
220         bool result = false;
221
222         pathname = build_id_cache__origname(sbuild_id);
223         if (!pathname)
224                 return false;
225
226         if (!strcmp(pathname, DSO__NAME_KALLSYMS))
227                 ret = sysfs__sprintf_build_id("/", real_sbuild_id);
228         else if (pathname[0] == '/')
229                 ret = filename__sprintf_build_id(pathname, real_sbuild_id);
230         else
231                 ret = -EINVAL;  /* Should we support other special DSO cache? */
232         if (ret >= 0)
233                 result = (strcmp(sbuild_id, real_sbuild_id) == 0);
234         free(pathname);
235
236         return result;
237 }
238
239 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
240 {
241         return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
242 }
243
244 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
245 {
246         bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
247         bool is_vdso = dso__is_vdso((struct dso *)dso);
248         char sbuild_id[SBUILD_ID_SIZE];
249         char *linkname;
250         bool alloc = (bf == NULL);
251         int ret;
252
253         if (!dso->has_build_id)
254                 return NULL;
255
256         build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
257         linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
258         if (!linkname)
259                 return NULL;
260
261         /* Check if old style build_id cache */
262         if (is_regular_file(linkname))
263                 ret = asnprintf(&bf, size, "%s", linkname);
264         else
265                 ret = asnprintf(&bf, size, "%s/%s", linkname,
266                          build_id_cache__basename(is_kallsyms, is_vdso));
267         if (ret < 0 || (!alloc && size < (unsigned int)ret))
268                 bf = NULL;
269         free(linkname);
270
271         return bf;
272 }
273
274 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
275 {
276         char *id_name = NULL, *ch;
277         struct stat sb;
278         char sbuild_id[SBUILD_ID_SIZE];
279
280         if (!dso->has_build_id)
281                 goto err;
282
283         build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
284         id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
285         if (!id_name)
286                 goto err;
287         if (access(id_name, F_OK))
288                 goto err;
289         if (lstat(id_name, &sb) == -1)
290                 goto err;
291         if ((size_t)sb.st_size > size - 1)
292                 goto err;
293         if (readlink(id_name, bf, size - 1) < 0)
294                 goto err;
295
296         bf[sb.st_size] = '\0';
297
298         /*
299          * link should be:
300          * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
301          */
302         ch = strrchr(bf, '/');
303         if (!ch)
304                 goto err;
305         if (ch - 3 < bf)
306                 goto err;
307
308         free(id_name);
309         return strncmp(".ko", ch - 3, 3) == 0;
310 err:
311         pr_err("Invalid build id: %s\n", id_name ? :
312                                          dso->long_name ? :
313                                          dso->short_name ? :
314                                          "[unknown]");
315         free(id_name);
316         return false;
317 }
318
319 #define dsos__for_each_with_build_id(pos, head) \
320         list_for_each_entry(pos, head, node)    \
321                 if (!pos->has_build_id)         \
322                         continue;               \
323                 else
324
325 static int write_buildid(const char *name, size_t name_len, u8 *build_id,
326                          pid_t pid, u16 misc, int fd)
327 {
328         int err;
329         struct build_id_event b;
330         size_t len;
331
332         len = name_len + 1;
333         len = PERF_ALIGN(len, NAME_ALIGN);
334
335         memset(&b, 0, sizeof(b));
336         memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
337         b.pid = pid;
338         b.header.misc = misc;
339         b.header.size = sizeof(b) + len;
340
341         err = writen(fd, &b, sizeof(b));
342         if (err < 0)
343                 return err;
344
345         return write_padded(fd, name, name_len + 1, len);
346 }
347
348 static int machine__write_buildid_table(struct machine *machine, int fd)
349 {
350         int err = 0;
351         char nm[PATH_MAX];
352         struct dso *pos;
353         u16 kmisc = PERF_RECORD_MISC_KERNEL,
354             umisc = PERF_RECORD_MISC_USER;
355
356         if (!machine__is_host(machine)) {
357                 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
358                 umisc = PERF_RECORD_MISC_GUEST_USER;
359         }
360
361         dsos__for_each_with_build_id(pos, &machine->dsos.head) {
362                 const char *name;
363                 size_t name_len;
364                 bool in_kernel = false;
365
366                 if (!pos->hit && !dso__is_vdso(pos))
367                         continue;
368
369                 if (dso__is_vdso(pos)) {
370                         name = pos->short_name;
371                         name_len = pos->short_name_len;
372                 } else if (dso__is_kcore(pos)) {
373                         machine__mmap_name(machine, nm, sizeof(nm));
374                         name = nm;
375                         name_len = strlen(nm);
376                 } else {
377                         name = pos->long_name;
378                         name_len = pos->long_name_len;
379                 }
380
381                 in_kernel = pos->kernel ||
382                                 is_kernel_module(name,
383                                         PERF_RECORD_MISC_CPUMODE_UNKNOWN);
384                 err = write_buildid(name, name_len, pos->build_id, machine->pid,
385                                     in_kernel ? kmisc : umisc, fd);
386                 if (err)
387                         break;
388         }
389
390         return err;
391 }
392
393 int perf_session__write_buildid_table(struct perf_session *session, int fd)
394 {
395         struct rb_node *nd;
396         int err = machine__write_buildid_table(&session->machines.host, fd);
397
398         if (err)
399                 return err;
400
401         for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
402                 struct machine *pos = rb_entry(nd, struct machine, rb_node);
403                 err = machine__write_buildid_table(pos, fd);
404                 if (err)
405                         break;
406         }
407         return err;
408 }
409
410 static int __dsos__hit_all(struct list_head *head)
411 {
412         struct dso *pos;
413
414         list_for_each_entry(pos, head, node)
415                 pos->hit = true;
416
417         return 0;
418 }
419
420 static int machine__hit_all_dsos(struct machine *machine)
421 {
422         return __dsos__hit_all(&machine->dsos.head);
423 }
424
425 int dsos__hit_all(struct perf_session *session)
426 {
427         struct rb_node *nd;
428         int err;
429
430         err = machine__hit_all_dsos(&session->machines.host);
431         if (err)
432                 return err;
433
434         for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
435                 struct machine *pos = rb_entry(nd, struct machine, rb_node);
436
437                 err = machine__hit_all_dsos(pos);
438                 if (err)
439                         return err;
440         }
441
442         return 0;
443 }
444
445 void disable_buildid_cache(void)
446 {
447         no_buildid_cache = true;
448 }
449
450 static bool lsdir_bid_head_filter(const char *name __maybe_unused,
451                                   struct dirent *d __maybe_unused)
452 {
453         return (strlen(d->d_name) == 2) &&
454                 isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
455 }
456
457 static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
458                                   struct dirent *d __maybe_unused)
459 {
460         int i = 0;
461         while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
462                 i++;
463         return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
464 }
465
466 struct strlist *build_id_cache__list_all(bool validonly)
467 {
468         struct strlist *toplist, *linklist = NULL, *bidlist;
469         struct str_node *nd, *nd2;
470         char *topdir, *linkdir = NULL;
471         char sbuild_id[SBUILD_ID_SIZE];
472
473         /* for filename__ functions */
474         if (validonly)
475                 symbol__init(NULL);
476
477         /* Open the top-level directory */
478         if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
479                 return NULL;
480
481         bidlist = strlist__new(NULL, NULL);
482         if (!bidlist)
483                 goto out;
484
485         toplist = lsdir(topdir, lsdir_bid_head_filter);
486         if (!toplist) {
487                 pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
488                 /* If there is no buildid cache, return an empty list */
489                 if (errno == ENOENT)
490                         goto out;
491                 goto err_out;
492         }
493
494         strlist__for_each_entry(nd, toplist) {
495                 if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
496                         goto err_out;
497                 /* Open the lower-level directory */
498                 linklist = lsdir(linkdir, lsdir_bid_tail_filter);
499                 if (!linklist) {
500                         pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
501                         goto err_out;
502                 }
503                 strlist__for_each_entry(nd2, linklist) {
504                         if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
505                                      nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
506                                 goto err_out;
507                         if (validonly && !build_id_cache__valid_id(sbuild_id))
508                                 continue;
509                         if (strlist__add(bidlist, sbuild_id) < 0)
510                                 goto err_out;
511                 }
512                 strlist__delete(linklist);
513                 zfree(&linkdir);
514         }
515
516 out_free:
517         strlist__delete(toplist);
518 out:
519         free(topdir);
520
521         return bidlist;
522
523 err_out:
524         strlist__delete(linklist);
525         zfree(&linkdir);
526         strlist__delete(bidlist);
527         bidlist = NULL;
528         goto out_free;
529 }
530
531 static bool str_is_build_id(const char *maybe_sbuild_id, size_t len)
532 {
533         size_t i;
534
535         for (i = 0; i < len; i++) {
536                 if (!isxdigit(maybe_sbuild_id[i]))
537                         return false;
538         }
539         return true;
540 }
541
542 /* Return the valid complete build-id */
543 char *build_id_cache__complement(const char *incomplete_sbuild_id)
544 {
545         struct strlist *bidlist;
546         struct str_node *nd, *cand = NULL;
547         char *sbuild_id = NULL;
548         size_t len = strlen(incomplete_sbuild_id);
549
550         if (len >= SBUILD_ID_SIZE ||
551             !str_is_build_id(incomplete_sbuild_id, len))
552                 return NULL;
553
554         bidlist = build_id_cache__list_all(true);
555         if (!bidlist)
556                 return NULL;
557
558         strlist__for_each_entry(nd, bidlist) {
559                 if (strncmp(nd->s, incomplete_sbuild_id, len) != 0)
560                         continue;
561                 if (cand) {     /* Error: There are more than 2 candidates. */
562                         cand = NULL;
563                         break;
564                 }
565                 cand = nd;
566         }
567         if (cand)
568                 sbuild_id = strdup(cand->s);
569         strlist__delete(bidlist);
570
571         return sbuild_id;
572 }
573
574 char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
575                                bool is_kallsyms, bool is_vdso)
576 {
577         char *realname = (char *)name, *filename;
578         bool slash = is_kallsyms || is_vdso;
579
580         if (!slash) {
581                 realname = realpath(name, NULL);
582                 if (!realname)
583                         return NULL;
584         }
585
586         if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
587                      is_vdso ? DSO__NAME_VDSO : realname,
588                      sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
589                 filename = NULL;
590
591         if (!slash)
592                 free(realname);
593
594         return filename;
595 }
596
597 int build_id_cache__list_build_ids(const char *pathname,
598                                    struct strlist **result)
599 {
600         char *dir_name;
601         int ret = 0;
602
603         dir_name = build_id_cache__cachedir(NULL, pathname, false, false);
604         if (!dir_name)
605                 return -ENOMEM;
606
607         *result = lsdir(dir_name, lsdir_no_dot_filter);
608         if (!*result)
609                 ret = -errno;
610         free(dir_name);
611
612         return ret;
613 }
614
615 #if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT)
616 static int build_id_cache__add_sdt_cache(const char *sbuild_id,
617                                           const char *realname)
618 {
619         struct probe_cache *cache;
620         int ret;
621
622         cache = probe_cache__new(sbuild_id);
623         if (!cache)
624                 return -1;
625
626         ret = probe_cache__scan_sdt(cache, realname);
627         if (ret >= 0) {
628                 pr_debug4("Found %d SDTs in %s\n", ret, realname);
629                 if (probe_cache__commit(cache) < 0)
630                         ret = -1;
631         }
632         probe_cache__delete(cache);
633         return ret;
634 }
635 #else
636 #define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
637 #endif
638
639 int build_id_cache__add_s(const char *sbuild_id, const char *name,
640                           bool is_kallsyms, bool is_vdso)
641 {
642         const size_t size = PATH_MAX;
643         char *realname = NULL, *filename = NULL, *dir_name = NULL,
644              *linkname = zalloc(size), *tmp;
645         int err = -1;
646
647         if (!is_kallsyms) {
648                 realname = realpath(name, NULL);
649                 if (!realname)
650                         goto out_free;
651         }
652
653         dir_name = build_id_cache__cachedir(sbuild_id, name,
654                                             is_kallsyms, is_vdso);
655         if (!dir_name)
656                 goto out_free;
657
658         /* Remove old style build-id cache */
659         if (is_regular_file(dir_name))
660                 if (unlink(dir_name))
661                         goto out_free;
662
663         if (mkdir_p(dir_name, 0755))
664                 goto out_free;
665
666         /* Save the allocated buildid dirname */
667         if (asprintf(&filename, "%s/%s", dir_name,
668                      build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
669                 filename = NULL;
670                 goto out_free;
671         }
672
673         if (access(filename, F_OK)) {
674                 if (is_kallsyms) {
675                          if (copyfile("/proc/kallsyms", filename))
676                                 goto out_free;
677                 } else if (link(realname, filename) && errno != EEXIST &&
678                                 copyfile(name, filename))
679                         goto out_free;
680         }
681
682         if (!build_id_cache__linkname(sbuild_id, linkname, size))
683                 goto out_free;
684         tmp = strrchr(linkname, '/');
685         *tmp = '\0';
686
687         if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
688                 goto out_free;
689
690         *tmp = '/';
691         tmp = dir_name + strlen(buildid_dir) - 5;
692         memcpy(tmp, "../..", 5);
693
694         if (symlink(tmp, linkname) == 0)
695                 err = 0;
696
697         /* Update SDT cache : error is just warned */
698         if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
699                 pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
700
701 out_free:
702         if (!is_kallsyms)
703                 free(realname);
704         free(filename);
705         free(dir_name);
706         free(linkname);
707         return err;
708 }
709
710 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
711                                  const char *name, bool is_kallsyms,
712                                  bool is_vdso)
713 {
714         char sbuild_id[SBUILD_ID_SIZE];
715
716         build_id__sprintf(build_id, build_id_size, sbuild_id);
717
718         return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso);
719 }
720
721 bool build_id_cache__cached(const char *sbuild_id)
722 {
723         bool ret = false;
724         char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
725
726         if (filename && !access(filename, F_OK))
727                 ret = true;
728         free(filename);
729
730         return ret;
731 }
732
733 int build_id_cache__remove_s(const char *sbuild_id)
734 {
735         const size_t size = PATH_MAX;
736         char *filename = zalloc(size),
737              *linkname = zalloc(size), *tmp;
738         int err = -1;
739
740         if (filename == NULL || linkname == NULL)
741                 goto out_free;
742
743         if (!build_id_cache__linkname(sbuild_id, linkname, size))
744                 goto out_free;
745
746         if (access(linkname, F_OK))
747                 goto out_free;
748
749         if (readlink(linkname, filename, size - 1) < 0)
750                 goto out_free;
751
752         if (unlink(linkname))
753                 goto out_free;
754
755         /*
756          * Since the link is relative, we must make it absolute:
757          */
758         tmp = strrchr(linkname, '/') + 1;
759         snprintf(tmp, size - (tmp - linkname), "%s", filename);
760
761         if (rm_rf(linkname))
762                 goto out_free;
763
764         err = 0;
765 out_free:
766         free(filename);
767         free(linkname);
768         return err;
769 }
770
771 static int dso__cache_build_id(struct dso *dso, struct machine *machine)
772 {
773         bool is_kallsyms = dso__is_kallsyms(dso);
774         bool is_vdso = dso__is_vdso(dso);
775         const char *name = dso->long_name;
776         char nm[PATH_MAX];
777
778         if (dso__is_kcore(dso)) {
779                 is_kallsyms = true;
780                 machine__mmap_name(machine, nm, sizeof(nm));
781                 name = nm;
782         }
783         return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
784                                      is_kallsyms, is_vdso);
785 }
786
787 static int __dsos__cache_build_ids(struct list_head *head,
788                                    struct machine *machine)
789 {
790         struct dso *pos;
791         int err = 0;
792
793         dsos__for_each_with_build_id(pos, head)
794                 if (dso__cache_build_id(pos, machine))
795                         err = -1;
796
797         return err;
798 }
799
800 static int machine__cache_build_ids(struct machine *machine)
801 {
802         return __dsos__cache_build_ids(&machine->dsos.head, machine);
803 }
804
805 int perf_session__cache_build_ids(struct perf_session *session)
806 {
807         struct rb_node *nd;
808         int ret;
809
810         if (no_buildid_cache)
811                 return 0;
812
813         if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
814                 return -1;
815
816         ret = machine__cache_build_ids(&session->machines.host);
817
818         for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
819                 struct machine *pos = rb_entry(nd, struct machine, rb_node);
820                 ret |= machine__cache_build_ids(pos);
821         }
822         return ret ? -1 : 0;
823 }
824
825 static bool machine__read_build_ids(struct machine *machine, bool with_hits)
826 {
827         return __dsos__read_build_ids(&machine->dsos.head, with_hits);
828 }
829
830 bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
831 {
832         struct rb_node *nd;
833         bool ret = machine__read_build_ids(&session->machines.host, with_hits);
834
835         for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
836                 struct machine *pos = rb_entry(nd, struct machine, rb_node);
837                 ret |= machine__read_build_ids(pos, with_hits);
838         }
839
840         return ret;
841 }