blob: 741af209b19d65283f8ce130d6104c233864dac1 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +02003#include <unistd.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <stdlib.h>
10#include <linux/kernel.h>
11
12#include "vdso.h"
13#include "util.h"
14#include "symbol.h"
Adrian Hunter2a030682014-07-22 16:17:53 +030015#include "machine.h"
Adrian Hunterf6832e172014-10-23 13:45:23 +030016#include "thread.h"
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020017#include "linux/string.h"
Jiri Olsa84f5d362014-07-14 23:46:48 +020018#include "debug.h"
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020019
Adrian Huntere477f3f2014-10-23 18:16:03 -030020/*
21 * Include definition of find_vdso_map() also used in perf-read-vdso.c for
22 * building perf-read-vdso32 and perf-read-vdsox32.
23 */
24#include "find-vdso-map.c"
25
Adrian Hunter30f4f812014-07-22 16:17:54 +030026#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
27
28struct vdso_file {
29 bool found;
30 bool error;
31 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
32 const char *dso_name;
Adrian Hunterf6832e172014-10-23 13:45:23 +030033 const char *read_prog;
Adrian Hunter30f4f812014-07-22 16:17:54 +030034};
35
36struct vdso_info {
37 struct vdso_file vdso;
Adrian Hunterf6832e172014-10-23 13:45:23 +030038#if BITS_PER_LONG == 64
39 struct vdso_file vdso32;
40 struct vdso_file vdsox32;
41#endif
Adrian Hunter30f4f812014-07-22 16:17:54 +030042};
43
Adrian Hunterd027b6402014-07-23 14:23:00 +030044static struct vdso_info *vdso_info__new(void)
45{
46 static const struct vdso_info vdso_info_init = {
47 .vdso = {
48 .temp_file_name = VDSO__TEMP_FILE_NAME,
Adrian Hunter51682dc2014-07-22 16:17:57 +030049 .dso_name = DSO__NAME_VDSO,
Adrian Hunterd027b6402014-07-23 14:23:00 +030050 },
Adrian Hunterf6832e172014-10-23 13:45:23 +030051#if BITS_PER_LONG == 64
52 .vdso32 = {
53 .temp_file_name = VDSO__TEMP_FILE_NAME,
54 .dso_name = DSO__NAME_VDSO32,
55 .read_prog = "perf-read-vdso32",
56 },
57 .vdsox32 = {
58 .temp_file_name = VDSO__TEMP_FILE_NAME,
59 .dso_name = DSO__NAME_VDSOX32,
60 .read_prog = "perf-read-vdsox32",
61 },
62#endif
Adrian Hunterd027b6402014-07-23 14:23:00 +030063 };
Adrian Hunter30f4f812014-07-22 16:17:54 +030064
Adrian Hunterd027b6402014-07-23 14:23:00 +030065 return memdup(&vdso_info_init, sizeof(vdso_info_init));
66}
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020067
Adrian Hunter30f4f812014-07-22 16:17:54 +030068static char *get_file(struct vdso_file *vdso_file)
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020069{
70 char *vdso = NULL;
71 char *buf = NULL;
72 void *start, *end;
73 size_t size;
74 int fd;
75
Adrian Hunter30f4f812014-07-22 16:17:54 +030076 if (vdso_file->found)
77 return vdso_file->temp_file_name;
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020078
Adrian Hunter30f4f812014-07-22 16:17:54 +030079 if (vdso_file->error || find_vdso_map(&start, &end))
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020080 return NULL;
81
82 size = end - start;
83
84 buf = memdup(start, size);
85 if (!buf)
86 return NULL;
87
Adrian Hunter30f4f812014-07-22 16:17:54 +030088 fd = mkstemp(vdso_file->temp_file_name);
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020089 if (fd < 0)
90 goto out;
91
92 if (size == (size_t) write(fd, buf, size))
Adrian Hunter30f4f812014-07-22 16:17:54 +030093 vdso = vdso_file->temp_file_name;
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +020094
95 close(fd);
96
97 out:
98 free(buf);
99
Adrian Hunter30f4f812014-07-22 16:17:54 +0300100 vdso_file->found = (vdso != NULL);
101 vdso_file->error = !vdso_file->found;
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200102 return vdso;
103}
104
Arnaldo Carvalho de Melo9a4388c2015-05-29 11:54:08 -0300105void machine__exit_vdso(struct machine *machine)
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200106{
Adrian Hunterd027b6402014-07-23 14:23:00 +0300107 struct vdso_info *vdso_info = machine->vdso_info;
108
109 if (!vdso_info)
110 return;
111
Adrian Hunter30f4f812014-07-22 16:17:54 +0300112 if (vdso_info->vdso.found)
113 unlink(vdso_info->vdso.temp_file_name);
Adrian Hunterf6832e172014-10-23 13:45:23 +0300114#if BITS_PER_LONG == 64
115 if (vdso_info->vdso32.found)
116 unlink(vdso_info->vdso32.temp_file_name);
117 if (vdso_info->vdsox32.found)
118 unlink(vdso_info->vdsox32.temp_file_name);
119#endif
Adrian Hunterd027b6402014-07-23 14:23:00 +0300120
121 zfree(&machine->vdso_info);
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200122}
123
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300124static struct dso *__machine__addnew_vdso(struct machine *machine, const char *short_name,
125 const char *long_name)
Adrian Hunter4f71f2a2014-07-22 16:17:56 +0300126{
127 struct dso *dso;
128
129 dso = dso__new(short_name);
130 if (dso != NULL) {
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300131 __dsos__add(&machine->dsos, dso);
Adrian Hunter4f71f2a2014-07-22 16:17:56 +0300132 dso__set_long_name(dso, long_name, false);
133 }
134
135 return dso;
136}
137
Adrian Hunterf6832e172014-10-23 13:45:23 +0300138static enum dso_type machine__thread_dso_type(struct machine *machine,
139 struct thread *thread)
140{
141 enum dso_type dso_type = DSO__TYPE_UNKNOWN;
Arnaldo Carvalho de Melodce04782018-04-25 17:28:55 -0300142 struct map *map = map_groups__first(thread->mg);
Adrian Hunterf6832e172014-10-23 13:45:23 +0300143
Adrian Hunterf6832e172014-10-23 13:45:23 +0300144 for (; map ; map = map_groups__next(map)) {
Arnaldo Carvalho de Melodce04782018-04-25 17:28:55 -0300145 struct dso *dso = map->dso;
Adrian Hunterf6832e172014-10-23 13:45:23 +0300146 if (!dso || dso->long_name[0] != '/')
147 continue;
148 dso_type = dso__type(dso, machine);
149 if (dso_type != DSO__TYPE_UNKNOWN)
150 break;
151 }
152
153 return dso_type;
154}
155
He Kuang76c588f2016-05-17 09:04:54 +0000156#if BITS_PER_LONG == 64
157
Adrian Hunterf6832e172014-10-23 13:45:23 +0300158static int vdso__do_copy_compat(FILE *f, int fd)
159{
160 char buf[4096];
161 size_t count;
162
163 while (1) {
164 count = fread(buf, 1, sizeof(buf), f);
165 if (ferror(f))
166 return -errno;
167 if (feof(f))
168 break;
169 if (count && writen(fd, buf, count) != (ssize_t)count)
170 return -errno;
171 }
172
173 return 0;
174}
175
176static int vdso__copy_compat(const char *prog, int fd)
177{
178 FILE *f;
179 int err;
180
181 f = popen(prog, "r");
182 if (!f)
183 return -errno;
184
185 err = vdso__do_copy_compat(f, fd);
186
187 if (pclose(f) == -1)
188 return -errno;
189
190 return err;
191}
192
193static int vdso__create_compat_file(const char *prog, char *temp_name)
194{
195 int fd, err;
196
197 fd = mkstemp(temp_name);
198 if (fd < 0)
199 return -errno;
200
201 err = vdso__copy_compat(prog, fd);
202
203 if (close(fd) == -1)
204 return -errno;
205
206 return err;
207}
208
209static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
210{
211 int err;
212
213 if (vdso_file->found)
214 return vdso_file->temp_file_name;
215
216 if (vdso_file->error)
217 return NULL;
218
219 err = vdso__create_compat_file(vdso_file->read_prog,
220 vdso_file->temp_file_name);
221 if (err) {
222 pr_err("%s failed, error %d\n", vdso_file->read_prog, err);
223 vdso_file->error = true;
224 return NULL;
225 }
226
227 vdso_file->found = true;
228
229 return vdso_file->temp_file_name;
230}
231
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300232static struct dso *__machine__findnew_compat(struct machine *machine,
233 struct vdso_file *vdso_file)
Adrian Hunterf6832e172014-10-23 13:45:23 +0300234{
235 const char *file_name;
236 struct dso *dso;
237
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300238 dso = __dsos__find(&machine->dsos, vdso_file->dso_name, true);
Adrian Hunterf6832e172014-10-23 13:45:23 +0300239 if (dso)
Adrian Hunter6d545a62015-07-07 14:13:38 +0300240 goto out;
Adrian Hunterf6832e172014-10-23 13:45:23 +0300241
242 file_name = vdso__get_compat_file(vdso_file);
243 if (!file_name)
Adrian Hunter6d545a62015-07-07 14:13:38 +0300244 goto out;
Adrian Hunterf6832e172014-10-23 13:45:23 +0300245
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300246 dso = __machine__addnew_vdso(machine, vdso_file->dso_name, file_name);
Adrian Hunter6d545a62015-07-07 14:13:38 +0300247out:
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300248 return dso;
Adrian Hunterf6832e172014-10-23 13:45:23 +0300249}
250
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300251static int __machine__findnew_vdso_compat(struct machine *machine,
252 struct thread *thread,
253 struct vdso_info *vdso_info,
254 struct dso **dso)
Adrian Hunterf6832e172014-10-23 13:45:23 +0300255{
256 enum dso_type dso_type;
257
258 dso_type = machine__thread_dso_type(machine, thread);
Adrian Hunter46b1fa82014-10-23 13:45:24 +0300259
260#ifndef HAVE_PERF_READ_VDSO32
261 if (dso_type == DSO__TYPE_32BIT)
262 return 0;
263#endif
264#ifndef HAVE_PERF_READ_VDSOX32
265 if (dso_type == DSO__TYPE_X32BIT)
266 return 0;
267#endif
268
Adrian Hunterf6832e172014-10-23 13:45:23 +0300269 switch (dso_type) {
270 case DSO__TYPE_32BIT:
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300271 *dso = __machine__findnew_compat(machine, &vdso_info->vdso32);
Adrian Hunterf6832e172014-10-23 13:45:23 +0300272 return 1;
273 case DSO__TYPE_X32BIT:
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300274 *dso = __machine__findnew_compat(machine, &vdso_info->vdsox32);
Adrian Hunterf6832e172014-10-23 13:45:23 +0300275 return 1;
276 case DSO__TYPE_UNKNOWN:
277 case DSO__TYPE_64BIT:
278 default:
279 return 0;
280 }
281}
282
283#endif
284
He Kuang76c588f2016-05-17 09:04:54 +0000285static struct dso *machine__find_vdso(struct machine *machine,
286 struct thread *thread)
287{
288 struct dso *dso = NULL;
289 enum dso_type dso_type;
290
291 dso_type = machine__thread_dso_type(machine, thread);
292 switch (dso_type) {
293 case DSO__TYPE_32BIT:
294 dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true);
295 if (!dso) {
296 dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO,
297 true);
298 if (dso && dso_type != dso__type(dso, machine))
299 dso = NULL;
300 }
301 break;
302 case DSO__TYPE_X32BIT:
303 dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true);
304 break;
305 case DSO__TYPE_64BIT:
306 case DSO__TYPE_UNKNOWN:
307 default:
308 dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
309 break;
310 }
311
312 return dso;
313}
314
Arnaldo Carvalho de Melo9a4388c2015-05-29 11:54:08 -0300315struct dso *machine__findnew_vdso(struct machine *machine,
He Kuang76c588f2016-05-17 09:04:54 +0000316 struct thread *thread)
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200317{
Adrian Hunterd027b6402014-07-23 14:23:00 +0300318 struct vdso_info *vdso_info;
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300319 struct dso *dso = NULL;
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200320
Arnaldo Carvalho de Melo0a7c74e2017-04-04 13:15:04 -0300321 down_write(&machine->dsos.lock);
Adrian Hunterd027b6402014-07-23 14:23:00 +0300322 if (!machine->vdso_info)
323 machine->vdso_info = vdso_info__new();
324
325 vdso_info = machine->vdso_info;
326 if (!vdso_info)
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300327 goto out_unlock;
Adrian Hunterd027b6402014-07-23 14:23:00 +0300328
He Kuang76c588f2016-05-17 09:04:54 +0000329 dso = machine__find_vdso(machine, thread);
330 if (dso)
331 goto out_unlock;
332
Adrian Hunterf6832e172014-10-23 13:45:23 +0300333#if BITS_PER_LONG == 64
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300334 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso))
335 goto out_unlock;
Adrian Hunterf6832e172014-10-23 13:45:23 +0300336#endif
337
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300338 dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true);
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200339 if (!dso) {
340 char *file;
341
Adrian Hunter30f4f812014-07-22 16:17:54 +0300342 file = get_file(&vdso_info->vdso);
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300343 if (file)
344 dso = __machine__addnew_vdso(machine, DSO__NAME_VDSO, file);
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200345 }
346
Arnaldo Carvalho de Meloe8807842015-06-01 15:40:01 -0300347out_unlock:
Arnaldo Carvalho de Melod3a7c482015-06-02 11:53:26 -0300348 dso__get(dso);
Arnaldo Carvalho de Melo0a7c74e2017-04-04 13:15:04 -0300349 up_write(&machine->dsos.lock);
Jiri Olsa7dbf4dc2012-09-10 18:50:19 +0200350 return dso;
351}
Adrian Hunter51682dc2014-07-22 16:17:57 +0300352
353bool dso__is_vdso(struct dso *dso)
354{
Adrian Hunterf6832e172014-10-23 13:45:23 +0300355 return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
356 !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
357 !strcmp(dso->short_name, DSO__NAME_VDSOX32);
Adrian Hunter51682dc2014-07-22 16:17:57 +0300358}