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