1 // SPDX-License-Identifier: GPL-2.0
10 #include <linux/kernel.h>
17 #include "linux/string.h"
21 * Include definition of find_vdso_map() also used in perf-read-vdso.c for
22 * building perf-read-vdso32 and perf-read-vdsox32.
24 #include "find-vdso-map.c"
26 #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
31 char temp_file_name
[sizeof(VDSO__TEMP_FILE_NAME
)];
33 const char *read_prog
;
37 struct vdso_file vdso
;
38 #if BITS_PER_LONG == 64
39 struct vdso_file vdso32
;
40 struct vdso_file vdsox32
;
44 static struct vdso_info
*vdso_info__new(void)
46 static const struct vdso_info vdso_info_init
= {
48 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
49 .dso_name
= DSO__NAME_VDSO
,
51 #if BITS_PER_LONG == 64
53 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
54 .dso_name
= DSO__NAME_VDSO32
,
55 .read_prog
= "perf-read-vdso32",
58 .temp_file_name
= VDSO__TEMP_FILE_NAME
,
59 .dso_name
= DSO__NAME_VDSOX32
,
60 .read_prog
= "perf-read-vdsox32",
65 return memdup(&vdso_info_init
, sizeof(vdso_info_init
));
68 static char *get_file(struct vdso_file
*vdso_file
)
77 return vdso_file
->temp_file_name
;
79 if (vdso_file
->error
|| find_vdso_map(&start
, &end
))
84 buf
= memdup(start
, size
);
88 fd
= mkstemp(vdso_file
->temp_file_name
);
92 if (size
== (size_t) write(fd
, buf
, size
))
93 vdso
= vdso_file
->temp_file_name
;
100 vdso_file
->found
= (vdso
!= NULL
);
101 vdso_file
->error
= !vdso_file
->found
;
105 void machine__exit_vdso(struct machine
*machine
)
107 struct vdso_info
*vdso_info
= machine
->vdso_info
;
112 if (vdso_info
->vdso
.found
)
113 unlink(vdso_info
->vdso
.temp_file_name
);
114 #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
);
121 zfree(&machine
->vdso_info
);
124 static struct dso
*__machine__addnew_vdso(struct machine
*machine
, const char *short_name
,
125 const char *long_name
)
129 dso
= dso__new(short_name
);
131 __dsos__add(&machine
->dsos
, dso
);
132 dso__set_long_name(dso
, long_name
, false);
138 static enum dso_type
machine__thread_dso_type(struct machine
*machine
,
139 struct thread
*thread
)
141 enum dso_type dso_type
= DSO__TYPE_UNKNOWN
;
142 struct map
*map
= map_groups__first(thread
->mg
);
144 for (; map
; map
= map_groups__next(map
)) {
145 struct dso
*dso
= map
->dso
;
146 if (!dso
|| dso
->long_name
[0] != '/')
148 dso_type
= dso__type(dso
, machine
);
149 if (dso_type
!= DSO__TYPE_UNKNOWN
)
156 #if BITS_PER_LONG == 64
158 static int vdso__do_copy_compat(FILE *f
, int fd
)
164 count
= fread(buf
, 1, sizeof(buf
), f
);
169 if (count
&& writen(fd
, buf
, count
) != (ssize_t
)count
)
176 static int vdso__copy_compat(const char *prog
, int fd
)
181 f
= popen(prog
, "r");
185 err
= vdso__do_copy_compat(f
, fd
);
193 static int vdso__create_compat_file(const char *prog
, char *temp_name
)
197 fd
= mkstemp(temp_name
);
201 err
= vdso__copy_compat(prog
, fd
);
209 static const char *vdso__get_compat_file(struct vdso_file
*vdso_file
)
213 if (vdso_file
->found
)
214 return vdso_file
->temp_file_name
;
216 if (vdso_file
->error
)
219 err
= vdso__create_compat_file(vdso_file
->read_prog
,
220 vdso_file
->temp_file_name
);
222 pr_err("%s failed, error %d\n", vdso_file
->read_prog
, err
);
223 vdso_file
->error
= true;
227 vdso_file
->found
= true;
229 return vdso_file
->temp_file_name
;
232 static struct dso
*__machine__findnew_compat(struct machine
*machine
,
233 struct vdso_file
*vdso_file
)
235 const char *file_name
;
238 dso
= __dsos__find(&machine
->dsos
, vdso_file
->dso_name
, true);
242 file_name
= vdso__get_compat_file(vdso_file
);
246 dso
= __machine__addnew_vdso(machine
, vdso_file
->dso_name
, file_name
);
251 static int __machine__findnew_vdso_compat(struct machine
*machine
,
252 struct thread
*thread
,
253 struct vdso_info
*vdso_info
,
256 enum dso_type dso_type
;
258 dso_type
= machine__thread_dso_type(machine
, thread
);
260 #ifndef HAVE_PERF_READ_VDSO32
261 if (dso_type
== DSO__TYPE_32BIT
)
264 #ifndef HAVE_PERF_READ_VDSOX32
265 if (dso_type
== DSO__TYPE_X32BIT
)
270 case DSO__TYPE_32BIT
:
271 *dso
= __machine__findnew_compat(machine
, &vdso_info
->vdso32
);
273 case DSO__TYPE_X32BIT
:
274 *dso
= __machine__findnew_compat(machine
, &vdso_info
->vdsox32
);
276 case DSO__TYPE_UNKNOWN
:
277 case DSO__TYPE_64BIT
:
285 static struct dso
*machine__find_vdso(struct machine
*machine
,
286 struct thread
*thread
)
288 struct dso
*dso
= NULL
;
289 enum dso_type dso_type
;
291 dso_type
= machine__thread_dso_type(machine
, thread
);
293 case DSO__TYPE_32BIT
:
294 dso
= __dsos__find(&machine
->dsos
, DSO__NAME_VDSO32
, true);
296 dso
= __dsos__find(&machine
->dsos
, DSO__NAME_VDSO
,
298 if (dso
&& dso_type
!= dso__type(dso
, machine
))
302 case DSO__TYPE_X32BIT
:
303 dso
= __dsos__find(&machine
->dsos
, DSO__NAME_VDSOX32
, true);
305 case DSO__TYPE_64BIT
:
306 case DSO__TYPE_UNKNOWN
:
308 dso
= __dsos__find(&machine
->dsos
, DSO__NAME_VDSO
, true);
315 struct dso
*machine__findnew_vdso(struct machine
*machine
,
316 struct thread
*thread
)
318 struct vdso_info
*vdso_info
;
319 struct dso
*dso
= NULL
;
321 down_write(&machine
->dsos
.lock
);
322 if (!machine
->vdso_info
)
323 machine
->vdso_info
= vdso_info__new();
325 vdso_info
= machine
->vdso_info
;
329 dso
= machine__find_vdso(machine
, thread
);
333 #if BITS_PER_LONG == 64
334 if (__machine__findnew_vdso_compat(machine
, thread
, vdso_info
, &dso
))
338 dso
= __dsos__find(&machine
->dsos
, DSO__NAME_VDSO
, true);
342 file
= get_file(&vdso_info
->vdso
);
344 dso
= __machine__addnew_vdso(machine
, DSO__NAME_VDSO
, file
);
349 up_write(&machine
->dsos
.lock
);
353 bool dso__is_vdso(struct dso
*dso
)
355 return !strcmp(dso
->short_name
, DSO__NAME_VDSO
) ||
356 !strcmp(dso
->short_name
, DSO__NAME_VDSO32
) ||
357 !strcmp(dso
->short_name
, DSO__NAME_VDSOX32
);