Blame view

tools/perf/util/vdso.c 7.1 KB
a43783aee   Arnaldo Carvalho de Melo   perf tools: Inclu...
1
  #include <errno.h>
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
2
3
4
5
6
7
8
9
10
11
12
13
  #include <unistd.h>
  #include <stdio.h>
  #include <string.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <stdlib.h>
  #include <linux/kernel.h>
  
  #include "vdso.h"
  #include "util.h"
  #include "symbol.h"
2a03068c5   Adrian Hunter   perf tools: Pass ...
14
  #include "machine.h"
f6832e172   Adrian Hunter   perf tools: Add s...
15
  #include "thread.h"
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
16
  #include "linux/string.h"
84f5d36f4   Jiri Olsa   perf tools: Move ...
17
  #include "debug.h"
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
18

e477f3f01   Adrian Hunter   perf tools: Build...
19
20
21
22
23
  /*
   * Include definition of find_vdso_map() also used in perf-read-vdso.c for
   * building perf-read-vdso32 and perf-read-vdsox32.
   */
  #include "find-vdso-map.c"
30f4f815a   Adrian Hunter   perf tools: Group...
24
25
26
27
28
29
30
  #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
  
  struct vdso_file {
  	bool found;
  	bool error;
  	char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
  	const char *dso_name;
f6832e172   Adrian Hunter   perf tools: Add s...
31
  	const char *read_prog;
30f4f815a   Adrian Hunter   perf tools: Group...
32
33
34
35
  };
  
  struct vdso_info {
  	struct vdso_file vdso;
f6832e172   Adrian Hunter   perf tools: Add s...
36
37
38
39
  #if BITS_PER_LONG == 64
  	struct vdso_file vdso32;
  	struct vdso_file vdsox32;
  #endif
30f4f815a   Adrian Hunter   perf tools: Group...
40
  };
d027b6400   Adrian Hunter   perf machine: Fix...
41
42
43
44
45
  static struct vdso_info *vdso_info__new(void)
  {
  	static const struct vdso_info vdso_info_init = {
  		.vdso    = {
  			.temp_file_name = VDSO__TEMP_FILE_NAME,
51682dc74   Adrian Hunter   perf tools: Separ...
46
  			.dso_name = DSO__NAME_VDSO,
d027b6400   Adrian Hunter   perf machine: Fix...
47
  		},
f6832e172   Adrian Hunter   perf tools: Add s...
48
49
50
51
52
53
54
55
56
57
58
59
  #if BITS_PER_LONG == 64
  		.vdso32  = {
  			.temp_file_name = VDSO__TEMP_FILE_NAME,
  			.dso_name = DSO__NAME_VDSO32,
  			.read_prog = "perf-read-vdso32",
  		},
  		.vdsox32  = {
  			.temp_file_name = VDSO__TEMP_FILE_NAME,
  			.dso_name = DSO__NAME_VDSOX32,
  			.read_prog = "perf-read-vdsox32",
  		},
  #endif
d027b6400   Adrian Hunter   perf machine: Fix...
60
61
62
63
  	};
  
  	return memdup(&vdso_info_init, sizeof(vdso_info_init));
  }
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
64

30f4f815a   Adrian Hunter   perf tools: Group...
65
  static char *get_file(struct vdso_file *vdso_file)
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
66
67
68
69
70
71
  {
  	char *vdso = NULL;
  	char *buf = NULL;
  	void *start, *end;
  	size_t size;
  	int fd;
30f4f815a   Adrian Hunter   perf tools: Group...
72
73
  	if (vdso_file->found)
  		return vdso_file->temp_file_name;
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
74

30f4f815a   Adrian Hunter   perf tools: Group...
75
  	if (vdso_file->error || find_vdso_map(&start, &end))
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
76
77
78
79
80
81
82
  		return NULL;
  
  	size = end - start;
  
  	buf = memdup(start, size);
  	if (!buf)
  		return NULL;
30f4f815a   Adrian Hunter   perf tools: Group...
83
  	fd = mkstemp(vdso_file->temp_file_name);
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
84
85
86
87
  	if (fd < 0)
  		goto out;
  
  	if (size == (size_t) write(fd, buf, size))
30f4f815a   Adrian Hunter   perf tools: Group...
88
  		vdso = vdso_file->temp_file_name;
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
89
90
91
92
93
  
  	close(fd);
  
   out:
  	free(buf);
30f4f815a   Adrian Hunter   perf tools: Group...
94
95
  	vdso_file->found = (vdso != NULL);
  	vdso_file->error = !vdso_file->found;
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
96
97
  	return vdso;
  }
9a4388c71   Arnaldo Carvalho de Melo   perf machine: Fix...
98
  void machine__exit_vdso(struct machine *machine)
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
99
  {
d027b6400   Adrian Hunter   perf machine: Fix...
100
101
102
103
  	struct vdso_info *vdso_info = machine->vdso_info;
  
  	if (!vdso_info)
  		return;
30f4f815a   Adrian Hunter   perf tools: Group...
104
105
  	if (vdso_info->vdso.found)
  		unlink(vdso_info->vdso.temp_file_name);
f6832e172   Adrian Hunter   perf tools: Add s...
106
107
108
109
110
111
  #if BITS_PER_LONG == 64
  	if (vdso_info->vdso32.found)
  		unlink(vdso_info->vdso32.temp_file_name);
  	if (vdso_info->vdsox32.found)
  		unlink(vdso_info->vdsox32.temp_file_name);
  #endif
d027b6400   Adrian Hunter   perf machine: Fix...
112
113
  
  	zfree(&machine->vdso_info);
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
114
  }
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
115
116
  static struct dso *__machine__addnew_vdso(struct machine *machine, const char *short_name,
  					  const char *long_name)
4f71f2a0a   Adrian Hunter   perf tools: Add v...
117
118
119
120
121
  {
  	struct dso *dso;
  
  	dso = dso__new(short_name);
  	if (dso != NULL) {
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
122
  		__dsos__add(&machine->dsos, dso);
4f71f2a0a   Adrian Hunter   perf tools: Add v...
123
124
125
126
127
  		dso__set_long_name(dso, long_name, false);
  	}
  
  	return dso;
  }
f6832e172   Adrian Hunter   perf tools: Add s...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  static enum dso_type machine__thread_dso_type(struct machine *machine,
  					      struct thread *thread)
  {
  	enum dso_type dso_type = DSO__TYPE_UNKNOWN;
  	struct map *map;
  	struct dso *dso;
  
  	map = map_groups__first(thread->mg, MAP__FUNCTION);
  	for (; map ; map = map_groups__next(map)) {
  		dso = map->dso;
  		if (!dso || dso->long_name[0] != '/')
  			continue;
  		dso_type = dso__type(dso, machine);
  		if (dso_type != DSO__TYPE_UNKNOWN)
  			break;
  	}
  
  	return dso_type;
  }
76c588f1f   He Kuang   perf tools: Find ...
147
  #if BITS_PER_LONG == 64
f6832e172   Adrian Hunter   perf tools: Add s...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  static int vdso__do_copy_compat(FILE *f, int fd)
  {
  	char buf[4096];
  	size_t count;
  
  	while (1) {
  		count = fread(buf, 1, sizeof(buf), f);
  		if (ferror(f))
  			return -errno;
  		if (feof(f))
  			break;
  		if (count && writen(fd, buf, count) != (ssize_t)count)
  			return -errno;
  	}
  
  	return 0;
  }
  
  static int vdso__copy_compat(const char *prog, int fd)
  {
  	FILE *f;
  	int err;
  
  	f = popen(prog, "r");
  	if (!f)
  		return -errno;
  
  	err = vdso__do_copy_compat(f, fd);
  
  	if (pclose(f) == -1)
  		return -errno;
  
  	return err;
  }
  
  static int vdso__create_compat_file(const char *prog, char *temp_name)
  {
  	int fd, err;
  
  	fd = mkstemp(temp_name);
  	if (fd < 0)
  		return -errno;
  
  	err = vdso__copy_compat(prog, fd);
  
  	if (close(fd) == -1)
  		return -errno;
  
  	return err;
  }
  
  static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
  {
  	int err;
  
  	if (vdso_file->found)
  		return vdso_file->temp_file_name;
  
  	if (vdso_file->error)
  		return NULL;
  
  	err = vdso__create_compat_file(vdso_file->read_prog,
  				       vdso_file->temp_file_name);
  	if (err) {
  		pr_err("%s failed, error %d
  ", vdso_file->read_prog, err);
  		vdso_file->error = true;
  		return NULL;
  	}
  
  	vdso_file->found = true;
  
  	return vdso_file->temp_file_name;
  }
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
222
223
  static struct dso *__machine__findnew_compat(struct machine *machine,
  					     struct vdso_file *vdso_file)
f6832e172   Adrian Hunter   perf tools: Add s...
224
225
226
  {
  	const char *file_name;
  	struct dso *dso;
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
227
  	dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true);
f6832e172   Adrian Hunter   perf tools: Add s...
228
  	if (dso)
6d545a632   Adrian Hunter   perf tools: Fix l...
229
  		goto out;
f6832e172   Adrian Hunter   perf tools: Add s...
230
231
232
  
  	file_name = vdso__get_compat_file(vdso_file);
  	if (!file_name)
6d545a632   Adrian Hunter   perf tools: Fix l...
233
  		goto out;
f6832e172   Adrian Hunter   perf tools: Add s...
234

e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
235
  	dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
6d545a632   Adrian Hunter   perf tools: Fix l...
236
  out:
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
237
  	return dso;
f6832e172   Adrian Hunter   perf tools: Add s...
238
  }
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
239
240
241
242
  static int __machine__findnew_vdso_compat(struct machine *machine,
  					  struct thread *thread,
  					  struct vdso_info *vdso_info,
  					  struct dso **dso)
f6832e172   Adrian Hunter   perf tools: Add s...
243
244
245
246
  {
  	enum dso_type dso_type;
  
  	dso_type = machine__thread_dso_type(machine, thread);
46b1fa85f   Adrian Hunter   perf tools: Do no...
247
248
249
250
251
252
253
254
255
  
  #ifndef HAVE_PERF_READ_VDSO32
  	if (dso_type == DSO__TYPE_32BIT)
  		return 0;
  #endif
  #ifndef HAVE_PERF_READ_VDSOX32
  	if (dso_type == DSO__TYPE_X32BIT)
  		return 0;
  #endif
f6832e172   Adrian Hunter   perf tools: Add s...
256
257
  	switch (dso_type) {
  	case DSO__TYPE_32BIT:
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
258
  		*dso = __machine__findnew_compat(machine, &vdso_info->vdso32);
f6832e172   Adrian Hunter   perf tools: Add s...
259
260
  		return 1;
  	case DSO__TYPE_X32BIT:
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
261
  		*dso = __machine__findnew_compat(machine, &vdso_info->vdsox32);
f6832e172   Adrian Hunter   perf tools: Add s...
262
263
264
265
266
267
268
269
270
  		return 1;
  	case DSO__TYPE_UNKNOWN:
  	case DSO__TYPE_64BIT:
  	default:
  		return 0;
  	}
  }
  
  #endif
76c588f1f   He Kuang   perf tools: Find ...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  static struct dso *machine__find_vdso(struct machine *machine,
  				      struct thread *thread)
  {
  	struct dso *dso = NULL;
  	enum dso_type dso_type;
  
  	dso_type = machine__thread_dso_type(machine, thread);
  	switch (dso_type) {
  	case DSO__TYPE_32BIT:
  		dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true);
  		if (!dso) {
  			dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO,
  					   true);
  			if (dso && dso_type != dso__type(dso, machine))
  				dso = NULL;
  		}
  		break;
  	case DSO__TYPE_X32BIT:
  		dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true);
  		break;
  	case DSO__TYPE_64BIT:
  	case DSO__TYPE_UNKNOWN:
  	default:
  		dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
  		break;
  	}
  
  	return dso;
  }
9a4388c71   Arnaldo Carvalho de Melo   perf machine: Fix...
300
  struct dso *machine__findnew_vdso(struct machine *machine,
76c588f1f   He Kuang   perf tools: Find ...
301
  				  struct thread *thread)
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
302
  {
d027b6400   Adrian Hunter   perf machine: Fix...
303
  	struct vdso_info *vdso_info;
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
304
  	struct dso *dso = NULL;
d027b6400   Adrian Hunter   perf machine: Fix...
305

e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
306
  	pthread_rwlock_wrlock(&machine->dsos.lock);
d027b6400   Adrian Hunter   perf machine: Fix...
307
308
309
310
311
  	if (!machine->vdso_info)
  		machine->vdso_info = vdso_info__new();
  
  	vdso_info = machine->vdso_info;
  	if (!vdso_info)
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
312
  		goto out_unlock;
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
313

76c588f1f   He Kuang   perf tools: Find ...
314
315
316
  	dso = machine__find_vdso(machine, thread);
  	if (dso)
  		goto out_unlock;
f6832e172   Adrian Hunter   perf tools: Add s...
317
  #if BITS_PER_LONG == 64
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
318
319
  	if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso))
  		goto out_unlock;
f6832e172   Adrian Hunter   perf tools: Add s...
320
  #endif
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
321
  	dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
322
323
  	if (!dso) {
  		char *file;
30f4f815a   Adrian Hunter   perf tools: Group...
324
  		file = get_file(&vdso_info->vdso);
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
325
326
  		if (file)
  			dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
327
  	}
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
328
  out_unlock:
d3a7c489c   Arnaldo Carvalho de Melo   perf tools: Refer...
329
  	dso__get(dso);
e88078442   Arnaldo Carvalho de Melo   perf tools: Prote...
330
  	pthread_rwlock_unlock(&machine->dsos.lock);
7dbf4dcfe   Jiri Olsa   perf tools: Back ...
331
332
  	return dso;
  }
51682dc74   Adrian Hunter   perf tools: Separ...
333
334
335
  
  bool dso__is_vdso(struct dso *dso)
  {
f6832e172   Adrian Hunter   perf tools: Add s...
336
337
338
  	return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
  	       !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
  	       !strcmp(dso->short_name, DSO__NAME_VDSOX32);
51682dc74   Adrian Hunter   perf tools: Separ...
339
  }