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