blob: f9ccd053cdf6fbea2ddc9000a8307a078ad85f8b [file] [log] [blame]
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -02001/*
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 */
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -03009#include "util.h"
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030010#include <errno.h>
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030011#include <stdio.h>
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020012#include "build-id.h"
13#include "event.h"
14#include "symbol.h"
15#include <linux/kernel.h>
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -030016#include "debug.h"
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020017#include "session.h"
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020018#include "tool.h"
Namhyung Kime195fac2014-11-04 10:14:30 +090019#include "header.h"
20#include "vdso.h"
Masami Hiramatsu6430a942016-07-01 17:04:10 +090021#include "probe-file.h"
Arnaldo Carvalho de Melo8ec20b12017-04-18 10:57:25 -030022#include "strlist.h"
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020023
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030024#include "sane_ctype.h"
Namhyung Kim73c5d222014-11-07 22:57:56 +090025
26static bool no_buildid_cache;
27
Andrew Vagin54a3cf52012-08-07 16:56:05 +040028int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
29 union perf_event *event,
Adrian Hunteref893252013-08-27 11:23:06 +030030 struct perf_sample *sample,
Andrew Vagin54a3cf52012-08-07 16:56:05 +040031 struct perf_evsel *evsel __maybe_unused,
32 struct machine *machine)
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020033{
34 struct addr_location al;
Adrian Hunteref893252013-08-27 11:23:06 +030035 struct thread *thread = machine__findnew_thread(machine, sample->pid,
Namhyung Kim13ce34d2014-05-12 09:56:42 +090036 sample->tid);
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020037
38 if (thread == NULL) {
39 pr_err("problem processing %d event, skipping it.\n",
40 event->header.type);
41 return -1;
42 }
43
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -030044 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020045
46 if (al.map != NULL)
47 al.map->dso->hit = 1;
48
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -030049 thread__put(thread);
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020050 return 0;
51}
52
Irina Tirdea1d037ca2012-09-11 01:15:03 +030053static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020054 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030055 struct perf_sample *sample
56 __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020057 struct machine *machine)
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -030058{
Adrian Hunter314add62013-08-27 11:23:03 +030059 struct thread *thread = machine__findnew_thread(machine,
60 event->fork.pid,
61 event->fork.tid);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -030062
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020063 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
64 event->fork.ppid, event->fork.ptid);
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -030065
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -030066 if (thread) {
He Kuang5e78c692015-04-10 17:35:00 +080067 machine__remove_thread(machine, thread);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -030068 thread__put(thread);
69 }
Arnaldo Carvalho de Melo591765f2010-07-30 18:28:42 -030070
71 return 0;
72}
73
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020074struct perf_tool build_id__mark_dso_hit_ops = {
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020075 .sample = build_id__mark_dso_hit,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020076 .mmap = perf_event__process_mmap,
Stephane Eranian5c5e8542013-08-21 12:10:25 +020077 .mmap2 = perf_event__process_mmap2,
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -030078 .fork = perf_event__process_fork,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020079 .exit = perf_event__exit_del_thread,
Stephane Eranian299c3452012-05-15 13:28:15 +020080 .attr = perf_event__process_attr,
81 .build_id = perf_event__process_build_id,
Adrian Hunter1216b652015-11-13 11:48:31 +020082 .ordered_events = true,
Arnaldo Carvalho de Melo7b2567c2010-02-03 16:52:04 -020083};
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030084
Jiri Olsaebb296c2012-10-27 23:18:28 +020085int build_id__sprintf(const u8 *build_id, int len, char *bf)
86{
87 char *bid = bf;
88 const u8 *raw = build_id;
89 int i;
90
91 for (i = 0; i < len; ++i) {
92 sprintf(bid, "%02x", *raw);
93 ++raw;
94 bid += 2;
95 }
96
Michael Petlan7375e152015-11-27 14:48:09 +010097 return (bid - bf) + 1;
Jiri Olsaebb296c2012-10-27 23:18:28 +020098}
99
Masami Hiramatsu0b5a7932015-08-15 20:42:59 +0900100int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
101{
102 char notes[PATH_MAX];
103 u8 build_id[BUILD_ID_SIZE];
104 int ret;
105
106 if (!root_dir)
107 root_dir = "";
108
109 scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
110
111 ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
112 if (ret < 0)
113 return ret;
114
115 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
116}
117
118int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
119{
120 u8 build_id[BUILD_ID_SIZE];
121 int ret;
122
123 ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
124 if (ret < 0)
125 return ret;
126 else if (ret != sizeof(build_id))
127 return -EINVAL;
128
129 return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
130}
131
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900132/* asnprintf consolidates asprintf and snprintf */
133static int asnprintf(char **strp, size_t size, const char *fmt, ...)
134{
135 va_list ap;
136 int ret;
137
138 if (!strp)
139 return -EINVAL;
140
141 va_start(ap, fmt);
142 if (*strp)
143 ret = vsnprintf(*strp, size, fmt, ap);
144 else
145 ret = vasprintf(strp, fmt, ap);
146 va_end(ap);
147
148 return ret;
149}
150
Masami Hiramatsu01412262016-05-29 00:15:37 +0900151char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
152 size_t size)
153{
Masami Hiramatsu01412262016-05-29 00:15:37 +0900154 bool retry_old = true;
155
Wang Nanc58c49a2016-06-07 03:54:38 +0000156 snprintf(bf, size, "%s/%s/%s/kallsyms",
157 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
Masami Hiramatsu01412262016-05-29 00:15:37 +0900158retry:
159 if (!access(bf, F_OK))
160 return bf;
Masami Hiramatsu01412262016-05-29 00:15:37 +0900161 if (retry_old) {
162 /* Try old style kallsyms cache */
Wang Nanc58c49a2016-06-07 03:54:38 +0000163 snprintf(bf, size, "%s/%s/%s",
164 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
Masami Hiramatsu01412262016-05-29 00:15:37 +0900165 retry_old = false;
166 goto retry;
167 }
168
169 return NULL;
170}
171
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900172char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900173{
174 char *tmp = bf;
175 int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
176 sbuild_id, sbuild_id + 2);
177 if (ret < 0 || (tmp && size < (unsigned int)ret))
178 return NULL;
179 return bf;
180}
181
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900182char *build_id_cache__origname(const char *sbuild_id)
183{
184 char *linkname;
185 char buf[PATH_MAX];
186 char *ret = NULL, *p;
187 size_t offs = 5; /* == strlen("../..") */
Tommi Rantala5a234212017-03-22 15:06:20 +0200188 ssize_t len;
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900189
190 linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
191 if (!linkname)
192 return NULL;
193
Tommi Rantala5a234212017-03-22 15:06:20 +0200194 len = readlink(linkname, buf, sizeof(buf) - 1);
195 if (len <= 0)
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900196 goto out;
Tommi Rantala5a234212017-03-22 15:06:20 +0200197 buf[len] = '\0';
198
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900199 /* The link should be "../..<origpath>/<sbuild_id>" */
200 p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */
201 if (p && (p > buf + offs)) {
202 *p = '\0';
203 if (buf[offs + 1] == '[')
204 offs++; /*
205 * This is a DSO name, like [kernel.kallsyms].
206 * Skip the first '/', since this is not the
207 * cache of a regular file.
208 */
209 ret = strdup(buf + offs); /* Skip "../..[/]" */
210 }
211out:
212 free(linkname);
213 return ret;
214}
215
Masami Hiramatsuc3492a32016-07-12 19:04:54 +0900216/* Check if the given build_id cache is valid on current running system */
217static bool build_id_cache__valid_id(char *sbuild_id)
218{
219 char real_sbuild_id[SBUILD_ID_SIZE] = "";
220 char *pathname;
221 int ret = 0;
222 bool result = false;
223
224 pathname = build_id_cache__origname(sbuild_id);
225 if (!pathname)
226 return false;
227
228 if (!strcmp(pathname, DSO__NAME_KALLSYMS))
229 ret = sysfs__sprintf_build_id("/", real_sbuild_id);
230 else if (pathname[0] == '/')
231 ret = filename__sprintf_build_id(pathname, real_sbuild_id);
232 else
233 ret = -EINVAL; /* Should we support other special DSO cache? */
234 if (ret >= 0)
235 result = (strcmp(sbuild_id, real_sbuild_id) == 0);
236 free(pathname);
237
238 return result;
239}
240
Masami Hiramatsu01412262016-05-29 00:15:37 +0900241static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
242{
243 return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
244}
245
Arnaldo Carvalho de Melo33449962013-12-10 15:46:29 -0300246char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -0300247{
Masami Hiramatsu01412262016-05-29 00:15:37 +0900248 bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
249 bool is_vdso = dso__is_vdso((struct dso *)dso);
250 char sbuild_id[SBUILD_ID_SIZE];
251 char *linkname;
252 bool alloc = (bf == NULL);
253 int ret;
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -0300254
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300255 if (!dso->has_build_id)
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -0300256 return NULL;
257
Masami Hiramatsu01412262016-05-29 00:15:37 +0900258 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
259 linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
260 if (!linkname)
261 return NULL;
262
263 /* Check if old style build_id cache */
264 if (is_regular_file(linkname))
265 ret = asnprintf(&bf, size, "%s", linkname);
266 else
267 ret = asnprintf(&bf, size, "%s/%s", linkname,
268 build_id_cache__basename(is_kallsyms, is_vdso));
269 if (ret < 0 || (!alloc && size < (unsigned int)ret))
270 bf = NULL;
271 free(linkname);
272
273 return bf;
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -0300274}
Namhyung Kime195fac2014-11-04 10:14:30 +0900275
Wang Nane7ee4042016-02-05 14:01:27 +0000276bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
277{
Masami Hiramatsu01412262016-05-29 00:15:37 +0900278 char *id_name = NULL, *ch;
Wang Nane7ee4042016-02-05 14:01:27 +0000279 struct stat sb;
Masami Hiramatsu01412262016-05-29 00:15:37 +0900280 char sbuild_id[SBUILD_ID_SIZE];
Wang Nane7ee4042016-02-05 14:01:27 +0000281
Masami Hiramatsu01412262016-05-29 00:15:37 +0900282 if (!dso->has_build_id)
283 goto err;
284
285 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
286 id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
Wang Nane7ee4042016-02-05 14:01:27 +0000287 if (!id_name)
288 goto err;
289 if (access(id_name, F_OK))
290 goto err;
291 if (lstat(id_name, &sb) == -1)
292 goto err;
293 if ((size_t)sb.st_size > size - 1)
294 goto err;
295 if (readlink(id_name, bf, size - 1) < 0)
296 goto err;
297
298 bf[sb.st_size] = '\0';
299
300 /*
301 * link should be:
302 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
303 */
304 ch = strrchr(bf, '/');
305 if (!ch)
306 goto err;
307 if (ch - 3 < bf)
308 goto err;
309
Masami Hiramatsu01412262016-05-29 00:15:37 +0900310 free(id_name);
Wang Nane7ee4042016-02-05 14:01:27 +0000311 return strncmp(".ko", ch - 3, 3) == 0;
312err:
Wang Nane7ee4042016-02-05 14:01:27 +0000313 pr_err("Invalid build id: %s\n", id_name ? :
314 dso->long_name ? :
315 dso->short_name ? :
316 "[unknown]");
Masami Hiramatsu01412262016-05-29 00:15:37 +0900317 free(id_name);
Wang Nane7ee4042016-02-05 14:01:27 +0000318 return false;
319}
320
Namhyung Kime195fac2014-11-04 10:14:30 +0900321#define dsos__for_each_with_build_id(pos, head) \
322 list_for_each_entry(pos, head, node) \
323 if (!pos->has_build_id) \
324 continue; \
325 else
326
327static int write_buildid(const char *name, size_t name_len, u8 *build_id,
328 pid_t pid, u16 misc, int fd)
329{
330 int err;
331 struct build_id_event b;
332 size_t len;
333
334 len = name_len + 1;
335 len = PERF_ALIGN(len, NAME_ALIGN);
336
337 memset(&b, 0, sizeof(b));
338 memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
339 b.pid = pid;
340 b.header.misc = misc;
341 b.header.size = sizeof(b) + len;
342
343 err = writen(fd, &b, sizeof(b));
344 if (err < 0)
345 return err;
346
347 return write_padded(fd, name, name_len + 1, len);
348}
349
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300350static int machine__write_buildid_table(struct machine *machine, int fd)
Namhyung Kime195fac2014-11-04 10:14:30 +0900351{
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300352 int err = 0;
Namhyung Kime195fac2014-11-04 10:14:30 +0900353 char nm[PATH_MAX];
354 struct dso *pos;
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300355 u16 kmisc = PERF_RECORD_MISC_KERNEL,
356 umisc = PERF_RECORD_MISC_USER;
Namhyung Kime195fac2014-11-04 10:14:30 +0900357
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300358 if (!machine__is_host(machine)) {
359 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
360 umisc = PERF_RECORD_MISC_GUEST_USER;
361 }
362
363 dsos__for_each_with_build_id(pos, &machine->dsos.head) {
Namhyung Kime195fac2014-11-04 10:14:30 +0900364 const char *name;
365 size_t name_len;
Wang Nanfd786fa2016-01-29 17:40:51 +0000366 bool in_kernel = false;
Namhyung Kime195fac2014-11-04 10:14:30 +0900367
He Kuang6ae98ba2016-05-12 08:43:11 +0000368 if (!pos->hit && !dso__is_vdso(pos))
Namhyung Kime195fac2014-11-04 10:14:30 +0900369 continue;
370
371 if (dso__is_vdso(pos)) {
372 name = pos->short_name;
Andrey Ryabinin70a2cba2016-04-19 11:17:27 +0300373 name_len = pos->short_name_len;
Namhyung Kime195fac2014-11-04 10:14:30 +0900374 } else if (dso__is_kcore(pos)) {
375 machine__mmap_name(machine, nm, sizeof(nm));
376 name = nm;
Andrey Ryabinin70a2cba2016-04-19 11:17:27 +0300377 name_len = strlen(nm);
Namhyung Kime195fac2014-11-04 10:14:30 +0900378 } else {
379 name = pos->long_name;
Andrey Ryabinin70a2cba2016-04-19 11:17:27 +0300380 name_len = pos->long_name_len;
Namhyung Kime195fac2014-11-04 10:14:30 +0900381 }
382
Wang Nanfd786fa2016-01-29 17:40:51 +0000383 in_kernel = pos->kernel ||
384 is_kernel_module(name,
385 PERF_RECORD_MISC_CPUMODE_UNKNOWN);
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300386 err = write_buildid(name, name_len, pos->build_id, machine->pid,
Wang Nanfd786fa2016-01-29 17:40:51 +0000387 in_kernel ? kmisc : umisc, fd);
Namhyung Kime195fac2014-11-04 10:14:30 +0900388 if (err)
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300389 break;
Namhyung Kime195fac2014-11-04 10:14:30 +0900390 }
391
Namhyung Kime195fac2014-11-04 10:14:30 +0900392 return err;
393}
394
395int perf_session__write_buildid_table(struct perf_session *session, int fd)
396{
397 struct rb_node *nd;
398 int err = machine__write_buildid_table(&session->machines.host, fd);
399
400 if (err)
401 return err;
402
403 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
404 struct machine *pos = rb_entry(nd, struct machine, rb_node);
405 err = machine__write_buildid_table(pos, fd);
406 if (err)
407 break;
408 }
409 return err;
410}
411
412static int __dsos__hit_all(struct list_head *head)
413{
414 struct dso *pos;
415
416 list_for_each_entry(pos, head, node)
417 pos->hit = true;
418
419 return 0;
420}
421
422static int machine__hit_all_dsos(struct machine *machine)
423{
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300424 return __dsos__hit_all(&machine->dsos.head);
Namhyung Kime195fac2014-11-04 10:14:30 +0900425}
426
427int dsos__hit_all(struct perf_session *session)
428{
429 struct rb_node *nd;
430 int err;
431
432 err = machine__hit_all_dsos(&session->machines.host);
433 if (err)
434 return err;
435
436 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
437 struct machine *pos = rb_entry(nd, struct machine, rb_node);
438
439 err = machine__hit_all_dsos(pos);
440 if (err)
441 return err;
442 }
443
444 return 0;
445}
446
Namhyung Kim73c5d222014-11-07 22:57:56 +0900447void disable_buildid_cache(void)
448{
449 no_buildid_cache = true;
450}
451
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900452static bool lsdir_bid_head_filter(const char *name __maybe_unused,
453 struct dirent *d __maybe_unused)
454{
455 return (strlen(d->d_name) == 2) &&
456 isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
457}
458
459static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
460 struct dirent *d __maybe_unused)
461{
462 int i = 0;
463 while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
464 i++;
465 return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
466}
467
Masami Hiramatsuc3492a32016-07-12 19:04:54 +0900468struct strlist *build_id_cache__list_all(bool validonly)
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900469{
470 struct strlist *toplist, *linklist = NULL, *bidlist;
471 struct str_node *nd, *nd2;
472 char *topdir, *linkdir = NULL;
473 char sbuild_id[SBUILD_ID_SIZE];
474
Masami Hiramatsuc3492a32016-07-12 19:04:54 +0900475 /* for filename__ functions */
476 if (validonly)
477 symbol__init(NULL);
478
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900479 /* Open the top-level directory */
480 if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
481 return NULL;
482
483 bidlist = strlist__new(NULL, NULL);
484 if (!bidlist)
485 goto out;
486
487 toplist = lsdir(topdir, lsdir_bid_head_filter);
488 if (!toplist) {
489 pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
490 /* If there is no buildid cache, return an empty list */
491 if (errno == ENOENT)
492 goto out;
493 goto err_out;
494 }
495
496 strlist__for_each_entry(nd, toplist) {
497 if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
498 goto err_out;
499 /* Open the lower-level directory */
500 linklist = lsdir(linkdir, lsdir_bid_tail_filter);
501 if (!linklist) {
502 pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
503 goto err_out;
504 }
505 strlist__for_each_entry(nd2, linklist) {
506 if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
507 nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
508 goto err_out;
Masami Hiramatsuc3492a32016-07-12 19:04:54 +0900509 if (validonly && !build_id_cache__valid_id(sbuild_id))
510 continue;
Masami Hiramatsu1f3736c2016-07-01 17:03:26 +0900511 if (strlist__add(bidlist, sbuild_id) < 0)
512 goto err_out;
513 }
514 strlist__delete(linklist);
515 zfree(&linkdir);
516 }
517
518out_free:
519 strlist__delete(toplist);
520out:
521 free(topdir);
522
523 return bidlist;
524
525err_out:
526 strlist__delete(linklist);
527 zfree(&linkdir);
528 strlist__delete(bidlist);
529 bidlist = NULL;
530 goto out_free;
531}
532
Masami Hiramatsua5981802016-07-12 19:05:37 +0900533static bool str_is_build_id(const char *maybe_sbuild_id, size_t len)
534{
535 size_t i;
536
537 for (i = 0; i < len; i++) {
538 if (!isxdigit(maybe_sbuild_id[i]))
539 return false;
540 }
541 return true;
542}
543
544/* Return the valid complete build-id */
545char *build_id_cache__complement(const char *incomplete_sbuild_id)
546{
547 struct strlist *bidlist;
548 struct str_node *nd, *cand = NULL;
549 char *sbuild_id = NULL;
550 size_t len = strlen(incomplete_sbuild_id);
551
552 if (len >= SBUILD_ID_SIZE ||
553 !str_is_build_id(incomplete_sbuild_id, len))
554 return NULL;
555
556 bidlist = build_id_cache__list_all(true);
557 if (!bidlist)
558 return NULL;
559
560 strlist__for_each_entry(nd, bidlist) {
561 if (strncmp(nd->s, incomplete_sbuild_id, len) != 0)
562 continue;
563 if (cand) { /* Error: There are more than 2 candidates. */
564 cand = NULL;
565 break;
566 }
567 cand = nd;
568 }
569 if (cand)
570 sbuild_id = strdup(cand->s);
571 strlist__delete(bidlist);
572
573 return sbuild_id;
574}
575
Masami Hiramatsu4698b8b2016-06-08 18:29:30 +0900576char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
577 bool is_kallsyms, bool is_vdso)
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900578{
579 char *realname = (char *)name, *filename;
580 bool slash = is_kallsyms || is_vdso;
581
582 if (!slash) {
583 realname = realpath(name, NULL);
584 if (!realname)
585 return NULL;
586 }
587
Masami Hiramatsu01412262016-05-29 00:15:37 +0900588 if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
589 is_vdso ? DSO__NAME_VDSO : realname,
590 sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900591 filename = NULL;
592
593 if (!slash)
594 free(realname);
595
596 return filename;
597}
598
599int build_id_cache__list_build_ids(const char *pathname,
600 struct strlist **result)
601{
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900602 char *dir_name;
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900603 int ret = 0;
604
Masami Hiramatsu4698b8b2016-06-08 18:29:30 +0900605 dir_name = build_id_cache__cachedir(NULL, pathname, false, false);
Masami Hiramatsud65444d2016-05-11 22:52:17 +0900606 if (!dir_name)
607 return -ENOMEM;
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900608
Masami Hiramatsud65444d2016-05-11 22:52:17 +0900609 *result = lsdir(dir_name, lsdir_no_dot_filter);
610 if (!*result)
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900611 ret = -errno;
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900612 free(dir_name);
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900613
614 return ret;
615}
616
Arnaldo Carvalho de Melo1c1a3a42016-07-12 12:19:09 -0300617#if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT)
Masami Hiramatsu6430a942016-07-01 17:04:10 +0900618static int build_id_cache__add_sdt_cache(const char *sbuild_id,
619 const char *realname)
620{
621 struct probe_cache *cache;
622 int ret;
623
624 cache = probe_cache__new(sbuild_id);
625 if (!cache)
626 return -1;
627
628 ret = probe_cache__scan_sdt(cache, realname);
629 if (ret >= 0) {
Adrian Hunterf9655202016-09-23 17:38:40 +0300630 pr_debug4("Found %d SDTs in %s\n", ret, realname);
Masami Hiramatsu6430a942016-07-01 17:04:10 +0900631 if (probe_cache__commit(cache) < 0)
632 ret = -1;
633 }
634 probe_cache__delete(cache);
635 return ret;
636}
637#else
638#define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
639#endif
640
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900641int build_id_cache__add_s(const char *sbuild_id, const char *name,
642 bool is_kallsyms, bool is_vdso)
Namhyung Kime195fac2014-11-04 10:14:30 +0900643{
644 const size_t size = PATH_MAX;
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900645 char *realname = NULL, *filename = NULL, *dir_name = NULL,
Masami Hiramatsu01412262016-05-29 00:15:37 +0900646 *linkname = zalloc(size), *tmp;
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900647 int err = -1;
Namhyung Kime195fac2014-11-04 10:14:30 +0900648
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900649 if (!is_kallsyms) {
Namhyung Kime195fac2014-11-04 10:14:30 +0900650 realname = realpath(name, NULL);
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900651 if (!realname)
652 goto out_free;
653 }
Namhyung Kime195fac2014-11-04 10:14:30 +0900654
Masami Hiramatsu4698b8b2016-06-08 18:29:30 +0900655 dir_name = build_id_cache__cachedir(sbuild_id, name,
656 is_kallsyms, is_vdso);
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900657 if (!dir_name)
Namhyung Kime195fac2014-11-04 10:14:30 +0900658 goto out_free;
659
Masami Hiramatsu01412262016-05-29 00:15:37 +0900660 /* Remove old style build-id cache */
661 if (is_regular_file(dir_name))
662 if (unlink(dir_name))
663 goto out_free;
664
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900665 if (mkdir_p(dir_name, 0755))
Namhyung Kime195fac2014-11-04 10:14:30 +0900666 goto out_free;
667
Masami Hiramatsu01412262016-05-29 00:15:37 +0900668 /* Save the allocated buildid dirname */
669 if (asprintf(&filename, "%s/%s", dir_name,
670 build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900671 filename = NULL;
672 goto out_free;
673 }
Namhyung Kime195fac2014-11-04 10:14:30 +0900674
675 if (access(filename, F_OK)) {
676 if (is_kallsyms) {
677 if (copyfile("/proc/kallsyms", filename))
678 goto out_free;
Milos Vyletel0635b0f2015-03-20 11:37:25 +0100679 } else if (link(realname, filename) && errno != EEXIST &&
680 copyfile(name, filename))
Namhyung Kime195fac2014-11-04 10:14:30 +0900681 goto out_free;
682 }
683
Masami Hiramatsu01412262016-05-29 00:15:37 +0900684 if (!build_id_cache__linkname(sbuild_id, linkname, size))
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900685 goto out_free;
686 tmp = strrchr(linkname, '/');
687 *tmp = '\0';
Namhyung Kime195fac2014-11-04 10:14:30 +0900688
689 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
690 goto out_free;
691
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900692 *tmp = '/';
Masami Hiramatsu01412262016-05-29 00:15:37 +0900693 tmp = dir_name + strlen(buildid_dir) - 5;
694 memcpy(tmp, "../..", 5);
Namhyung Kime195fac2014-11-04 10:14:30 +0900695
Masami Hiramatsu01412262016-05-29 00:15:37 +0900696 if (symlink(tmp, linkname) == 0)
Namhyung Kime195fac2014-11-04 10:14:30 +0900697 err = 0;
Masami Hiramatsu6430a942016-07-01 17:04:10 +0900698
699 /* Update SDT cache : error is just warned */
Tommi Rantala2ccc2202017-03-22 15:06:19 +0200700 if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
Adrian Hunterf9655202016-09-23 17:38:40 +0300701 pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
Masami Hiramatsu6430a942016-07-01 17:04:10 +0900702
Namhyung Kime195fac2014-11-04 10:14:30 +0900703out_free:
704 if (!is_kallsyms)
705 free(realname);
706 free(filename);
Masami Hiramatsu8d8c8e42015-02-27 13:50:26 +0900707 free(dir_name);
Namhyung Kime195fac2014-11-04 10:14:30 +0900708 free(linkname);
709 return err;
710}
711
712static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900713 const char *name, bool is_kallsyms,
714 bool is_vdso)
Namhyung Kime195fac2014-11-04 10:14:30 +0900715{
Masami Hiramatsud77fac72015-07-15 18:14:28 +0900716 char sbuild_id[SBUILD_ID_SIZE];
Namhyung Kime195fac2014-11-04 10:14:30 +0900717
718 build_id__sprintf(build_id, build_id_size, sbuild_id);
719
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900720 return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso);
Namhyung Kime195fac2014-11-04 10:14:30 +0900721}
722
Masami Hiramatsua50d11a2015-02-26 15:54:40 +0900723bool build_id_cache__cached(const char *sbuild_id)
724{
725 bool ret = false;
Masami Hiramatsu01412262016-05-29 00:15:37 +0900726 char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
Masami Hiramatsua50d11a2015-02-26 15:54:40 +0900727
728 if (filename && !access(filename, F_OK))
729 ret = true;
730 free(filename);
731
732 return ret;
733}
734
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900735int build_id_cache__remove_s(const char *sbuild_id)
Namhyung Kime195fac2014-11-04 10:14:30 +0900736{
737 const size_t size = PATH_MAX;
738 char *filename = zalloc(size),
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900739 *linkname = zalloc(size), *tmp;
Namhyung Kime195fac2014-11-04 10:14:30 +0900740 int err = -1;
741
742 if (filename == NULL || linkname == NULL)
743 goto out_free;
744
Masami Hiramatsu01412262016-05-29 00:15:37 +0900745 if (!build_id_cache__linkname(sbuild_id, linkname, size))
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900746 goto out_free;
Namhyung Kime195fac2014-11-04 10:14:30 +0900747
748 if (access(linkname, F_OK))
749 goto out_free;
750
751 if (readlink(linkname, filename, size - 1) < 0)
752 goto out_free;
753
754 if (unlink(linkname))
755 goto out_free;
756
757 /*
758 * Since the link is relative, we must make it absolute:
759 */
Masami Hiramatsu5cb113f2015-02-10 18:18:53 +0900760 tmp = strrchr(linkname, '/') + 1;
761 snprintf(tmp, size - (tmp - linkname), "%s", filename);
Namhyung Kime195fac2014-11-04 10:14:30 +0900762
Masami Hiramatsu01412262016-05-29 00:15:37 +0900763 if (rm_rf(linkname))
Namhyung Kime195fac2014-11-04 10:14:30 +0900764 goto out_free;
765
766 err = 0;
767out_free:
768 free(filename);
769 free(linkname);
770 return err;
771}
772
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900773static int dso__cache_build_id(struct dso *dso, struct machine *machine)
Namhyung Kime195fac2014-11-04 10:14:30 +0900774{
Masami Hiramatsu01412262016-05-29 00:15:37 +0900775 bool is_kallsyms = dso__is_kallsyms(dso);
Namhyung Kime195fac2014-11-04 10:14:30 +0900776 bool is_vdso = dso__is_vdso(dso);
777 const char *name = dso->long_name;
778 char nm[PATH_MAX];
779
780 if (dso__is_kcore(dso)) {
781 is_kallsyms = true;
782 machine__mmap_name(machine, nm, sizeof(nm));
783 name = nm;
784 }
785 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900786 is_kallsyms, is_vdso);
Namhyung Kime195fac2014-11-04 10:14:30 +0900787}
788
789static int __dsos__cache_build_ids(struct list_head *head,
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900790 struct machine *machine)
Namhyung Kime195fac2014-11-04 10:14:30 +0900791{
792 struct dso *pos;
793 int err = 0;
794
795 dsos__for_each_with_build_id(pos, head)
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900796 if (dso__cache_build_id(pos, machine))
Namhyung Kime195fac2014-11-04 10:14:30 +0900797 err = -1;
798
799 return err;
800}
801
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900802static int machine__cache_build_ids(struct machine *machine)
Namhyung Kime195fac2014-11-04 10:14:30 +0900803{
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300804 return __dsos__cache_build_ids(&machine->dsos.head, machine);
Namhyung Kime195fac2014-11-04 10:14:30 +0900805}
806
807int perf_session__cache_build_ids(struct perf_session *session)
808{
809 struct rb_node *nd;
810 int ret;
Namhyung Kime195fac2014-11-04 10:14:30 +0900811
Namhyung Kim73c5d222014-11-07 22:57:56 +0900812 if (no_buildid_cache)
813 return 0;
814
Jiri Olsa498922a2014-12-01 20:06:23 +0100815 if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
Namhyung Kime195fac2014-11-04 10:14:30 +0900816 return -1;
817
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900818 ret = machine__cache_build_ids(&session->machines.host);
Namhyung Kime195fac2014-11-04 10:14:30 +0900819
820 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
821 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Masami Hiramatsue35f7362015-02-10 18:18:51 +0900822 ret |= machine__cache_build_ids(pos);
Namhyung Kime195fac2014-11-04 10:14:30 +0900823 }
824 return ret ? -1 : 0;
825}
826
827static bool machine__read_build_ids(struct machine *machine, bool with_hits)
828{
Arnaldo Carvalho de Melo3d39ac52015-05-28 13:06:42 -0300829 return __dsos__read_build_ids(&machine->dsos.head, with_hits);
Namhyung Kime195fac2014-11-04 10:14:30 +0900830}
831
832bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
833{
834 struct rb_node *nd;
835 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
836
837 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
838 struct machine *pos = rb_entry(nd, struct machine, rb_node);
839 ret |= machine__read_build_ids(pos, with_hits);
840 }
841
842 return ret;
843}