]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/linux/linux_ptrace.c
Fix mac_veriexec_parser build after r347938
[FreeBSD/FreeBSD.git] / sys / i386 / linux / linux_ptrace.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Alexander Kabaev
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_cpu.h"
33
34 #include <sys/param.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/syscallsubr.h>
40 #include <sys/systm.h>
41
42 #include <machine/md_var.h>
43 #include <machine/pcb.h>
44 #include <machine/reg.h>
45
46 #include <i386/linux/linux.h>
47 #include <i386/linux/linux_proto.h>
48 #include <compat/linux/linux_signal.h>
49
50 /*
51  *   Linux ptrace requests numbers. Mostly identical to FreeBSD,
52  *   except for MD ones and PT_ATTACH/PT_DETACH.
53  */
54 #define PTRACE_TRACEME          0
55 #define PTRACE_PEEKTEXT         1
56 #define PTRACE_PEEKDATA         2
57 #define PTRACE_PEEKUSR          3
58 #define PTRACE_POKETEXT         4
59 #define PTRACE_POKEDATA         5
60 #define PTRACE_POKEUSR          6
61 #define PTRACE_CONT             7
62 #define PTRACE_KILL             8
63 #define PTRACE_SINGLESTEP       9
64
65 #define PTRACE_ATTACH           16
66 #define PTRACE_DETACH           17
67
68 #define LINUX_PTRACE_SYSCALL    24
69
70 #define PTRACE_GETREGS          12
71 #define PTRACE_SETREGS          13
72 #define PTRACE_GETFPREGS        14
73 #define PTRACE_SETFPREGS        15
74 #define PTRACE_GETFPXREGS       18
75 #define PTRACE_SETFPXREGS       19
76
77 #define PTRACE_SETOPTIONS       21
78
79 /*
80  * Linux keeps debug registers at the following
81  * offset in the user struct
82  */
83 #define LINUX_DBREG_OFFSET      252
84 #define LINUX_DBREG_SIZE        (8*sizeof(l_int))
85
86 static __inline int
87 map_signum(int signum)
88 {
89
90         signum = linux_to_bsd_signal(signum);
91         return ((signum == SIGSTOP)? 0 : signum);
92 }
93
94 struct linux_pt_reg {
95         l_long  ebx;
96         l_long  ecx;
97         l_long  edx;
98         l_long  esi;
99         l_long  edi;
100         l_long  ebp;
101         l_long  eax;
102         l_int   xds;
103         l_int   xes;
104         l_int   xfs;
105         l_int   xgs;
106         l_long  orig_eax;
107         l_long  eip;
108         l_int   xcs;
109         l_long  eflags;
110         l_long  esp;
111         l_int   xss;
112 };
113
114 /*
115  *   Translate i386 ptrace registers between Linux and FreeBSD formats.
116  *   The translation is pretty straighforward, for all registers, but
117  *   orig_eax on Linux side and r_trapno and r_err in FreeBSD
118  */
119 static void
120 map_regs_to_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
121 {
122         linux_r->ebx = bsd_r->r_ebx;
123         linux_r->ecx = bsd_r->r_ecx;
124         linux_r->edx = bsd_r->r_edx;
125         linux_r->esi = bsd_r->r_esi;
126         linux_r->edi = bsd_r->r_edi;
127         linux_r->ebp = bsd_r->r_ebp;
128         linux_r->eax = bsd_r->r_eax;
129         linux_r->xds = bsd_r->r_ds;
130         linux_r->xes = bsd_r->r_es;
131         linux_r->xfs = bsd_r->r_fs;
132         linux_r->xgs = bsd_r->r_gs;
133         linux_r->orig_eax = bsd_r->r_eax;
134         linux_r->eip = bsd_r->r_eip;
135         linux_r->xcs = bsd_r->r_cs;
136         linux_r->eflags = bsd_r->r_eflags;
137         linux_r->esp = bsd_r->r_esp;
138         linux_r->xss = bsd_r->r_ss;
139 }
140
141 static void
142 map_regs_from_linux(struct reg *bsd_r, struct linux_pt_reg *linux_r)
143 {
144         bsd_r->r_ebx = linux_r->ebx;
145         bsd_r->r_ecx = linux_r->ecx;
146         bsd_r->r_edx = linux_r->edx;
147         bsd_r->r_esi = linux_r->esi;
148         bsd_r->r_edi = linux_r->edi;
149         bsd_r->r_ebp = linux_r->ebp;
150         bsd_r->r_eax = linux_r->eax;
151         bsd_r->r_ds  = linux_r->xds;
152         bsd_r->r_es  = linux_r->xes;
153         bsd_r->r_fs  = linux_r->xfs;
154         bsd_r->r_gs  = linux_r->xgs;
155         bsd_r->r_eip = linux_r->eip;
156         bsd_r->r_cs  = linux_r->xcs;
157         bsd_r->r_eflags = linux_r->eflags;
158         bsd_r->r_esp = linux_r->esp;
159         bsd_r->r_ss = linux_r->xss;
160 }
161
162 struct linux_pt_fpreg {
163         l_long cwd;
164         l_long swd;
165         l_long twd;
166         l_long fip;
167         l_long fcs;
168         l_long foo;
169         l_long fos;
170         l_long st_space[2*10];
171 };
172
173 static void
174 map_fpregs_to_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
175 {
176         linux_r->cwd = bsd_r->fpr_env[0];
177         linux_r->swd = bsd_r->fpr_env[1];
178         linux_r->twd = bsd_r->fpr_env[2];
179         linux_r->fip = bsd_r->fpr_env[3];
180         linux_r->fcs = bsd_r->fpr_env[4];
181         linux_r->foo = bsd_r->fpr_env[5];
182         linux_r->fos = bsd_r->fpr_env[6];
183         bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(linux_r->st_space));
184 }
185
186 static void
187 map_fpregs_from_linux(struct fpreg *bsd_r, struct linux_pt_fpreg *linux_r)
188 {
189         bsd_r->fpr_env[0] = linux_r->cwd;
190         bsd_r->fpr_env[1] = linux_r->swd;
191         bsd_r->fpr_env[2] = linux_r->twd;
192         bsd_r->fpr_env[3] = linux_r->fip;
193         bsd_r->fpr_env[4] = linux_r->fcs;
194         bsd_r->fpr_env[5] = linux_r->foo;
195         bsd_r->fpr_env[6] = linux_r->fos;
196         bcopy(bsd_r->fpr_acc, linux_r->st_space, sizeof(bsd_r->fpr_acc));
197 }
198
199 struct linux_pt_fpxreg {
200         l_ushort        cwd;
201         l_ushort        swd;
202         l_ushort        twd;
203         l_ushort        fop;
204         l_long          fip;
205         l_long          fcs;
206         l_long          foo;
207         l_long          fos;
208         l_long          mxcsr;
209         l_long          reserved;
210         l_long          st_space[32];
211         l_long          xmm_space[32];
212         l_long          padding[56];
213 };
214
215 static int
216 linux_proc_read_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
217 {
218
219         PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
220         if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
221                 return (EIO);
222         bcopy(&get_pcb_user_save_td(td)->sv_xmm, fpxregs, sizeof(*fpxregs));
223         return (0);
224 }
225
226 static int
227 linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
228 {
229
230         PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
231         if (cpu_fxsr == 0 || (td->td_proc->p_flag & P_INMEM) == 0)
232                 return (EIO);
233         bcopy(fpxregs, &get_pcb_user_save_td(td)->sv_xmm, sizeof(*fpxregs));
234         return (0);
235 }
236
237 int
238 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
239 {
240         union {
241                 struct linux_pt_reg     reg;
242                 struct linux_pt_fpreg   fpreg;
243                 struct linux_pt_fpxreg  fpxreg;
244         } r;
245         union {
246                 struct reg              bsd_reg;
247                 struct fpreg            bsd_fpreg;
248                 struct dbreg            bsd_dbreg;
249         } u;
250         void *addr;
251         pid_t pid;
252         int error, req;
253
254         error = 0;
255
256         /* by default, just copy data intact */
257         req  = uap->req;
258         pid  = (pid_t)uap->pid;
259         addr = (void *)uap->addr;
260
261         switch (req) {
262         case PTRACE_TRACEME:
263         case PTRACE_POKETEXT:
264         case PTRACE_POKEDATA:
265         case PTRACE_KILL:
266                 error = kern_ptrace(td, req, pid, addr, uap->data);
267                 break;
268         case PTRACE_PEEKTEXT:
269         case PTRACE_PEEKDATA: {
270                 /* need to preserve return value */
271                 int rval = td->td_retval[0];
272                 error = kern_ptrace(td, req, pid, addr, 0);
273                 if (error == 0)
274                         error = copyout(td->td_retval, (void *)uap->data,
275                             sizeof(l_int));
276                 td->td_retval[0] = rval;
277                 break;
278         }
279         case PTRACE_DETACH:
280                 error = kern_ptrace(td, PT_DETACH, pid, (void *)1,
281                      map_signum(uap->data));
282                 break;
283         case PTRACE_SINGLESTEP:
284         case PTRACE_CONT:
285                 error = kern_ptrace(td, req, pid, (void *)1,
286                      map_signum(uap->data));
287                 break;
288         case PTRACE_ATTACH:
289                 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
290                 break;
291         case PTRACE_GETREGS:
292                 /* Linux is using data where FreeBSD is using addr */
293                 error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
294                 if (error == 0) {
295                         map_regs_to_linux(&u.bsd_reg, &r.reg);
296                         error = copyout(&r.reg, (void *)uap->data,
297                             sizeof(r.reg));
298                 }
299                 break;
300         case PTRACE_SETREGS:
301                 /* Linux is using data where FreeBSD is using addr */
302                 error = copyin((void *)uap->data, &r.reg, sizeof(r.reg));
303                 if (error == 0) {
304                         map_regs_from_linux(&u.bsd_reg, &r.reg);
305                         error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
306                 }
307                 break;
308         case PTRACE_GETFPREGS:
309                 /* Linux is using data where FreeBSD is using addr */
310                 error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0);
311                 if (error == 0) {
312                         map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg);
313                         error = copyout(&r.fpreg, (void *)uap->data,
314                             sizeof(r.fpreg));
315                 }
316                 break;
317         case PTRACE_SETFPREGS:
318                 /* Linux is using data where FreeBSD is using addr */
319                 error = copyin((void *)uap->data, &r.fpreg, sizeof(r.fpreg));
320                 if (error == 0) {
321                         map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg);
322                         error = kern_ptrace(td, PT_SETFPREGS, pid,
323                             &u.bsd_fpreg, 0);
324                 }
325                 break;
326         case PTRACE_SETFPXREGS:
327                 error = copyin((void *)uap->data, &r.fpxreg, sizeof(r.fpxreg));
328                 if (error)
329                         break;
330                 /* FALL THROUGH */
331         case PTRACE_GETFPXREGS: {
332                 struct proc *p;
333                 struct thread *td2;
334
335                 if (sizeof(struct linux_pt_fpxreg) != sizeof(struct savexmm)) {
336                         static int once = 0;
337                         if (!once) {
338                                 printf("linux: savexmm != linux_pt_fpxreg\n");
339                                 once = 1;
340                         }
341                         error = EIO;
342                         break;
343                 }
344
345                 if ((p = pfind(uap->pid)) == NULL) {
346                         error = ESRCH;
347                         break;
348                 }
349
350                 /* Exiting processes can't be debugged. */
351                 if ((p->p_flag & P_WEXIT) != 0) {
352                         error = ESRCH;
353                         goto fail;
354                 }
355
356                 if ((error = p_candebug(td, p)) != 0)
357                         goto fail;
358
359                 /* System processes can't be debugged. */
360                 if ((p->p_flag & P_SYSTEM) != 0) {
361                         error = EINVAL;
362                         goto fail;
363                 }
364
365                 /* not being traced... */
366                 if ((p->p_flag & P_TRACED) == 0) {
367                         error = EPERM;
368                         goto fail;
369                 }
370
371                 /* not being traced by YOU */
372                 if (p->p_pptr != td->td_proc) {
373                         error = EBUSY;
374                         goto fail;
375                 }
376
377                 /* not currently stopped */
378                 if (!P_SHOULDSTOP(p) || (p->p_flag & P_WAITED) == 0) {
379                         error = EBUSY;
380                         goto fail;
381                 }
382
383                 if (req == PTRACE_GETFPXREGS) {
384                         _PHOLD(p);      /* may block */
385                         td2 = FIRST_THREAD_IN_PROC(p);
386                         error = linux_proc_read_fpxregs(td2, &r.fpxreg);
387                         _PRELE(p);
388                         PROC_UNLOCK(p);
389                         if (error == 0)
390                                 error = copyout(&r.fpxreg, (void *)uap->data,
391                                     sizeof(r.fpxreg));
392                 } else {
393                         /* clear dangerous bits exactly as Linux does*/
394                         r.fpxreg.mxcsr &= 0xffbf;
395                         _PHOLD(p);      /* may block */
396                         td2 = FIRST_THREAD_IN_PROC(p);
397                         error = linux_proc_write_fpxregs(td2, &r.fpxreg);
398                         _PRELE(p);
399                         PROC_UNLOCK(p);
400                 }
401                 break;
402
403         fail:
404                 PROC_UNLOCK(p);
405                 break;
406         }
407         case PTRACE_PEEKUSR:
408         case PTRACE_POKEUSR: {
409                 error = EIO;
410
411                 /* check addr for alignment */
412                 if (uap->addr < 0 || uap->addr & (sizeof(l_int) - 1))
413                         break;
414                 /*
415                  * Allow Linux programs to access register values in
416                  * user struct. We simulate this through PT_GET/SETREGS
417                  * as necessary.
418                  */
419                 if (uap->addr < sizeof(struct linux_pt_reg)) {
420                         error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
421                         if (error != 0)
422                                 break;
423
424                         map_regs_to_linux(&u.bsd_reg, &r.reg);
425                         if (req == PTRACE_PEEKUSR) {
426                                 error = copyout((char *)&r.reg + uap->addr,
427                                     (void *)uap->data, sizeof(l_int));
428                                 break;
429                         }
430
431                         *(l_int *)((char *)&r.reg + uap->addr) =
432                             (l_int)uap->data;
433
434                         map_regs_from_linux(&u.bsd_reg, &r.reg);
435                         error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
436                 }
437
438                 /*
439                  * Simulate debug registers access
440                  */
441                 if (uap->addr >= LINUX_DBREG_OFFSET &&
442                     uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
443                         error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg,
444                             0);
445                         if (error != 0)
446                                 break;
447
448                         uap->addr -= LINUX_DBREG_OFFSET;
449                         if (req == PTRACE_PEEKUSR) {
450                                 error = copyout((char *)&u.bsd_dbreg +
451                                     uap->addr, (void *)uap->data,
452                                     sizeof(l_int));
453                                 break;
454                         }
455
456                         *(l_int *)((char *)&u.bsd_dbreg + uap->addr) =
457                              uap->data;
458                         error = kern_ptrace(td, PT_SETDBREGS, pid,
459                             &u.bsd_dbreg, 0);
460                 }
461
462                 break;
463         }
464         case LINUX_PTRACE_SYSCALL:
465                 /* fall through */
466         default:
467                 printf("linux: ptrace(%u, ...) not implemented\n",
468                     (unsigned int)uap->req);
469                 error = EINVAL;
470                 break;
471         }
472
473         return (error);
474 }