1 // SPDX-License-Identifier: GPL-2.0
10 #include <linux/kernel.h>
14 #include <internal/lib.h>
19 #include "linux/string.h"
20 #include <linux/zalloc.h>
24 * Include definition of find_map() also used in perf-read-vdso.c for
25 * building perf-read-vdso32 and perf-read-vdsox32.
29 #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
34 char temp_file_name
[sizeof(VDSO__TEMP_FILE_NAME
)];
36 const char *read_prog
;
40 struct vdso_file vdso
;
41 #if BITS_PER_LONG == 64
42 struct vdso_file vdso32
;
43 struct vdso_file vdsox32
;
47 static struct vdso_info
*vdso_info__new(void)
49 static const struct vdso_info vdso_info_init
= {
51 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
52 .dso_name
= DSO__NAME_VDSO
,
54 #if BITS_PER_LONG == 64
56 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
57 .dso_name
= DSO__NAME_VDSO32
,
58 .read_prog
= "perf-read-vdso32",
61 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
62 .dso_name
= DSO__NAME_VDSOX32
,
63 .read_prog
= "perf-read-vdsox32",
68 return memdup(&vdso_info_init
, sizeof(vdso_info_init
));
71 static char *get_file(struct vdso_file
*vdso_file
)
80 return vdso_file
->temp_file_name
;
82 if (vdso_file
->error
|| find_map(&start
, &end
, VDSO__MAP_NAME
))
87 buf
= memdup(start
, size
);
91 fd
= mkstemp(vdso_file
->temp_file_name
);
95 if (size
== (size_t) write(fd
, buf
, size
))
96 vdso
= vdso_file
->temp_file_name
;
103 vdso_file
->found
= (vdso
!= NULL
);
104 vdso_file
->error
= !vdso_file
->found
;
108 void machine__exit_vdso(struct machine
*machine
)
110 struct vdso_info
*vdso_info
= machine
->vdso_info
;
115 if (vdso_info
->vdso
.found
)
116 unlink(vdso_info
->vdso
.temp_file_name
);
117 #if BITS_PER_LONG == 64
118 if (vdso_info
->vdso32
.found
)
119 unlink(vdso_info
->vdso32
.temp_file_name
);
120 if (vdso_info
->vdsox32
.found
)
121 unlink(vdso_info
->vdsox32
.temp_file_name
);
124 zfree(&machine
->vdso_info
);
127 static struct dso
*__machine__addnew_vdso(struct machine
*machine
, const char *short_name
,
128 const char *long_name
)
132 dso
= dso__new(short_name
);
134 __dsos__add(&machine
->dsos
, dso
);
135 dso__set_long_name(dso
, long_name
, false);
141 struct machine__thread_dso_type_maps_cb_args
{
142 struct machine
*machine
;
143 enum dso_type dso_type
;
146 static int machine__thread_dso_type_maps_cb(struct map
*map
, void *data
)
148 struct machine__thread_dso_type_maps_cb_args
*args
= data
;
149 struct dso
*dso
= map__dso(map
);
151 if (!dso
|| dso__long_name(dso
)[0] != '/')
154 args
->dso_type
= dso__type(dso
, args
->machine
);
155 return (args
->dso_type
!= DSO__TYPE_UNKNOWN
) ? 1 : 0;
158 static enum dso_type
machine__thread_dso_type(struct machine
*machine
,
159 struct thread
*thread
)
161 struct machine__thread_dso_type_maps_cb_args args
= {
163 .dso_type
= DSO__TYPE_UNKNOWN
,
166 maps__for_each_map(thread__maps(thread
), machine__thread_dso_type_maps_cb
, &args
);
168 return args
.dso_type
;
171 #if BITS_PER_LONG == 64
173 static int vdso__do_copy_compat(FILE *f
, int fd
)
179 count
= fread(buf
, 1, sizeof(buf
), f
);
184 if (count
&& writen(fd
, buf
, count
) != (ssize_t
)count
)
191 static int vdso__copy_compat(const char *prog
, int fd
)
196 f
= popen(prog
, "r");
200 err
= vdso__do_copy_compat(f
, fd
);
208 static int vdso__create_compat_file(const char *prog
, char *temp_name
)
212 fd
= mkstemp(temp_name
);
216 err
= vdso__copy_compat(prog
, fd
);
224 static const char *vdso__get_compat_file(struct vdso_file
*vdso_file
)
228 if (vdso_file
->found
)
229 return vdso_file
->temp_file_name
;
231 if (vdso_file
->error
)
234 err
= vdso__create_compat_file(vdso_file
->read_prog
,
235 vdso_file
->temp_file_name
);
237 pr_err("%s failed, error %d\n", vdso_file
->read_prog
, err
);
238 vdso_file
->error
= true;
242 vdso_file
->found
= true;
244 return vdso_file
->temp_file_name
;
247 static struct dso
*__machine__findnew_compat(struct machine
*machine
,
248 struct vdso_file
*vdso_file
)
250 const char *file_name
;
253 dso
= dsos__find(&machine
->dsos
, vdso_file
->dso_name
, true);
257 file_name
= vdso__get_compat_file(vdso_file
);
261 return __machine__addnew_vdso(machine
, vdso_file
->dso_name
, file_name
);
264 static int __machine__findnew_vdso_compat(struct machine
*machine
,
265 struct thread
*thread
,
266 struct vdso_info
*vdso_info
,
269 enum dso_type dso_type
;
271 dso_type
= machine__thread_dso_type(machine
, thread
);
273 #ifndef HAVE_PERF_READ_VDSO32
274 if (dso_type
== DSO__TYPE_32BIT
)
277 #ifndef HAVE_PERF_READ_VDSOX32
278 if (dso_type
== DSO__TYPE_X32BIT
)
283 case DSO__TYPE_32BIT
:
284 *dso
= __machine__findnew_compat(machine
, &vdso_info
->vdso32
);
286 case DSO__TYPE_X32BIT
:
287 *dso
= __machine__findnew_compat(machine
, &vdso_info
->vdsox32
);
289 case DSO__TYPE_UNKNOWN
:
290 case DSO__TYPE_64BIT
:
298 static struct dso
*machine__find_vdso(struct machine
*machine
,
299 struct thread
*thread
)
301 struct dso
*dso
= NULL
;
302 enum dso_type dso_type
;
304 dso_type
= machine__thread_dso_type(machine
, thread
);
306 case DSO__TYPE_32BIT
:
307 dso
= dsos__find(&machine
->dsos
, DSO__NAME_VDSO32
, true);
309 dso
= dsos__find(&machine
->dsos
, DSO__NAME_VDSO
,
311 if (dso
&& dso_type
!= dso__type(dso
, machine
)) {
317 case DSO__TYPE_X32BIT
:
318 dso
= dsos__find(&machine
->dsos
, DSO__NAME_VDSOX32
, true);
320 case DSO__TYPE_64BIT
:
321 case DSO__TYPE_UNKNOWN
:
323 dso
= dsos__find(&machine
->dsos
, DSO__NAME_VDSO
, true);
330 struct dso
*machine__findnew_vdso(struct machine
*machine
,
331 struct thread
*thread
)
333 struct vdso_info
*vdso_info
;
334 struct dso
*dso
= NULL
;
337 if (!machine
->vdso_info
)
338 machine
->vdso_info
= vdso_info__new();
340 vdso_info
= machine
->vdso_info
;
344 dso
= machine__find_vdso(machine
, thread
);
348 #if BITS_PER_LONG == 64
349 if (__machine__findnew_vdso_compat(machine
, thread
, vdso_info
, &dso
))
353 dso
= dsos__find(&machine
->dsos
, DSO__NAME_VDSO
, true);
357 file
= get_file(&vdso_info
->vdso
);
361 return __machine__addnew_vdso(machine
, DSO__NAME_VDSO
, file
);
364 bool dso__is_vdso(struct dso
*dso
)
366 return !strcmp(dso__short_name(dso
), DSO__NAME_VDSO
) ||
367 !strcmp(dso__short_name(dso
), DSO__NAME_VDSO32
) ||
368 !strcmp(dso__short_name(dso
), DSO__NAME_VDSOX32
);