The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/emulation/linux/i386/linux_ptrace.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e85335c9668b3f233f3a6bb5dab8d8af


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.