]> Zhao Yanbai Git Server - minix.git/commitdiff
ptrace(2) modifications:
authorDavid van Moolenbroek <david@minix3.org>
Tue, 29 Dec 2009 21:32:15 +0000 (21:32 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Tue, 29 Dec 2009 21:32:15 +0000 (21:32 +0000)
- add T_GETRANGE/T_SETRANGE to get/set ranges of values
- change EIO error code to EFAULT
- move common-I&D text-to-data translation to umap_local

include/sys/ptrace.h
kernel/arch/i386/memory.c
kernel/system/do_trace.c
man/man2/ptrace.2
servers/pm/trace.c

index e9694dd9eaa3d637fa589c9c74cc805cfac519b1..4c84753749b21ddea6d8f7d2ba9695e9e95d5daf 100644 (file)
@@ -21,6 +21,8 @@
 #define T_ATTACH       11      /* attach to a running process */
 #define T_DETACH       12      /* detach from a traced process */
 #define T_SETOPT       13      /* set trace options */
+#define T_GETRANGE     14      /* get range of values */
+#define T_SETRANGE     15      /* set range of values */
 
 #define T_READB_INS    100     /* Read a byte from the text segment of an
                                 * untraced process (only for root)
 #define TO_TRACEFORK   0x1     /* automatically attach to forked children */
 #define TO_ALTEXEC     0x2     /* send SIGSTOP on successful exec() */
 
+/* Trace spaces. */
+#define TS_INS         0       /* text space */
+#define TS_DATA                1       /* data space */
+
+/* Trance range structure. */
+struct ptrace_range {
+  int pr_space;                        /* space in traced process */
+  long pr_addr;                        /* address in traced process */
+  void *pr_ptr;                        /* buffer in caller process */
+  size_t pr_size;              /* size of range, in bytes */
+};
+
 /* Function Prototypes. */
 #ifndef _ANSI_H
 #include <ansi.h>
index 53c2ce4c72d95fa65d169b9294dec59533ceb2d1..330cb9338028be42a1b0e24b4a0ea58fb082b6a6 100644 (file)
@@ -397,6 +397,8 @@ vir_bytes bytes;                /* # of bytes to be copied */
  
   if (seg != T)
         seg = (vc < rp->p_memmap[D].mem_vir + rp->p_memmap[D].mem_len ? D : S);
+  else if (rp->p_memmap[T].mem_len == 0)       /* common I&D? */
+        seg = D;                               /* ptrace needs this */
  
   if ((vir_addr>>CLICK_SHIFT) >= rp->p_memmap[seg].mem_vir +
         rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
index 96910f209dbd3043f8c64506d31c177a1a116575..e785183b93200ce3911a7ee3d4bd5510231c4438 100644 (file)
@@ -16,8 +16,6 @@
 /*==========================================================================*
  *                             do_trace                                    *
  *==========================================================================*/
-#define TR_VLSIZE      ((vir_bytes) sizeof(long))
-
 PUBLIC int do_trace(m_ptr)
 register message *m_ptr;
 {
@@ -28,16 +26,22 @@ register message *m_ptr;
  * T_GETINS    return value from instruction space
  * T_GETDATA   return value from data space
  * T_GETUSER   return value from user process table
- * T_SETINS    set value from instruction space
- * T_SETDATA   set value from data space
+ * T_SETINS    set value in instruction space
+ * T_SETDATA   set value in data space
  * T_SETUSER   set value in user process table
  * T_RESUME    resume execution
  * T_EXIT      exit
  * T_STEP      set trace bit
  * T_SYSCALL   trace system call
+ * T_ATTACH    attach to an existing process
+ * T_DETACH    detach from a traced process
+ * T_SETOPT    set trace options
+ * T_GETRANGE  get range of values
+ * T_SETRANGE  set range of values
  *
- * The T_OK and T_EXIT commands are handled completely by the process manager,
- * all others come here.
+ * The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled completely by
+ * the process manager. T_GETRANGE and T_SETRANGE use sys_vircopy(). All others
+ * come here.
  */
 
   register struct proc *rp;
@@ -91,12 +95,9 @@ register message *m_ptr;
        return(OK);
 
   case T_GETINS:               /* return value from instruction space */
-       if (rp->p_memmap[T].mem_len != 0) {
-               COPYFROMPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
-               m_ptr->CTL_DATA = tr_data;
-               break;
-       }
-       /* Text space is actually data space - fall through. */
+       COPYFROMPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+       m_ptr->CTL_DATA = tr_data;
+       break;
 
   case T_GETDATA:              /* return value from data space */
        COPYFROMPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long));
@@ -104,7 +105,7 @@ register message *m_ptr;
        break;
 
   case T_GETUSER:              /* return value from process table */
-       if ((tr_addr & (sizeof(long) - 1)) != 0) return(EIO);
+       if ((tr_addr & (sizeof(long) - 1)) != 0) return(EFAULT);
 
        if (tr_addr <= sizeof(struct proc) - sizeof(long)) {
                m_ptr->CTL_DATA = *(long *) ((char *) rp + (int) tr_addr);
@@ -117,18 +118,15 @@ register message *m_ptr;
        i = sizeof(long) - 1;
        tr_addr -= (sizeof(struct proc) + i) & ~i;
 
-       if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EIO);
+       if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EFAULT);
 
        m_ptr->CTL_DATA = *(long *) ((char *) rp->p_priv + (int) tr_addr);
        break;
 
   case T_SETINS:               /* set value in instruction space */
-       if (rp->p_memmap[T].mem_len != 0) {
-               COPYTOPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
-               m_ptr->CTL_DATA = 0;
-               break;
-       }
-       /* Text space is actually data space - fall through. */
+       COPYTOPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+       m_ptr->CTL_DATA = 0;
+       break;
 
   case T_SETDATA:                      /* set value in data space */
        COPYTOPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long));
@@ -138,7 +136,7 @@ register message *m_ptr;
   case T_SETUSER:                      /* set value in process table */
        if ((tr_addr & (sizeof(reg_t) - 1)) != 0 ||
             tr_addr > sizeof(struct stackframe_s) - sizeof(reg_t))
-               return(EIO);
+               return(EFAULT);
        i = (int) tr_addr;
 #if (_MINIX_CHIP == _CHIP_INTEL)
        /* Altering segment registers might crash the kernel when it
@@ -153,7 +151,7 @@ register message *m_ptr;
            i == (int) &((struct proc *) 0)->p_reg.fs ||
 #endif
            i == (int) &((struct proc *) 0)->p_reg.ss)
-               return(EIO);
+               return(EFAULT);
 #endif
        if (i == (int) &((struct proc *) 0)->p_reg.psw)
                /* only selected bits are changeable */
@@ -185,12 +183,13 @@ register message *m_ptr;
        break;
 
   case T_READB_INS:            /* get value from instruction space */
-       COPYFROMPROC(rp->p_memmap[T].mem_len > 0 ? T : D, tr_addr, (vir_bytes) &ub, 1);
+       COPYFROMPROC(T, tr_addr, (vir_bytes) &ub, 1);
        m_ptr->CTL_DATA = ub;
        break;
 
   case T_WRITEB_INS:           /* set value in instruction space */
-       COPYTOPROC(rp->p_memmap[T].mem_len > 0 ? T : D,tr_addr, (vir_bytes) &tr_data, 1);
+       ub = (unsigned char) (tr_data & 0xff);
+       COPYTOPROC(T, tr_addr, (vir_bytes) &ub, 1);
        m_ptr->CTL_DATA = 0;
        break;
 
index b4b3766c39b35599cc095fb6f05fdff7035baee8..05f085c89c750cb9a6b63e7a9f136b5560b39908 100644 (file)
@@ -94,6 +94,16 @@ interpreted as an additional signal to pass to the process.
 .B T_SETOPT
 Set the given process's trace options to the bit combination of flags given
 in the \fIdata\fP argument.
+.TP
+.B T_GETRANGE
+Get a range of values from the address space of the traced process. The
+\fIaddr\fP argument must be a pointer to a fully initialized
+\fBstruct ptrace_range\fP structure.
+.TP
+.B T_SETRANGE
+Set a range of values in the address space of the traced process. The
+\fIaddr\fP argument must be a pointer to a fully initialized
+\fBstruct ptrace_range\fP structure.
 .PP
 The following option flags are currently supported for \fBT_SETOPT\fP:
 .TP 2
@@ -108,22 +118,56 @@ Send \fBSIGSTOP\fP instead of \fBSIGTRAP\fP upon a successful
 .BR execve (2).
 This allows the tracer to disambiguate between this case and other traps.
 .PP
-All addresses specified for the \fBT_GET\fP* and \fBT_SET\fP* requests must be
+The \fBT_GETRANGE\fP and \fBT_SETRANGE\fP calls use the following structure:
+.PP
+.RS
+.nf
+.ft B
+.ta +4n +8n
+struct ptrace_range {
+       int     pr_space;
+       long    pr_addr;
+       size_t  pr_size;
+       void    *pr_ptr;
+};
+.RE
+.PP
+The \fBpr_space\fP field specifies the address space from which to retrieve
+or set the values. It must be set to either of the following values:
+.PP
+.TP 10
+.B TS_INS
+Text space.
+.TP
+.B TS_DATA
+Data space.
+.PP
+The \fBpr_addr\fP field specifies the start address of the target area in the
+traced process. The \fBpr_size\fP field specifies the number of bytes to
+retrieve or set, and must be between 1 and LONG_MAX. The \fBpr_ptr\fP field
+must point to a buffer in the calling process that is used to store the
+retrieved values (for \fBT_GETRANGE\fP) or contains the values to set (for
+\fBT_SETRANGE\fP).
+.PP
+All addresses specified for the \fBT_GETINS\fP, \fBT_GETDATA\fP,
+\fBT_GETUSER\fP requests and their \fBT_SET\fP* counterparts must be
 aligned on \fBlong\fP boundary. Similarly, only \fBlong\fP sized values can be
 retrieved and set at a time.
 .SH "RETURN VALUE"
-All but the \fBT_GET\fP* requests return 0 upon successful completion.
+All but the \fBT_GETINS\fP, \fBT_GETDATA\fP, \fBT_GETUSER\fP requests return 0
+upon successful completion.
 Otherwise, a value of -1 is returned and \fIerrno\fP is set to indicate the
 error.
 .PP
-The \fBT_GET\fP* requests return the resulting data. Here, -1 is a legitimate
-return value. To distinguish between this and an error, clear \fIerrno\fP
+The \fBT_GETINS\fP, \fBT_GETDATA\fP, \fBT_GETUSER\fP requests return the
+resulting data. Here, -1 is a legitimate return value.
+To distinguish between this and an error, clear \fIerrno\fP
 before the \fBptrace\fP call, and check whether it is zero afterwards.
 .SH ERRORS
 The functions will fail if any of the following errors occur:
 .TP 10
 .B EINVAL
-Invalid request or signal given.
+Invalid request, signal, space, or length given.
 .TP 10
 .B ESRCH
 The given process is not found, exiting, or not traced by the caller.
@@ -131,8 +175,8 @@ The given process is not found, exiting, or not traced by the caller.
 .B EBUSY
 The given process is not stopped, or already being traced.
 .TP 10
-.B EIO
-The given address is out of range or not properly aligned.
+.B EFAULT
+The given address is invalid, inaccessible, or not properly aligned.
 .TP 10
 .B EPERM
 Attaching is denied, because the caller equals the given process,
index 8b833bd75ec1bb338065a6a4fe773fa8e988876e..d706c9b98cab1a9ad84d65a7211ddb8e68c6362c 100644 (file)
@@ -18,6 +18,8 @@
  * T_ATTACH    attach to an existing process
  * T_DETACH    detach from a traced process
  * T_SETOPT    set trace options
+ * T_GETRANGE  get range of values
+ * T_SETRANGE  set range of values
  * 
  * The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled here, and the
  * T_RESUME, T_STEP, T_SYSCALL, and T_DETACH commands are partially handled
@@ -38,7 +40,8 @@
 PUBLIC int do_trace()
 {
   register struct mproc *child;
-  int i, r, req;
+  struct ptrace_range pr;
+  int i, r, seg, req;
 
   req = m_in.request;
 
@@ -155,6 +158,30 @@ PUBLIC int do_trace()
        mp->mp_reply.reply_trace = 0;
        return(OK);
 
+  case T_GETRANGE:
+  case T_SETRANGE:     /* get/set range of values */
+       r = sys_datacopy(who_e, (vir_bytes) m_in.PMTRACE_ADDR,
+                       SELF, (vir_bytes) &pr, (phys_bytes) sizeof(pr));
+       if (r != OK) return(r);
+
+       if (pr.pr_space != TS_INS && pr.pr_space != TS_DATA) return(EINVAL);
+       if (pr.pr_size == 0 || pr.pr_size > LONG_MAX) return(EINVAL);
+
+       seg = (pr.pr_space == TS_INS) ? T : D;
+       if (req == T_GETRANGE)
+               r = sys_vircopy(child->mp_endpoint, seg, (vir_bytes) pr.pr_addr,
+                       who_e, D, (vir_bytes) pr.pr_ptr,
+                       (phys_bytes) pr.pr_size);
+       else
+               r = sys_vircopy(who_e, D, (vir_bytes) pr.pr_ptr,
+                       child->mp_endpoint, seg, (vir_bytes) pr.pr_addr,
+                       (phys_bytes) pr.pr_size);
+
+       if (r != OK) return(r);
+
+       mp->mp_reply.reply_trace = 0;
+       return(OK);
+
   case T_DETACH:       /* detach from traced process */
        if (m_in.data < 0 || m_in.data >= _NSIG) return(EINVAL);