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