Deleted Added
full compact
linux_emul.c (293494) linux_emul.c (293528)
1/*-
2 * Copyright (c) 2006 Roman Divacky
3 * Copyright (c) 2013 Dmitry Chagin
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 14 unchanged lines hidden (view full) ---

23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2006 Roman Divacky
3 * Copyright (c) 2013 Dmitry Chagin
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 14 unchanged lines hidden (view full) ---

23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_emul.c 293494 2016-01-09 15:17:34Z dchagin $");
31__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_emul.c 293528 2016-01-09 16:11:09Z dchagin $");
32
32
33#include "opt_compat.h"
34#include "opt_kdtrace.h"
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/imgact.h>
39#include <sys/kernel.h>
40#include <sys/ktr.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/mutex.h>
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/imgact.h>
36#include <sys/kernel.h>
37#include <sys/ktr.h>
38#include <sys/lock.h>
39#include <sys/malloc.h>
40#include <sys/mutex.h>
44#include <sys/sdt.h>
45#include <sys/sx.h>
46#include <sys/proc.h>
47#include <sys/syscallsubr.h>
48#include <sys/sysent.h>
49#include <sys/sysproto.h>
50#include <sys/unistd.h>
51
41#include <sys/sx.h>
42#include <sys/proc.h>
43#include <sys/syscallsubr.h>
44#include <sys/sysent.h>
45#include <sys/sysproto.h>
46#include <sys/unistd.h>
47
52#ifdef COMPAT_LINUX32
53#include <machine/../linux32/linux.h>
54#include <machine/../linux32/linux32_proto.h>
55#else
56#include <machine/../linux/linux.h>
57#include <machine/../linux/linux_proto.h>
58#endif
59
60#include <compat/linux/linux_dtrace.h>
61#include <compat/linux/linux_emul.h>
48#include <compat/linux/linux_emul.h>
62#include <compat/linux/linux_futex.h>
63#include <compat/linux/linux_misc.h>
64#include <compat/linux/linux_util.h>
65
49#include <compat/linux/linux_misc.h>
50#include <compat/linux/linux_util.h>
51
66/**
67 * Special DTrace provider for the linuxulator.
68 *
69 * In this file we define the provider for the entire linuxulator. All
70 * modules (= files of the linuxulator) use it.
71 *
72 * We define a different name depending on the emulated bitsize, see
73 * ../../<ARCH>/linux{,32}/linux.h, e.g.:
74 * native bitsize = linuxulator
75 * amd64, 32bit emulation = linuxulator32
76 */
77LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE);
78
52
79/**
80 * DTrace probes in this module.
81 */
82LIN_SDT_PROBE_DEFINE1(emul, em_find, entry, "struct thread *");
83LIN_SDT_PROBE_DEFINE0(emul, em_find, return);
84LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *",
85 "struct thread *", "int");
86LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread);
87LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork);
88LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec);
89LIN_SDT_PROBE_DEFINE0(emul, proc_init, return);
90LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *");
91LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, entry, "struct thread *");
92LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, futex_failed);
93LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, child_clear_tid_error, "int");
94LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, return);
95LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *",
96 "struct image_params *");
97LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return);
98LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry);
99LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int");
100LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return);
101LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *");
102LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return);
103
104/*
53/*
105 * This returns reference to the emuldata entry (if found)
54 * This returns reference to the thread emuldata entry (if found)
106 *
107 * Hold PROC_LOCK when referencing emuldata from other threads.
108 */
109struct linux_emuldata *
110em_find(struct thread *td)
111{
112 struct linux_emuldata *em;
113
55 *
56 * Hold PROC_LOCK when referencing emuldata from other threads.
57 */
58struct linux_emuldata *
59em_find(struct thread *td)
60{
61 struct linux_emuldata *em;
62
114 LIN_SDT_PROBE1(emul, em_find, entry, td);
115
116 em = td->td_emuldata;
117
63 em = td->td_emuldata;
64
118 LIN_SDT_PROBE1(emul, em_find, return, em);
119
120 return (em);
121}
122
65 return (em);
66}
67
68/*
69 * This returns reference to the proc pemuldata entry (if found)
70 *
71 * Hold PROC_LOCK when referencing proc pemuldata from other threads.
72 * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
73 */
74struct linux_pemuldata *
75pem_find(struct proc *p)
76{
77 struct linux_pemuldata *pem;
78
79 pem = p->p_emuldata;
80
81 return (pem);
82}
83
123void
124linux_proc_init(struct thread *td, struct thread *newtd, int flags)
125{
126 struct linux_emuldata *em;
84void
85linux_proc_init(struct thread *td, struct thread *newtd, int flags)
86{
87 struct linux_emuldata *em;
88 struct linux_pemuldata *pem;
127
89
128 LIN_SDT_PROBE3(emul, proc_init, entry, td, newtd, flags);
129
130 if (newtd != NULL) {
131 /* non-exec call */
132 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
133 em->pdeath_signal = 0;
90 if (newtd != NULL) {
91 /* non-exec call */
92 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
93 em->pdeath_signal = 0;
134 em->flags = 0;
135 em->robust_futexes = NULL;
136 if (flags & LINUX_CLONE_THREAD) {
94 em->robust_futexes = NULL;
95 if (flags & LINUX_CLONE_THREAD) {
137 LIN_SDT_PROBE0(emul, proc_init, create_thread);
138
139 em->em_tid = newtd->td_tid;
140 } else {
96 em->em_tid = newtd->td_tid;
97 } else {
141 LIN_SDT_PROBE0(emul, proc_init, fork);
142
143 em->em_tid = newtd->td_proc->p_pid;
98
99 em->em_tid = newtd->td_proc->p_pid;
100
101 pem = malloc(sizeof(*pem), M_TEMP, M_WAITOK | M_ZERO);
102 sx_init(&pem->pem_sx, "lpemlk");
103 newtd->td_proc->p_emuldata = pem;
144 }
145 newtd->td_emuldata = em;
146 } else {
147 /* exec */
104 }
105 newtd->td_emuldata = em;
106 } else {
107 /* exec */
148 LIN_SDT_PROBE0(emul, proc_init, exec);
149
150 /* lookup the old one */
151 em = em_find(td);
152 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
153
154 em->em_tid = td->td_proc->p_pid;
155 }
156
157 em->child_clear_tid = NULL;
158 em->child_set_tid = NULL;
108
109 /* lookup the old one */
110 em = em_find(td);
111 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
112
113 em->em_tid = td->td_proc->p_pid;
114 }
115
116 em->child_clear_tid = NULL;
117 em->child_set_tid = NULL;
159
160 LIN_SDT_PROBE0(emul, proc_init, return);
161}
162
163void
164linux_proc_exit(void *arg __unused, struct proc *p)
165{
118}
119
120void
121linux_proc_exit(void *arg __unused, struct proc *p)
122{
123 struct linux_pemuldata *pem;
166 struct thread *td = curthread;
167
124 struct thread *td = curthread;
125
168 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) {
169 LIN_SDT_PROBE1(emul, proc_exit, entry, p);
170 (p->p_sysent->sv_thread_detach)(td);
171 }
126 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
127 return;
128
129 pem = pem_find(p);
130 if (pem == NULL)
131 return;
132 (p->p_sysent->sv_thread_detach)(td);
133
134 p->p_emuldata = NULL;
135
136 sx_destroy(&pem->pem_sx);
137 free(pem, M_TEMP);
172}
173
174int
175linux_common_execve(struct thread *td, struct image_args *eargs)
176{
138}
139
140int
141linux_common_execve(struct thread *td, struct image_args *eargs)
142{
143 struct linux_pemuldata *pem;
177 struct linux_emuldata *em;
178 struct proc *p;
179 int error;
180
181 p = td->td_proc;
182
183 /*
184 * Unlike FreeBSD abort all other threads before

--- 10 unchanged lines hidden (view full) ---

195 PROC_UNLOCK(p);
196
197 error = kern_execve(td, eargs, NULL);
198 if (error != 0)
199 return (error);
200
201 /*
202 * In a case of transition from Linux binary execing to
144 struct linux_emuldata *em;
145 struct proc *p;
146 int error;
147
148 p = td->td_proc;
149
150 /*
151 * Unlike FreeBSD abort all other threads before

--- 10 unchanged lines hidden (view full) ---

162 PROC_UNLOCK(p);
163
164 error = kern_execve(td, eargs, NULL);
165 if (error != 0)
166 return (error);
167
168 /*
169 * In a case of transition from Linux binary execing to
203 * FreeBSD binary we destroy linux emuldata thread entry.
170 * FreeBSD binary we destroy linux emuldata thread & proc entries.
204 */
205 if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
206 PROC_LOCK(p);
207 em = em_find(td);
171 */
172 if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
173 PROC_LOCK(p);
174 em = em_find(td);
208 KASSERT(em != NULL, ("proc_exec: emuldata not found.\n"));
175 KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
209 td->td_emuldata = NULL;
176 td->td_emuldata = NULL;
177
178 pem = pem_find(p);
179 KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
180 p->p_emuldata = NULL;
210 PROC_UNLOCK(p);
211
212 free(em, M_TEMP);
181 PROC_UNLOCK(p);
182
183 free(em, M_TEMP);
184 free(pem, M_TEMP);
213 }
214 return (0);
215}
216
217void
218linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
219{
220 struct thread *td = curthread;
221
222 /*
223 * In a case of execing to linux binary we create linux
224 * emuldata thread entry.
225 */
226 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
227 SV_ABI_LINUX)) {
185 }
186 return (0);
187}
188
189void
190linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
191{
192 struct thread *td = curthread;
193
194 /*
195 * In a case of execing to linux binary we create linux
196 * emuldata thread entry.
197 */
198 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
199 SV_ABI_LINUX)) {
228 LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp);
229 if (SV_PROC_ABI(p) == SV_ABI_LINUX)
230 linux_proc_init(td, NULL, 0);
231 else
232 linux_proc_init(td, td, 0);
200 if (SV_PROC_ABI(p) == SV_ABI_LINUX)
201 linux_proc_init(td, NULL, 0);
202 else
203 linux_proc_init(td, td, 0);
233
234 LIN_SDT_PROBE0(emul, proc_exec, return);
235 }
236}
237
238void
204 }
205}
206
207void
239linux_thread_detach(struct thread *td)
240{
241 struct linux_sys_futex_args cup;
242 struct linux_emuldata *em;
243 int *child_clear_tid;
244 int null = 0;
245 int error;
246
247 LIN_SDT_PROBE1(emul, linux_thread_detach, entry, td);
248
249 em = em_find(td);
250 KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
251
252 LINUX_CTR1(exit, "thread detach(%d)", em->em_tid);
253
254 release_futexes(td, em);
255
256 child_clear_tid = em->child_clear_tid;
257
258 if (child_clear_tid != NULL) {
259
260 LINUX_CTR2(exit, "thread detach(%d) %p",
261 em->em_tid, child_clear_tid);
262
263 error = copyout(&null, child_clear_tid, sizeof(null));
264 if (error) {
265 LIN_SDT_PROBE1(emul, linux_thread_detach,
266 child_clear_tid_error, error);
267
268 LIN_SDT_PROBE0(emul, linux_thread_detach, return);
269 return;
270 }
271
272 cup.uaddr = child_clear_tid;
273 cup.op = LINUX_FUTEX_WAKE;
274 cup.val = 1; /* wake one */
275 cup.timeout = NULL;
276 cup.uaddr2 = NULL;
277 cup.val3 = 0;
278 error = linux_sys_futex(td, &cup);
279 /*
280 * this cannot happen at the moment and if this happens it
281 * probably means there is a user space bug
282 */
283 if (error) {
284 LIN_SDT_PROBE0(emul, linux_thread_detach, futex_failed);
285 printf(LMSG("futex stuff in thread_detach failed.\n"));
286 }
287 }
288
289 LIN_SDT_PROBE0(emul, linux_thread_detach, return);
290}
291
292void
293linux_thread_dtor(void *arg __unused, struct thread *td)
294{
295 struct linux_emuldata *em;
296
297 em = em_find(td);
298 if (em == NULL)
299 return;
300 td->td_emuldata = NULL;

--- 6 unchanged lines hidden (view full) ---

307void
308linux_schedtail(struct thread *td)
309{
310 struct linux_emuldata *em;
311 struct proc *p;
312 int error = 0;
313 int *child_set_tid;
314
208linux_thread_dtor(void *arg __unused, struct thread *td)
209{
210 struct linux_emuldata *em;
211
212 em = em_find(td);
213 if (em == NULL)
214 return;
215 td->td_emuldata = NULL;

--- 6 unchanged lines hidden (view full) ---

222void
223linux_schedtail(struct thread *td)
224{
225 struct linux_emuldata *em;
226 struct proc *p;
227 int error = 0;
228 int *child_set_tid;
229
315 LIN_SDT_PROBE1(emul, linux_schedtail, entry, td);
316
317 p = td->td_proc;
318
319 em = em_find(td);
230 p = td->td_proc;
231
232 em = em_find(td);
320 KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n"));
233 KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
321 child_set_tid = em->child_set_tid;
322
323 if (child_set_tid != NULL) {
324 error = copyout(&em->em_tid, (int *)child_set_tid,
325 sizeof(em->em_tid));
326 LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d",
327 td->td_tid, child_set_tid, em->em_tid, error);
234 child_set_tid = em->child_set_tid;
235
236 if (child_set_tid != NULL) {
237 error = copyout(&em->em_tid, (int *)child_set_tid,
238 sizeof(em->em_tid));
239 LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d",
240 td->td_tid, child_set_tid, em->em_tid, error);
328
329 if (error != 0) {
330 LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error,
331 error);
332 }
333 } else
334 LINUX_CTR1(clone, "schedtail(%d)", em->em_tid);
241 } else
242 LINUX_CTR1(clone, "schedtail(%d)", em->em_tid);
335
336 LIN_SDT_PROBE0(emul, linux_schedtail, return);
337}
243}
338
339int
340linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
341{
342 struct linux_emuldata *em;
343
344 LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr);
345
346 em = em_find(td);
347 KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
348
349 em->child_clear_tid = args->tidptr;
350
351 td->td_retval[0] = em->em_tid;
352
353 LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
354 em->em_tid, args->tidptr, td->td_retval[0]);
355
356 LIN_SDT_PROBE0(emul, linux_set_tid_address, return);
357 return (0);
358}