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} | |