Blame view

tools/perf/util/build-id.c 18.8 KB
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
1
2
3
4
5
6
7
8
  /*
   * build-id.c
   *
   * build-id support
   *
   * Copyright (C) 2009, 2010 Red Hat Inc.
   * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
   */
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
9
  #include "util.h"
76b31a29d   Arnaldo Carvalho de Melo   perf tools: Remov...
10
  #include <dirent.h>
a43783aee   Arnaldo Carvalho de Melo   perf tools: Inclu...
11
  #include <errno.h>
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
12
  #include <stdio.h>
7a8ef4c4b   Arnaldo Carvalho de Melo   perf tools: Remov...
13
14
  #include <sys/stat.h>
  #include <sys/types.h>
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
15
16
17
  #include "build-id.h"
  #include "event.h"
  #include "symbol.h"
e7ff8920e   Arnaldo Carvalho de Melo   perf tools: Use j...
18
  #include "thread.h"
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
19
  #include <linux/kernel.h>
591765fda   Arnaldo Carvalho de Melo   perf tools: Relea...
20
  #include "debug.h"
d20deb64e   Arnaldo Carvalho de Melo   perf tools: Pass ...
21
  #include "session.h"
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
22
  #include "tool.h"
e195fac80   Namhyung Kim   perf build-id: Mo...
23
24
  #include "header.h"
  #include "vdso.h"
9a3993d40   Arnaldo Carvalho de Melo   perf tools: Move ...
25
  #include "path.h"
6430a94ea   Masami Hiramatsu   perf buildid-cach...
26
  #include "probe-file.h"
8ec20b176   Arnaldo Carvalho de Melo   perf str{filter,l...
27
  #include "strlist.h"
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
28

3d689ed60   Arnaldo Carvalho de Melo   perf tools: Move ...
29
  #include "sane_ctype.h"
73c5d224b   Namhyung Kim   perf build-id: Mo...
30
31
  
  static bool no_buildid_cache;
54a3cf59b   Andrew Vagin   perf inject: Mark...
32
33
  int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
  			   union perf_event *event,
ef89325f7   Adrian Hunter   perf tools: Remov...
34
  			   struct perf_sample *sample,
54a3cf59b   Andrew Vagin   perf inject: Mark...
35
36
  			   struct perf_evsel *evsel __maybe_unused,
  			   struct machine *machine)
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
37
38
  {
  	struct addr_location al;
ef89325f7   Adrian Hunter   perf tools: Remov...
39
  	struct thread *thread = machine__findnew_thread(machine, sample->pid,
13ce34df1   Namhyung Kim   perf tools: Use t...
40
  							sample->tid);
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
41
42
43
44
45
46
47
  
  	if (thread == NULL) {
  		pr_err("problem processing %d event, skipping it.
  ",
  			event->header.type);
  		return -1;
  	}
473398a21   Arnaldo Carvalho de Melo   perf tools: Add c...
48
  	thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
49
50
51
  
  	if (al.map != NULL)
  		al.map->dso->hit = 1;
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
52
  	thread__put(thread);
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
53
54
  	return 0;
  }
1d037ca16   Irina Tirdea   perf tools: Use _...
55
  static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
d20deb64e   Arnaldo Carvalho de Melo   perf tools: Pass ...
56
  				       union perf_event *event,
1d037ca16   Irina Tirdea   perf tools: Use _...
57
58
  				       struct perf_sample *sample
  				       __maybe_unused,
743eb8686   Arnaldo Carvalho de Melo   perf tools: Resol...
59
  				       struct machine *machine)
591765fda   Arnaldo Carvalho de Melo   perf tools: Relea...
60
  {
314add6b1   Adrian Hunter   perf tools: chang...
61
62
63
  	struct thread *thread = machine__findnew_thread(machine,
  							event->fork.pid,
  							event->fork.tid);
591765fda   Arnaldo Carvalho de Melo   perf tools: Relea...
64

8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
65
66
67
  	dump_printf("(%d:%d):(%d:%d)
  ", event->fork.pid, event->fork.tid,
  		    event->fork.ppid, event->fork.ptid);
591765fda   Arnaldo Carvalho de Melo   perf tools: Relea...
68

b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
69
  	if (thread) {
5e78c69b7   He Kuang   perf buildid-list...
70
  		machine__remove_thread(machine, thread);
b91fc39f4   Arnaldo Carvalho de Melo   perf machine: Pro...
71
72
  		thread__put(thread);
  	}
591765fda   Arnaldo Carvalho de Melo   perf tools: Relea...
73
74
75
  
  	return 0;
  }
45694aa77   Arnaldo Carvalho de Melo   perf tools: Renam...
76
  struct perf_tool build_id__mark_dso_hit_ops = {
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
77
  	.sample	= build_id__mark_dso_hit,
8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
78
  	.mmap	= perf_event__process_mmap,
5c5e854bc   Stephane Eranian   perf tools: Add a...
79
  	.mmap2	= perf_event__process_mmap2,
f62d3f0f4   Arnaldo Carvalho de Melo   perf event: No ne...
80
  	.fork	= perf_event__process_fork,
8115d60c3   Arnaldo Carvalho de Melo   perf tools: Kill ...
81
  	.exit	= perf_event__exit_del_thread,
299c34520   Stephane Eranian   perf buildid-list...
82
83
  	.attr		 = perf_event__process_attr,
  	.build_id	 = perf_event__process_build_id,
1216b65c5   Adrian Hunter   perf buildid-list...
84
  	.ordered_events	 = true,
7b2567c1f   Arnaldo Carvalho de Melo   perf build-id: Mo...
85
  };
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
86

ebb296c27   Jiri Olsa   perf tools: Move ...
87
88
89
90
91
92
93
94
95
96
97
  int build_id__sprintf(const u8 *build_id, int len, char *bf)
  {
  	char *bid = bf;
  	const u8 *raw = build_id;
  	int i;
  
  	for (i = 0; i < len; ++i) {
  		sprintf(bid, "%02x", *raw);
  		++raw;
  		bid += 2;
  	}
7375e151b   Michael Petlan   perf buildid-list...
98
  	return (bid - bf) + 1;
ebb296c27   Jiri Olsa   perf tools: Move ...
99
  }
0b5a7935f   Masami Hiramatsu   perf buildid: Int...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
  {
  	char notes[PATH_MAX];
  	u8 build_id[BUILD_ID_SIZE];
  	int ret;
  
  	if (!root_dir)
  		root_dir = "";
  
  	scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
  
  	ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
  	if (ret < 0)
  		return ret;
  
  	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
  }
  
  int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
  {
  	u8 build_id[BUILD_ID_SIZE];
  	int ret;
  
  	ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
  	if (ret < 0)
  		return ret;
  	else if (ret != sizeof(build_id))
  		return -EINVAL;
  
  	return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
  }
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  /* asnprintf consolidates asprintf and snprintf */
  static int asnprintf(char **strp, size_t size, const char *fmt, ...)
  {
  	va_list ap;
  	int ret;
  
  	if (!strp)
  		return -EINVAL;
  
  	va_start(ap, fmt);
  	if (*strp)
  		ret = vsnprintf(*strp, size, fmt, ap);
  	else
  		ret = vasprintf(strp, fmt, ap);
  	va_end(ap);
  
  	return ret;
  }
01412261d   Masami Hiramatsu   perf buildid-cach...
149
150
151
  char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
  				    size_t size)
  {
01412261d   Masami Hiramatsu   perf buildid-cach...
152
  	bool retry_old = true;
c58c49ac6   Wang Nan   perf tools: Fix c...
153
154
  	snprintf(bf, size, "%s/%s/%s/kallsyms",
  		 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
01412261d   Masami Hiramatsu   perf buildid-cach...
155
156
157
  retry:
  	if (!access(bf, F_OK))
  		return bf;
01412261d   Masami Hiramatsu   perf buildid-cach...
158
159
  	if (retry_old) {
  		/* Try old style kallsyms cache */
c58c49ac6   Wang Nan   perf tools: Fix c...
160
161
  		snprintf(bf, size, "%s/%s/%s",
  			 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
01412261d   Masami Hiramatsu   perf buildid-cach...
162
163
164
165
166
167
  		retry_old = false;
  		goto retry;
  	}
  
  	return NULL;
  }
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
168
  char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
169
170
171
172
173
174
175
176
  {
  	char *tmp = bf;
  	int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
  			    sbuild_id, sbuild_id + 2);
  	if (ret < 0 || (tmp && size < (unsigned int)ret))
  		return NULL;
  	return bf;
  }
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
177
178
179
180
181
182
  char *build_id_cache__origname(const char *sbuild_id)
  {
  	char *linkname;
  	char buf[PATH_MAX];
  	char *ret = NULL, *p;
  	size_t offs = 5;	/* == strlen("../..") */
5a2342111   Tommi Rantala   perf buildid: Do ...
183
  	ssize_t len;
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
184
185
186
187
  
  	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
  	if (!linkname)
  		return NULL;
5a2342111   Tommi Rantala   perf buildid: Do ...
188
189
  	len = readlink(linkname, buf, sizeof(buf) - 1);
  	if (len <= 0)
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
190
  		goto out;
5a2342111   Tommi Rantala   perf buildid: Do ...
191
  	buf[len] = '\0';
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  	/* The link should be "../..<origpath>/<sbuild_id>" */
  	p = strrchr(buf, '/');	/* Cut off the "/<sbuild_id>" */
  	if (p && (p > buf + offs)) {
  		*p = '\0';
  		if (buf[offs + 1] == '[')
  			offs++;	/*
  				 * This is a DSO name, like [kernel.kallsyms].
  				 * Skip the first '/', since this is not the
  				 * cache of a regular file.
  				 */
  		ret = strdup(buf + offs);	/* Skip "../..[/]" */
  	}
  out:
  	free(linkname);
  	return ret;
  }
c3492a3a4   Masami Hiramatsu   perf probe: Make ...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /* Check if the given build_id cache is valid on current running system */
  static bool build_id_cache__valid_id(char *sbuild_id)
  {
  	char real_sbuild_id[SBUILD_ID_SIZE] = "";
  	char *pathname;
  	int ret = 0;
  	bool result = false;
  
  	pathname = build_id_cache__origname(sbuild_id);
  	if (!pathname)
  		return false;
  
  	if (!strcmp(pathname, DSO__NAME_KALLSYMS))
  		ret = sysfs__sprintf_build_id("/", real_sbuild_id);
  	else if (pathname[0] == '/')
  		ret = filename__sprintf_build_id(pathname, real_sbuild_id);
  	else
  		ret = -EINVAL;	/* Should we support other special DSO cache? */
  	if (ret >= 0)
  		result = (strcmp(sbuild_id, real_sbuild_id) == 0);
  	free(pathname);
  
  	return result;
  }
01412261d   Masami Hiramatsu   perf buildid-cach...
232
233
234
235
  static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
  {
  	return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
  }
3344996e4   Arnaldo Carvalho de Melo   perf symbols: Con...
236
  char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
237
  {
01412261d   Masami Hiramatsu   perf buildid-cach...
238
239
240
241
242
243
  	bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
  	bool is_vdso = dso__is_vdso((struct dso *)dso);
  	char sbuild_id[SBUILD_ID_SIZE];
  	char *linkname;
  	bool alloc = (bf == NULL);
  	int ret;
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
244

c824c4338   Arnaldo Carvalho de Melo   perf tools: Stop ...
245
  	if (!dso->has_build_id)
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
246
  		return NULL;
01412261d   Masami Hiramatsu   perf buildid-cach...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
  	linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
  	if (!linkname)
  		return NULL;
  
  	/* Check if old style build_id cache */
  	if (is_regular_file(linkname))
  		ret = asnprintf(&bf, size, "%s", linkname);
  	else
  		ret = asnprintf(&bf, size, "%s/%s", linkname,
  			 build_id_cache__basename(is_kallsyms, is_vdso));
  	if (ret < 0 || (!alloc && size < (unsigned int)ret))
  		bf = NULL;
  	free(linkname);
  
  	return bf;
b36f19d57   Arnaldo Carvalho de Melo   perf annotate: Us...
263
  }
e195fac80   Namhyung Kim   perf build-id: Mo...
264

e7ee40475   Wang Nan   perf symbols: Fix...
265
266
  bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
  {
01412261d   Masami Hiramatsu   perf buildid-cach...
267
  	char *id_name = NULL, *ch;
e7ee40475   Wang Nan   perf symbols: Fix...
268
  	struct stat sb;
01412261d   Masami Hiramatsu   perf buildid-cach...
269
270
271
272
  	char sbuild_id[SBUILD_ID_SIZE];
  
  	if (!dso->has_build_id)
  		goto err;
e7ee40475   Wang Nan   perf symbols: Fix...
273

01412261d   Masami Hiramatsu   perf buildid-cach...
274
275
  	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
  	id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
e7ee40475   Wang Nan   perf symbols: Fix...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  	if (!id_name)
  		goto err;
  	if (access(id_name, F_OK))
  		goto err;
  	if (lstat(id_name, &sb) == -1)
  		goto err;
  	if ((size_t)sb.st_size > size - 1)
  		goto err;
  	if (readlink(id_name, bf, size - 1) < 0)
  		goto err;
  
  	bf[sb.st_size] = '\0';
  
  	/*
  	 * link should be:
  	 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
  	 */
  	ch = strrchr(bf, '/');
  	if (!ch)
  		goto err;
  	if (ch - 3 < bf)
  		goto err;
01412261d   Masami Hiramatsu   perf buildid-cach...
298
  	free(id_name);
e7ee40475   Wang Nan   perf symbols: Fix...
299
300
  	return strncmp(".ko", ch - 3, 3) == 0;
  err:
e7ee40475   Wang Nan   perf symbols: Fix...
301
302
303
304
305
  	pr_err("Invalid build id: %s
  ", id_name ? :
  					 dso->long_name ? :
  					 dso->short_name ? :
  					 "[unknown]");
01412261d   Masami Hiramatsu   perf buildid-cach...
306
  	free(id_name);
e7ee40475   Wang Nan   perf symbols: Fix...
307
308
  	return false;
  }
e195fac80   Namhyung Kim   perf build-id: Mo...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  #define dsos__for_each_with_build_id(pos, head)	\
  	list_for_each_entry(pos, head, node)	\
  		if (!pos->has_build_id)		\
  			continue;		\
  		else
  
  static int write_buildid(const char *name, size_t name_len, u8 *build_id,
  			 pid_t pid, u16 misc, int fd)
  {
  	int err;
  	struct build_id_event b;
  	size_t len;
  
  	len = name_len + 1;
  	len = PERF_ALIGN(len, NAME_ALIGN);
  
  	memset(&b, 0, sizeof(b));
  	memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
  	b.pid = pid;
  	b.header.misc = misc;
  	b.header.size = sizeof(b) + len;
  
  	err = writen(fd, &b, sizeof(b));
  	if (err < 0)
  		return err;
  
  	return write_padded(fd, name, name_len + 1, len);
  }
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
337
  static int machine__write_buildid_table(struct machine *machine, int fd)
e195fac80   Namhyung Kim   perf build-id: Mo...
338
  {
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
339
  	int err = 0;
e195fac80   Namhyung Kim   perf build-id: Mo...
340
341
  	char nm[PATH_MAX];
  	struct dso *pos;
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
342
343
344
345
346
347
348
  	u16 kmisc = PERF_RECORD_MISC_KERNEL,
  	    umisc = PERF_RECORD_MISC_USER;
  
  	if (!machine__is_host(machine)) {
  		kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
  		umisc = PERF_RECORD_MISC_GUEST_USER;
  	}
e195fac80   Namhyung Kim   perf build-id: Mo...
349

3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
350
  	dsos__for_each_with_build_id(pos, &machine->dsos.head) {
e195fac80   Namhyung Kim   perf build-id: Mo...
351
352
  		const char *name;
  		size_t name_len;
fd786fac7   Wang Nan   perf buildid: Fix...
353
  		bool in_kernel = false;
e195fac80   Namhyung Kim   perf build-id: Mo...
354

6ae98ba61   He Kuang   perf symbols: Sto...
355
  		if (!pos->hit && !dso__is_vdso(pos))
e195fac80   Namhyung Kim   perf build-id: Mo...
356
357
358
359
  			continue;
  
  		if (dso__is_vdso(pos)) {
  			name = pos->short_name;
70a2cba97   Andrey Ryabinin   perf buildid: Fix...
360
  			name_len = pos->short_name_len;
e195fac80   Namhyung Kim   perf build-id: Mo...
361
362
363
  		} else if (dso__is_kcore(pos)) {
  			machine__mmap_name(machine, nm, sizeof(nm));
  			name = nm;
70a2cba97   Andrey Ryabinin   perf buildid: Fix...
364
  			name_len = strlen(nm);
e195fac80   Namhyung Kim   perf build-id: Mo...
365
366
  		} else {
  			name = pos->long_name;
70a2cba97   Andrey Ryabinin   perf buildid: Fix...
367
  			name_len = pos->long_name_len;
e195fac80   Namhyung Kim   perf build-id: Mo...
368
  		}
fd786fac7   Wang Nan   perf buildid: Fix...
369
370
371
  		in_kernel = pos->kernel ||
  				is_kernel_module(name,
  					PERF_RECORD_MISC_CPUMODE_UNKNOWN);
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
372
  		err = write_buildid(name, name_len, pos->build_id, machine->pid,
fd786fac7   Wang Nan   perf buildid: Fix...
373
  				    in_kernel ? kmisc : umisc, fd);
e195fac80   Namhyung Kim   perf build-id: Mo...
374
  		if (err)
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
375
  			break;
e195fac80   Namhyung Kim   perf build-id: Mo...
376
  	}
e195fac80   Namhyung Kim   perf build-id: Mo...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  	return err;
  }
  
  int perf_session__write_buildid_table(struct perf_session *session, int fd)
  {
  	struct rb_node *nd;
  	int err = machine__write_buildid_table(&session->machines.host, fd);
  
  	if (err)
  		return err;
  
  	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
  		err = machine__write_buildid_table(pos, fd);
  		if (err)
  			break;
  	}
  	return err;
  }
  
  static int __dsos__hit_all(struct list_head *head)
  {
  	struct dso *pos;
  
  	list_for_each_entry(pos, head, node)
  		pos->hit = true;
  
  	return 0;
  }
  
  static int machine__hit_all_dsos(struct machine *machine)
  {
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
409
  	return __dsos__hit_all(&machine->dsos.head);
e195fac80   Namhyung Kim   perf build-id: Mo...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  }
  
  int dsos__hit_all(struct perf_session *session)
  {
  	struct rb_node *nd;
  	int err;
  
  	err = machine__hit_all_dsos(&session->machines.host);
  	if (err)
  		return err;
  
  	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
  
  		err = machine__hit_all_dsos(pos);
  		if (err)
  			return err;
  	}
  
  	return 0;
  }
73c5d224b   Namhyung Kim   perf build-id: Mo...
431
432
433
434
  void disable_buildid_cache(void)
  {
  	no_buildid_cache = true;
  }
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
435
  static bool lsdir_bid_head_filter(const char *name __maybe_unused,
767fe71b2   Arnaldo Carvalho de Melo   perf tools: Remov...
436
  				  struct dirent *d)
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
437
438
439
440
441
442
  {
  	return (strlen(d->d_name) == 2) &&
  		isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
  }
  
  static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
767fe71b2   Arnaldo Carvalho de Melo   perf tools: Remov...
443
  				  struct dirent *d)
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
444
445
446
447
448
449
  {
  	int i = 0;
  	while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
  		i++;
  	return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
  }
c3492a3a4   Masami Hiramatsu   perf probe: Make ...
450
  struct strlist *build_id_cache__list_all(bool validonly)
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
451
452
453
454
455
  {
  	struct strlist *toplist, *linklist = NULL, *bidlist;
  	struct str_node *nd, *nd2;
  	char *topdir, *linkdir = NULL;
  	char sbuild_id[SBUILD_ID_SIZE];
c3492a3a4   Masami Hiramatsu   perf probe: Make ...
456
457
458
  	/* for filename__ functions */
  	if (validonly)
  		symbol__init(NULL);
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  	/* Open the top-level directory */
  	if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
  		return NULL;
  
  	bidlist = strlist__new(NULL, NULL);
  	if (!bidlist)
  		goto out;
  
  	toplist = lsdir(topdir, lsdir_bid_head_filter);
  	if (!toplist) {
  		pr_debug("Error in lsdir(%s): %d
  ", topdir, errno);
  		/* If there is no buildid cache, return an empty list */
  		if (errno == ENOENT)
  			goto out;
  		goto err_out;
  	}
  
  	strlist__for_each_entry(nd, toplist) {
  		if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
  			goto err_out;
  		/* Open the lower-level directory */
  		linklist = lsdir(linkdir, lsdir_bid_tail_filter);
  		if (!linklist) {
  			pr_debug("Error in lsdir(%s): %d
  ", linkdir, errno);
  			goto err_out;
  		}
  		strlist__for_each_entry(nd2, linklist) {
  			if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
  				     nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
  				goto err_out;
c3492a3a4   Masami Hiramatsu   perf probe: Make ...
491
492
  			if (validonly && !build_id_cache__valid_id(sbuild_id))
  				continue;
1f3736c9c   Masami Hiramatsu   perf probe: Show ...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  			if (strlist__add(bidlist, sbuild_id) < 0)
  				goto err_out;
  		}
  		strlist__delete(linklist);
  		zfree(&linkdir);
  	}
  
  out_free:
  	strlist__delete(toplist);
  out:
  	free(topdir);
  
  	return bidlist;
  
  err_out:
  	strlist__delete(linklist);
  	zfree(&linkdir);
  	strlist__delete(bidlist);
  	bidlist = NULL;
  	goto out_free;
  }
a598180aa   Masami Hiramatsu   perf probe: Suppo...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  static bool str_is_build_id(const char *maybe_sbuild_id, size_t len)
  {
  	size_t i;
  
  	for (i = 0; i < len; i++) {
  		if (!isxdigit(maybe_sbuild_id[i]))
  			return false;
  	}
  	return true;
  }
  
  /* Return the valid complete build-id */
  char *build_id_cache__complement(const char *incomplete_sbuild_id)
  {
  	struct strlist *bidlist;
  	struct str_node *nd, *cand = NULL;
  	char *sbuild_id = NULL;
  	size_t len = strlen(incomplete_sbuild_id);
  
  	if (len >= SBUILD_ID_SIZE ||
  	    !str_is_build_id(incomplete_sbuild_id, len))
  		return NULL;
  
  	bidlist = build_id_cache__list_all(true);
  	if (!bidlist)
  		return NULL;
  
  	strlist__for_each_entry(nd, bidlist) {
  		if (strncmp(nd->s, incomplete_sbuild_id, len) != 0)
  			continue;
  		if (cand) {	/* Error: There are more than 2 candidates. */
  			cand = NULL;
  			break;
  		}
  		cand = nd;
  	}
  	if (cand)
  		sbuild_id = strdup(cand->s);
  	strlist__delete(bidlist);
  
  	return sbuild_id;
  }
4698b8b75   Masami Hiramatsu   perf buildid: Ren...
556
557
  char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
  			       bool is_kallsyms, bool is_vdso)
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
558
559
560
561
562
563
564
565
566
  {
  	char *realname = (char *)name, *filename;
  	bool slash = is_kallsyms || is_vdso;
  
  	if (!slash) {
  		realname = realpath(name, NULL);
  		if (!realname)
  			return NULL;
  	}
01412261d   Masami Hiramatsu   perf buildid-cach...
567
568
569
  	if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
  		     is_vdso ? DSO__NAME_VDSO : realname,
  		     sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
570
571
572
573
574
575
576
577
578
579
580
  		filename = NULL;
  
  	if (!slash)
  		free(realname);
  
  	return filename;
  }
  
  int build_id_cache__list_build_ids(const char *pathname,
  				   struct strlist **result)
  {
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
581
  	char *dir_name;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
582
  	int ret = 0;
4698b8b75   Masami Hiramatsu   perf buildid: Ren...
583
  	dir_name = build_id_cache__cachedir(NULL, pathname, false, false);
d65444d2f   Masami Hiramatsu   perf buildid-cach...
584
585
  	if (!dir_name)
  		return -ENOMEM;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
586

d65444d2f   Masami Hiramatsu   perf buildid-cach...
587
588
  	*result = lsdir(dir_name, lsdir_no_dot_filter);
  	if (!*result)
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
589
  		ret = -errno;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
590
  	free(dir_name);
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
591
592
593
  
  	return ret;
  }
1c1a3a472   Arnaldo Carvalho de Melo   perf tools: Add f...
594
  #if defined(HAVE_LIBELF_SUPPORT) && defined(HAVE_GELF_GETNOTE_SUPPORT)
6430a94ea   Masami Hiramatsu   perf buildid-cach...
595
596
597
598
599
600
601
602
603
604
605
606
  static int build_id_cache__add_sdt_cache(const char *sbuild_id,
  					  const char *realname)
  {
  	struct probe_cache *cache;
  	int ret;
  
  	cache = probe_cache__new(sbuild_id);
  	if (!cache)
  		return -1;
  
  	ret = probe_cache__scan_sdt(cache, realname);
  	if (ret >= 0) {
f9655200e   Adrian Hunter   perf probe: Incre...
607
608
  		pr_debug4("Found %d SDTs in %s
  ", ret, realname);
6430a94ea   Masami Hiramatsu   perf buildid-cach...
609
610
611
612
613
614
615
616
617
  		if (probe_cache__commit(cache) < 0)
  			ret = -1;
  	}
  	probe_cache__delete(cache);
  	return ret;
  }
  #else
  #define build_id_cache__add_sdt_cache(sbuild_id, realname) (0)
  #endif
e35f7362b   Masami Hiramatsu   perf buildid-cach...
618
619
  int build_id_cache__add_s(const char *sbuild_id, const char *name,
  			  bool is_kallsyms, bool is_vdso)
e195fac80   Namhyung Kim   perf build-id: Mo...
620
621
  {
  	const size_t size = PATH_MAX;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
622
  	char *realname = NULL, *filename = NULL, *dir_name = NULL,
01412261d   Masami Hiramatsu   perf buildid-cach...
623
  	     *linkname = zalloc(size), *tmp;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
624
  	int err = -1;
e195fac80   Namhyung Kim   perf build-id: Mo...
625

8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
626
  	if (!is_kallsyms) {
e195fac80   Namhyung Kim   perf build-id: Mo...
627
  		realname = realpath(name, NULL);
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
628
629
630
  		if (!realname)
  			goto out_free;
  	}
e195fac80   Namhyung Kim   perf build-id: Mo...
631

4698b8b75   Masami Hiramatsu   perf buildid: Ren...
632
633
  	dir_name = build_id_cache__cachedir(sbuild_id, name,
  					    is_kallsyms, is_vdso);
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
634
  	if (!dir_name)
e195fac80   Namhyung Kim   perf build-id: Mo...
635
  		goto out_free;
01412261d   Masami Hiramatsu   perf buildid-cach...
636
637
638
639
  	/* Remove old style build-id cache */
  	if (is_regular_file(dir_name))
  		if (unlink(dir_name))
  			goto out_free;
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
640
  	if (mkdir_p(dir_name, 0755))
e195fac80   Namhyung Kim   perf build-id: Mo...
641
  		goto out_free;
01412261d   Masami Hiramatsu   perf buildid-cach...
642
643
644
  	/* Save the allocated buildid dirname */
  	if (asprintf(&filename, "%s/%s", dir_name,
  		     build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
645
646
647
  		filename = NULL;
  		goto out_free;
  	}
e195fac80   Namhyung Kim   perf build-id: Mo...
648
649
650
651
652
  
  	if (access(filename, F_OK)) {
  		if (is_kallsyms) {
  			 if (copyfile("/proc/kallsyms", filename))
  				goto out_free;
0635b0f71   Milos Vyletel   perf tools: Fix r...
653
654
  		} else if (link(realname, filename) && errno != EEXIST &&
  				copyfile(name, filename))
e195fac80   Namhyung Kim   perf build-id: Mo...
655
656
  			goto out_free;
  	}
01412261d   Masami Hiramatsu   perf buildid-cach...
657
  	if (!build_id_cache__linkname(sbuild_id, linkname, size))
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
658
659
660
  		goto out_free;
  	tmp = strrchr(linkname, '/');
  	*tmp = '\0';
e195fac80   Namhyung Kim   perf build-id: Mo...
661
662
663
  
  	if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
  		goto out_free;
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
664
  	*tmp = '/';
01412261d   Masami Hiramatsu   perf buildid-cach...
665
666
  	tmp = dir_name + strlen(buildid_dir) - 5;
  	memcpy(tmp, "../..", 5);
e195fac80   Namhyung Kim   perf build-id: Mo...
667

01412261d   Masami Hiramatsu   perf buildid-cach...
668
  	if (symlink(tmp, linkname) == 0)
e195fac80   Namhyung Kim   perf build-id: Mo...
669
  		err = 0;
6430a94ea   Masami Hiramatsu   perf buildid-cach...
670
671
  
  	/* Update SDT cache : error is just warned */
2ccc22023   Tommi Rantala   perf buildid: Do ...
672
  	if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
f9655200e   Adrian Hunter   perf probe: Incre...
673
674
  		pr_debug4("Failed to update/scan SDT cache for %s
  ", realname);
6430a94ea   Masami Hiramatsu   perf buildid-cach...
675

e195fac80   Namhyung Kim   perf build-id: Mo...
676
677
678
679
  out_free:
  	if (!is_kallsyms)
  		free(realname);
  	free(filename);
8d8c8e4cb   Masami Hiramatsu   perf buildid-cach...
680
  	free(dir_name);
e195fac80   Namhyung Kim   perf build-id: Mo...
681
682
683
684
685
  	free(linkname);
  	return err;
  }
  
  static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
e35f7362b   Masami Hiramatsu   perf buildid-cach...
686
687
  				 const char *name, bool is_kallsyms,
  				 bool is_vdso)
e195fac80   Namhyung Kim   perf build-id: Mo...
688
  {
d77fac7f9   Masami Hiramatsu   perf buildid: Use...
689
  	char sbuild_id[SBUILD_ID_SIZE];
e195fac80   Namhyung Kim   perf build-id: Mo...
690
691
  
  	build_id__sprintf(build_id, build_id_size, sbuild_id);
e35f7362b   Masami Hiramatsu   perf buildid-cach...
692
  	return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso);
e195fac80   Namhyung Kim   perf build-id: Mo...
693
  }
a50d11a10   Masami Hiramatsu   perf buildid-cach...
694
695
696
  bool build_id_cache__cached(const char *sbuild_id)
  {
  	bool ret = false;
01412261d   Masami Hiramatsu   perf buildid-cach...
697
  	char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
a50d11a10   Masami Hiramatsu   perf buildid-cach...
698
699
700
701
702
703
704
  
  	if (filename && !access(filename, F_OK))
  		ret = true;
  	free(filename);
  
  	return ret;
  }
e35f7362b   Masami Hiramatsu   perf buildid-cach...
705
  int build_id_cache__remove_s(const char *sbuild_id)
e195fac80   Namhyung Kim   perf build-id: Mo...
706
707
708
  {
  	const size_t size = PATH_MAX;
  	char *filename = zalloc(size),
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
709
  	     *linkname = zalloc(size), *tmp;
e195fac80   Namhyung Kim   perf build-id: Mo...
710
711
712
713
  	int err = -1;
  
  	if (filename == NULL || linkname == NULL)
  		goto out_free;
01412261d   Masami Hiramatsu   perf buildid-cach...
714
  	if (!build_id_cache__linkname(sbuild_id, linkname, size))
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
715
  		goto out_free;
e195fac80   Namhyung Kim   perf build-id: Mo...
716
717
718
719
720
721
722
723
724
725
726
727
728
  
  	if (access(linkname, F_OK))
  		goto out_free;
  
  	if (readlink(linkname, filename, size - 1) < 0)
  		goto out_free;
  
  	if (unlink(linkname))
  		goto out_free;
  
  	/*
  	 * Since the link is relative, we must make it absolute:
  	 */
5cb113fd8   Masami Hiramatsu   perf buildid-cach...
729
730
  	tmp = strrchr(linkname, '/') + 1;
  	snprintf(tmp, size - (tmp - linkname), "%s", filename);
e195fac80   Namhyung Kim   perf build-id: Mo...
731

01412261d   Masami Hiramatsu   perf buildid-cach...
732
  	if (rm_rf(linkname))
e195fac80   Namhyung Kim   perf build-id: Mo...
733
734
735
736
737
738
739
740
  		goto out_free;
  
  	err = 0;
  out_free:
  	free(filename);
  	free(linkname);
  	return err;
  }
e35f7362b   Masami Hiramatsu   perf buildid-cach...
741
  static int dso__cache_build_id(struct dso *dso, struct machine *machine)
e195fac80   Namhyung Kim   perf build-id: Mo...
742
  {
01412261d   Masami Hiramatsu   perf buildid-cach...
743
  	bool is_kallsyms = dso__is_kallsyms(dso);
e195fac80   Namhyung Kim   perf build-id: Mo...
744
745
746
747
748
749
750
751
752
753
  	bool is_vdso = dso__is_vdso(dso);
  	const char *name = dso->long_name;
  	char nm[PATH_MAX];
  
  	if (dso__is_kcore(dso)) {
  		is_kallsyms = true;
  		machine__mmap_name(machine, nm, sizeof(nm));
  		name = nm;
  	}
  	return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
e35f7362b   Masami Hiramatsu   perf buildid-cach...
754
  				     is_kallsyms, is_vdso);
e195fac80   Namhyung Kim   perf build-id: Mo...
755
756
757
  }
  
  static int __dsos__cache_build_ids(struct list_head *head,
e35f7362b   Masami Hiramatsu   perf buildid-cach...
758
  				   struct machine *machine)
e195fac80   Namhyung Kim   perf build-id: Mo...
759
760
761
762
763
  {
  	struct dso *pos;
  	int err = 0;
  
  	dsos__for_each_with_build_id(pos, head)
e35f7362b   Masami Hiramatsu   perf buildid-cach...
764
  		if (dso__cache_build_id(pos, machine))
e195fac80   Namhyung Kim   perf build-id: Mo...
765
766
767
768
  			err = -1;
  
  	return err;
  }
e35f7362b   Masami Hiramatsu   perf buildid-cach...
769
  static int machine__cache_build_ids(struct machine *machine)
e195fac80   Namhyung Kim   perf build-id: Mo...
770
  {
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
771
  	return __dsos__cache_build_ids(&machine->dsos.head, machine);
e195fac80   Namhyung Kim   perf build-id: Mo...
772
773
774
775
776
777
  }
  
  int perf_session__cache_build_ids(struct perf_session *session)
  {
  	struct rb_node *nd;
  	int ret;
e195fac80   Namhyung Kim   perf build-id: Mo...
778

73c5d224b   Namhyung Kim   perf build-id: Mo...
779
780
  	if (no_buildid_cache)
  		return 0;
498922adf   Jiri Olsa   perf buildid-cach...
781
  	if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
e195fac80   Namhyung Kim   perf build-id: Mo...
782
  		return -1;
e35f7362b   Masami Hiramatsu   perf buildid-cach...
783
  	ret = machine__cache_build_ids(&session->machines.host);
e195fac80   Namhyung Kim   perf build-id: Mo...
784
785
786
  
  	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
e35f7362b   Masami Hiramatsu   perf buildid-cach...
787
  		ret |= machine__cache_build_ids(pos);
e195fac80   Namhyung Kim   perf build-id: Mo...
788
789
790
791
792
793
  	}
  	return ret ? -1 : 0;
  }
  
  static bool machine__read_build_ids(struct machine *machine, bool with_hits)
  {
3d39ac538   Arnaldo Carvalho de Melo   perf machine: No ...
794
  	return __dsos__read_build_ids(&machine->dsos.head, with_hits);
e195fac80   Namhyung Kim   perf build-id: Mo...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  }
  
  bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
  {
  	struct rb_node *nd;
  	bool ret = machine__read_build_ids(&session->machines.host, with_hits);
  
  	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
  		struct machine *pos = rb_entry(nd, struct machine, rb_node);
  		ret |= machine__read_build_ids(pos, with_hits);
  	}
  
  	return ret;
  }