Subject: PT_SYSCALL in NetBSD/sparc
To: None <current-users@netbsd.org>
From: der Mouse <mouse@Collatz.McRCIM.McGill.EDU>
List: current-users
Date: 11/08/1994 11:12:25
Here's my (rather alpha) PT_SYSCALL for NetBSD/sparc.  (This is going
to current-users rather than port-sparc because I want it to be easy to
do similar things for other architectures, and want to make sure I
haven't somehow put something SPARC-specific in a non-SPARC-specific
file.  People using other architectures looking at it strikes me as the
best way to accomplish this.)

This also includes a manpage for ptrace(2).  (I've sent a previous
version of this to core; this version is updated to match the interface
provided by these diffs.)

Comments, flames, fan mail, bug reports, etc, invited.

					der Mouse

			    mouse@collatz.mcrcim.mcgill.edu

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Tue Nov  8 11:09:35 1994
# Run this through sh to create:
#	ptrace.2
#	PT_SYSCALL.diffs
echo x - ptrace.2 \(10914 characters\)
sed 's/^X//' > ptrace.2 << \EOF
X.\" This file is in the public domain.
X.Dd November 7, 1994
X.Dt PTRACE 2
X.Os NetBSD 1.0BETA
X.Sh NAME
X.Nm ptrace
X.Nd process tracing and debugging
X.Sh SYNOPSIS
X.Fd #include <sys/types.h>
X.Fd #include <sys/ptrace.h>
X.Ft int
X.Fn ptrace "int request" "pid_t pid" "caddr_t addr" "int data"
X.Sh DESCRIPTION
X.Fn ptrace
Xprovides tracing and debugging facilities.  It allows one process (the
X.Em tracing
Xprocess) to control another (the
X.Em traced
Xprocess).  Most of the time, the traced process runs normally, but when
Xit receives a signal
X.Po
Xsee
X.Xr sigaction 2
X.Pc ,
Xit stops.  The tracing process is expected to notice this via
X.Xr wait 2
Xor the delivery of a
X.Dv SIGCHLD
Xsignal, examine the state of the stopped process, and cause it to
Xterminate or continue as appropriate.
X.Fn ptrace
Xis the mechanism by which all this happens.
X.Pp
XThe
X.Fa request
Xargument specifies what operation is being performed; the meaning of
Xthe rest of the arguments depends on the operation, but except for one
Xspecial case noted below, all
X.Fn ptrace
Xcalls are made by the tracing process, and the
X.Fa pid
Xargument specifies the process ID of the traced process.
X.Fa request
Xcan be:
X.Bl -tag -width 12n
X.It Dv PT_TRACE_ME
XThis request is the only one used by the traced process; it declares
Xthat the process expects to be traced by its parent.  All the other
Xarguments are ignored.  (If the parent process does not expect to trace
Xthe child, it will probably be rather confused by the results; once the
Xtraced process stops, it cannot be made to continue except via
X.Eo \&
X.Fn ptrace
X.Ec \&.)
XWhen a process has used this request and calls
X.Xr execve 2
Xor any of the routines built on it
X.Po
Xsuch as
X.Xr execv 3
X.Pc ,
Xit will stop before executing the first instruction of the new image.
XAlso, any setuid or setgid bits on the executable being executed will
Xbe ignored.
X.It Dv PT_READ_I , Dv PT_READ_D
XThese requests read a single
X.Li int
Xof data from the traced process' address space.  Traditionally,
X.Fn ptrace
Xhas allowed for machines with distinct address spaces for instruction
Xand data, which is why there are two requests: conceptually,
X.Dv PT_READ_I
Xreads from the instruction space and
X.Dv PT_READ_D
Xreads from the data space.  In the current NetBSD implementation, these
Xtwo requests are completely identical.  The
X.Fa addr
Xargument specifies the address (in the traced process' virtual address
Xspace) at which the read is to be done.  This address does not have to
Xmeet any alignment constraints.  The value read is returned as the
Xreturn value from
X.Eo \&
X.Fn ptrace
X.Ec .
X.It Dv PT_WRITE_I , Dv PT_WRITE_D
XThese requests parallel
X.Dv PT_READ_I
Xand
X.Dv PT_READ_D ,
Xexcept that they write rather than read.  The
X.Fa data
Xargument supplies the value to be written.
X.It Dv PT_READ_U
XThis request reads an
X.Li int
Xfrom the traced process' user structure.  The
X.Fa addr
Xargument specifies the location of the int relative to the base of the
Xuser structure; it will usually be an integer value cast to
X.Li caddr_t
Xeither explicitly or via the presence of a prototype for
X.Eo \&
X.Fn ptrace
X.Ec .
XUnlike
X.Dv PT_READ_I
Xand
X.Dv PT_READ_D ,
X.Fa addr
Xmust be aligned on an
X.Li int
Xboundary.  The value read is returned as the return value from
X.Eo \&
X.Fn ptrace
X.Ec .
X.It Dv PT_WRITE_U
XThis request writes an
X.Li int
Xinto the traced process' user structure.
X.Fa addr
Xspecifies the offset, just as for
X.Dv PT_READ_U ,
Xand
X.Fa data
Xspecifies the value to be written, just as for
X.Dv PT_WRITE_I
Xand
X.Dv PT_WRITE_D .
X.It Dv PT_CONTINUE
XThe traced process continues execution.
X.Fa addr
Xis an address specifying the place where execution is to be resumed (a
Xnew value for the program counter), or
X.Li (caddr_t)1
Xto indicate that execution is to pick up where it left off.
X.Fa data
Xprovides a signal number to be delivered to the traced process as it
Xresumes execution, or 0 if no signal is to be sent.
X.It Dv PT_KILL
XThe traced process terminates, as if
X.Dv PT_CONTINUE
Xhad been used with
X.Dv SIGKILL
Xgiven as the signal to be delivered.
X.It Dv PT_ATTACH
XThis request allows a process to gain control of an otherwise unrelated
Xprocess and begin tracing it.  It does not need any cooperation from
Xthe to-be-traced process.  In this case,
X.Fa pid
Xspecifies the process ID of the to-be-traced process, and the other two
Xarguments are ignored.  This request requires that the target process
Xmust have the same real UID as the tracing process, and that it must
Xnot be executing a setuid or setgid executable.  (If the tracing
Xprocess is running as root, these restrictions do not apply.)  The
Xtracing process will see the newly-traced process stop and may then
Xcontrol it as if it had been traced all along.
X.It Dv PT_DETACH
XThis request is like PT_CONTINUE, except that it does not allow
Xspecifying an alternate place to continue execution, and after it
Xsucceeds, the traced process is no longer traced and continues
Xexecution normally.
X.El
X.Pp
XAdditionally, machine-specific requests can exist.  On the SPARC, these
Xare:
X.Bl -tag -width 12n
X.It Dv PT_GETREGS
XThis request reads the traced process' machine registers into the
X.Dq Li "struct reg"
X(defined in
X.Aq Pa machine/reg.h )
Xpointed to by
X.Fa addr .
X.It Dv PT_SETREGS
XThis request is the converse of
X.Dv PT_GETREGS ;
Xit loads the traced process' machine registers from the
X.Dq Li "struct reg"
X(defined in
X.Aq Pa machine/reg.h )
Xpointed to by
X.Fa addr .
X.It Dv PT_GETFPREGS
XThis request reads the traced process' floating-point registers into
Xthe
X.Dq Li "struct fpreg"
X(defined in
X.Aq Pa machine/reg.h )
Xpointed to by
X.Fa addr .
X.It Dv PT_SETFPREGS
XThis request is the converse of
X.Dv PT_GETFPREGS ;
Xit loads the traced process' floating-point registers from the
X.Dq Li "struct fpreg"
X(defined in
X.Aq Pa machine/reg.h )
Xpointed to by
X.Fa addr .
X.It Dv PT_SYSCALL
XThis request is like
X.Dv PT_CONTINUE
Xexcept that the process will stop next time it executes any system
Xcall.  Information about the system call can be examined with
X.Dv PT_READ_U
Xand potentially modified with
X.Dv PT_WRITE_U
Xthrough the
X.Li u_kproc.kp_proc.p_md.md_syscall
Xelement of the user structure (see below).  If the process is continued
Xwith another
X.Dv PT_SYSCALL
Xrequest, it will stop again on exit from the syscall, at which point
Xthe return values can be examined and potentially changed.  The
X.Li u_kproc.kp_proc.p_md.md_syscall
Xelement is of type
X.Dq Li "struct pt_syscall" ,
Xand the necessary include files for using
X.Dv PT_SYSCALL
Xare
X.Aq Pa sys/param.h ,
X.Aq Pa sys/user.h ,
Xand
X.Aq Pa sys/proc.h .
XThe
X.Dq Li "pt_syscall"
Xstructure contains the following fields:
X.Bl -item -compact -offset indent
X.It
X.Li syscall_compat
X.It
X.Li syscall_num
X.It
X.Li syscall_nargs
X.It
X.Li syscall_args[8]
X.It
X.Li syscall_err
X.It
X.Li syscall_rv[2]
X.El
XWhen a process stops on entry to a syscall,
X.Li syscall_num
Xholds the number of the syscall,
X.Li syscall_nargs
Xholds the number of arguments it expects, and
X.Li syscall_args
Xholds the arguments themselves.  (Only the first
X.Li syscall_nargs
Xelements of
X.Li syscall_args
Xare guaranteed to be useful.)
X.Li syscall_compat
Xholds one of the
X.Eo \&
X.Li EMUL_
X.Ec xxx
Xvalues from
X.Aq Pa sys/proc.h ,
Xdescribing whether the process is a
X.Sq native
XNetBSD process or whether it's taking advantage of other-OS
Xcompatability.  This is relevant to
X.Dv PT_SYSCALL
Xbecause different syscall vectors are used for
X.Sq native
Xand
X.Sq foreign
Xsyscalls.
X.Pp
XWhen a process stops on exit from a syscall,
X.Li syscall_num
Xis
X.Eo \&
X.Li -1
X.Ec ,
X.Li syscall_err
Xholds the error number
X.Po
Xsee
X.Xr errno 2
X.Pc ,
Xor 0 if no error occurred, and
X.Li syscall_rv
Xholds the return values.  (If the syscall returns only one value, only
X.Li syscall_rv[0]
Xis useful.)  The tracing process can modify any of these with
X.Dv PT_WRITE_U ;
Xonly some modifications are useful.
X.Pp
XOn entry to a syscall,
X.Li syscall_num
Xcan be changed, and the syscall actually performed will correspond to
Xthe new number (it is the responsibility of the tracing process to fill
Xin
X.Li syscall_args
Xappropriately for the new call, but there is no need to modify
X.Eo \&
X.Li syscall_nargs
X.Ec ).
X.Li syscall_compat
Xis checked, and
X.Li syscall_num
Xis interpreted relative to the appropriate syscall vector.  (If
X.Li syscall_compat
Xis set to a value not implemented for the machine in use, the effect is
Xas if
X.Li syscall_num
Xwere set to an out-of-range value.)  If the new syscall number is 0, no
Xsyscall is actually performed; instead,
X.Li syscall_err
Xand
X.Li syscall_rv
Xare passed back to the traced process directly (and therefore should be
Xfilled in).  If the syscall number is otherwise out of range, a dummy
Xsyscall which simply produces an
X.Er ENOSYS
Xerror is effectively performed.
X.Pp
XOn exit from a syscall, only
X.Li syscall_err
Xand
X.Li syscall_rv
Xcan usefully be changed; they are set to the values returned by the
Xsyscall and will be passed back to the traced process by the normal
Xsyscall return mechanism.
X.El
X.Sh ERRORS
XSome requests can cause
X.Fn ptrace
Xto return
X.Li -1
Xas a non-error value; to disambiguate,
X.Va errno
Xcan be set to 0 before the call and checked afterwards.  The possible
Xerrors are:
X.Bl -tag -width 4n
X.It Bq Er ESRCH
XNo process having the specified process ID exists.
X.It Bq Er EINVAL
X.Bl -bullet -compact
X.It
XA process attempted to use
X.Dv PT_ATTACH
Xon itself.
X.It
XThe
X.Fa request
Xwas not one of the legal requests.
X.It
XThe
X.Fa addr
Xto
X.Dv PT_READ_U
Xor
X.Dv PT_WRITE_U
Xwas not
X.Li int Ns \&-aligned.
X.It
XThe signal number (in
X.Fa data )
Xto
X.Dv PT_CONTINUE
Xor
X.Dv PT_SYSCALL
Xwas neither 0 nor a legal signal number.
X.It
X.Dv PT_GETREGS ,
X.Dv PT_SETREGS ,
X.Dv PT_GETFPREGS ,
Xor
X.Dv PT_SETFPREGS
Xwas attempted on a process with no valid register set.  (This is
Xnormally true only of system processes.)
X.El
X.It Bq Er EBUSY
X.Bl -bullet -compact
X.It
X.Dv PT_ATTACH
Xwas attempted on a process that was already being traced.
X.It
XA request attempted to manipulate a process that was being traced by
Xsome process other than the one making the request.
X.It
XA request (other than
X.Dv PT_ATTACH )
Xspecified a process that wasn't stopped.
X.El
X.It Bq Er EPERM
X.Bl -bullet -compact
X.It
XA request (other than
X.Dv PT_ATTACH )
Xattempted to manipulate a process that wasn't being traced at all.
X.It
XAn attempt was made to use
X.Dv PT_ATTACH
Xon a process in violation of the requirements listed under
X.Dv PT_ATTACH
Xabove.
X.El
X.Sh BUGS
XOn the SPARC, the PC is set to the provided PC value for
X.Dv PT_CONTINUE
Xand similar calls, but the NPC is set willy-nilly to 4 greater than the
XPC value.  Using
X.Dv PT_GETREGS
Xand
X.Dv PT_SETREGS
Xto modify the PC, passing
X.Li (caddr_t)1
Xto
X.Eo \&
X.Fn ptrace
X.Ec ,
Xshould be able to sidestep this.
X.Pp
XSingle-stepping is not available.
X.Pp
XWhen using
X.Dv PT_SYSCALL ,
Xthere is no easy way to tell whether the traced process stopped because
Xit made a syscall or because it received a
X.Dv SIGTRAP
Xat a moment that it just happened to have valid-looking garbage in its
X.Dq Li "struct mdproc" .
EOF
if test 10914 -ne "`wc -c ptrace.2`"
then
echo shar: error transmitting ptrace.2 \(should have been 10914 characters\)
fi
echo x - PT_SYSCALL.diffs \(11051 characters\)
sed 's/^X//' > PT_SYSCALL.diffs << \EOF
X*** old/./arch/sparc/include/proc.h	Fri Dec 17 01:55:29 1993
X***************
X*** 46,54 ****
X--- 46,67 ----
X   */
X  
X  /*
X+  * Structure for PT_SYSCALL interface.
X+  */
X+ struct pt_syscall {
X+   int syscall_compat;
X+   int syscall_num;
X+   int syscall_nargs;
X+   int syscall_args[8];
X+   int syscall_err;
X+   int syscall_rv[2];
X+   } ;
X+ 
X+ /*
X   * Machine-dependent part of the proc structure for SPARC.
X   */
X  struct mdproc {
X  	struct	trapframe *md_tf;	/* trap/syscall registers */
X  	struct	fpstate *md_fpstate;	/* fpu state, if any; always resident */
X+ 	struct pt_syscall md_syscall;	/* PT_SYSCALL interface */
X  };
X*** old/./arch/sparc/include/ptrace.h	Sat Feb 12 05:17:49 1994
X***************
X*** 52,54 ****
X--- 52,55 ----
X  #define	PT_SETREGS	(PT_FIRSTMACH + 1)
X  #define	PT_GETFPREGS	(PT_FIRSTMACH + 2)
X  #define	PT_SETFPREGS	(PT_FIRSTMACH + 3)
X+ #define PT_SYSCALL      (PT_FIRSTMACH + 4)
X*** old/./arch/sparc/sparc/process_machdep.c	Mon Aug 15 13:24:54 1994
X***************
X*** 139,141 ****
X--- 139,153 ----
X  	bcopy(regs, p->p_md.md_fpstate, sizeof(struct fpreg));
X  	return 0;
X  }
X+ 
X+ /*
X+  * Copy that subset of the struct mdproc that userland is allowed to write
X+  * with ptrace(PT_WRITE_U) from "from" to "to".
X+  */
X+ void
X+ process_write_p_md(to, from)
X+ struct mdproc *to;
X+ struct mdproc *from;
X+ {
X+  to->md_syscall = from->md_syscall;
X+ }
X*** old/./arch/sparc/sparc/trap.c	Sun May 22 06:37:18 1994
X***************
X*** 656,661 ****
X--- 656,690 ----
X  	}
X  }
X  
X+ int
X+ set_call_vec(emul, callpp, nsysp)
X+ int emul;
X+ struct sysent **callp;
X+ int *nsysp;
X+ {
X+ #ifdef COMPAT_SUNOS
X+  extern int nsun_sysent;
X+  extern struct sysent sun_sysent[];
X+ #endif
X+ 
X+  switch (emul)
X+   { case EMUL_NETBSD:
X+        *callp = sysent;
X+        *nsys = nsysent;
X+        break;
X+ #ifdef COMPAT_SUNOS
X+     case EMUL_SUNOS:
X+        *callp = sun_sysent;
X+        *nsys = nsun_sysent;
X+        break;
X+ #endif
X+     default:
X+        return(1);
X+        break;
X+   }
X+  return(0);
X+ }
X+ 
X  /*
X   * System calls.  `pc' is just a copy of tf->tf_pc.
X   *
X***************
X*** 669,689 ****
X  	register struct trapframe *tf;
X  	int pc;
X  {
X! 	register int i, nsys, *ap, nap;
X! 	register struct sysent *callp;
X  	register struct proc *p;
X  	int error, new;
X  	struct args {
X  		int i[8];
X  	} args;
X  	int rval[2];
X  	u_quad_t sticks;
X- 	extern int nsysent;
X  	extern struct pcb *cpcb;
X- #ifdef COMPAT_SUNOS
X- 	extern int nsun_sysent;
X- 	extern struct sysent sun_sysent[];
X- #endif
X  
X  	cnt.v_syscall++;
X  	p = curproc;
X--- 698,714 ----
X  	register struct trapframe *tf;
X  	int pc;
X  {
X! 	register int i, *ap, nap;
X  	register struct proc *p;
X+ 	int nsys;
X+ 	struct sysent *callp;
X  	int error, new;
X  	struct args {
X  		int i[8];
X  	} args;
X  	int rval[2];
X  	u_quad_t sticks;
X  	extern struct pcb *cpcb;
X  
X  	cnt.v_syscall++;
X  	p = curproc;
X***************
X*** 699,716 ****
X  	p->p_md.md_tf = tf;
X  	new = code & (SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
X  	code &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
X! 	switch (p->p_emul) {
X! 	case EMUL_NETBSD:
X! 		callp = sysent;
X! 		nsys = nsysent;
X! 		break;
X! #ifdef COMPAT_SUNOS
X! 	case EMUL_SUNOS:
X! 		callp = sun_sysent;
X! 		nsys = nsun_sysent;
X! 		break;
X! #endif
X! 	}
X  
X  	/*
X  	 * The first six system call arguments are in the six %o registers.
X--- 724,730 ----
X  	p->p_md.md_tf = tf;
X  	new = code & (SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
X  	code &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
X! 	if (set_call_vec(p->p_emul,&callp,&nsys)) panic("syscall p_emul");
X  
X  	/*
X  	 * The first six system call arguments are in the six %o registers.
X***************
X*** 768,774 ****
X  #endif
X  	rval[0] = 0;
X  	rval[1] = tf->tf_out[1];
X! 	error = (*callp->sy_call)(p, &args, rval);
X  	if (error == 0) {
X  		/*
X  		 * If fork succeeded and we are the child, our stack
X--- 782,873 ----
X  #endif
X  	rval[0] = 0;
X  	rval[1] = tf->tf_out[1];
X!  if (p->p_flag & P_PTSYSCALL)
X!   {
X! #ifdef PT_SYSCALL_DEBUG
X!     const char *s;
X! #ifdef SYSCALL_DEBUG
X!     printf("traced syscall %s[%d](",syscallnames[code],code);
X! #else
X!     printf("traced syscall %d(",code);
X! #endif
X!     s = "";
X!     for (i=0;i<callp->sy_narg;i++)
X!      { printf("%s%x",s,args.i[i]);
X!        s = ",";
X!      }
X!     printf(") -> ");
X! #endif
X!     p->p_md.md_syscall.syscall_compat = p->p_emul;
X!     p->p_md.md_syscall.syscall_num = code;
X!     p->p_md.md_syscall.syscall_nargs = callp->sy_narg;
X!     /* don't reveal kernel stack trash to user-land */
X!     for (i=0;i<callp->sy_narg;i++) p->p_md.md_syscall.syscall_args[i] = args.i[i];
X!     for (;i<8;i++) p->p_md.md_syscall.syscall_args[i] = 0;
X!     p->p_md.md_syscall.syscall_err = 0;
X!     p->p_md.md_syscall.syscall_rv[0] = rval[0];
X!     p->p_md.md_syscall.syscall_rv[1] = rval[1];
X!     ptrace_syscall(p);
X!     rval[0] = p->p_md.md_syscall.syscall_rv[0];
X!     rval[1] = p->p_md.md_syscall.syscall_rv[1];
X!     if (p->p_md.md_syscall.syscall_num == 0)
X!      { error = p->p_md.md_syscall.syscall_err;
X! #ifdef PT_SYSCALL_DEBUG
X!        printf("ptrace-provided: err=%d rv0=%x rv1=%x\n",error,rval[0],rval[1]);
X! #endif
X!      }
X!     else
X!      { if (set_call_vec(p->p_md.md_syscall.syscall_compat,&callp,&nsys))
X! 	{ set_call_vec(EMUL_NETBSD,&callp,&nsys);
X! 	  code = 0;
X! 	}
X!        else
X! 	{ code = p->p_md.md_syscall.syscall_num;
X! 	  if ((code < 0) || (code >= nsys)) code = 0;
X! 	}
X!        callp += code;
X!        for (i=0;i<8;i++) args.i[i] = p->p_md.md_syscall.syscall_args[i];
X! #ifdef PT_SYSCALL_DEBUG
X! #ifdef SYSCALL_DEBUG
X!        printf("now %s[%d](",syscallnames[code],code);
X! #else
X!        printf("now %d(",code);
X! #endif
X!        s = "";
X!        for (i=0;i<callp->sy_narg;i++)
X! 	{ printf("%s%x",s,args.i[i]);
X! 	  s = ",";
X! 	}
X!        printf(") -> ");
X! #endif
X!        error = (*callp->sy_call)(p, &args, rval);
X!        if (p == curproc)
X! 	{ p->p_md.md_syscall.syscall_err = error;
X! 	  p->p_md.md_syscall.syscall_rv[0] = rval[0];
X! 	  p->p_md.md_syscall.syscall_rv[1] = rval[1];
X! #ifdef PT_SYSCALL_DEBUG
X! 	  printf("[err=%d rv0=%x rv1=%x] ",error,rval[0],rval[1]);
X! #endif
X! 	  p->p_md.md_syscall.syscall_num = -1;
X! 	  ptrace_syscall(p);
X! 	  error = p->p_md.md_syscall.syscall_err;
X! 	  rval[0] = p->p_md.md_syscall.syscall_rv[0];
X! 	  rval[1] = p->p_md.md_syscall.syscall_rv[1];
X! #ifdef PT_SYSCALL_DEBUG
X! 	  printf("err=%d rv0=%x rv1=%x\n",error,rval[0],rval[1]);
X! #endif
X! 	}
X!        else
X! 	{
X! #ifdef PT_SYSCALL_DEBUG
X! 	  printf("p=%x[%d] curproc=%x[%d] err=%d rv0=%x rv1=%x\n",(int)p,p->p_pid,(int)curproc,curproc->p_pid,error,rval[0],rval[1]);
X! #endif
X! 	}
X!      }
X!   }
X!  else
X!   { error = (*callp->sy_call)(p, &args, rval);
X!   }
X  	if (error == 0) {
X  		/*
X  		 * If fork succeeded and we are the child, our stack
X*** old/./kern/sys_process.c	Sun Oct  2 14:22:23 1994
X***************
X*** 84,89 ****
X--- 84,90 ----
X  	struct uio uio;
X  	struct iovec iov;
X  	int error, step, write;
X+ 	int flg;
X  
X  	/* "A foolish consistency..." XXX */
X  	if (uap->req == PT_TRACE_ME)
X***************
X*** 133,138 ****
X--- 134,142 ----
X  	case  PT_CONTINUE:
X  	case  PT_KILL:
X  	case  PT_DETACH:
X+ #ifdef PT_SYSCALL
X+ 	case  PT_SYSCALL:
X+ #endif
X  #ifdef PT_STEP
X  	case  PT_STEP:
X  #endif
X***************
X*** 177,182 ****
X--- 181,187 ----
X  
X  	/* Now do the operation. */
X  	step = write = 0;
X+ 	flg = 0;
X  	*retval = 0;
X  
X  	switch (uap->req) {
X***************
X*** 221,226 ****
X--- 226,232 ----
X  		/*
X  		 * Fill in eproc in user area, because user.h says that
X  		 * it's valid for ptrace().  Do it the same way as coredump().
X+ 		 * Wish we didn't have to repeat this for every word we read.
X  		 */
X  		bcopy(t, &t->p_addr->u_kproc.kp_proc, sizeof(struct proc));
X  		fill_eproc(t, &t->p_addr->u_kproc.kp_eproc);
X***************
X*** 232,239 ****
X  	case  PT_WRITE_U:
X  		/*
X  		 * Mostly the same as PT_READ_U, but write data instead of
X! 		 * reading it.  Don't bother filling in the eproc, because
X! 		 * it won't be used for anything anyway.
X  		 */
X  		if ((u_long)uap->addr > (ctob(UPAGES) - sizeof(int)) ||
X  #ifdef m68k /* XXX */
X--- 238,244 ----
X  	case  PT_WRITE_U:
X  		/*
X  		 * Mostly the same as PT_READ_U, but write data instead of
X! 		 * reading it.  Make sure writing p_md works, for PT_SYSCALL.
X  		 */
X  		if ((u_long)uap->addr > (ctob(UPAGES) - sizeof(int)) ||
X  #ifdef m68k /* XXX */
X***************
X*** 243,253 ****
X  #endif /* !m68k XXX */
X  			return (EINVAL);
X  
X! 		/* And write the data. */
X  		*(int *)((caddr_t)t->p_addr + (u_long)uap->addr) = uap->data;
X  		return (0);
X  
X  #ifdef PT_STEP
X  	case  PT_STEP:
X  		/*
X  		 * From the 4.4BSD PRM:
X--- 248,273 ----
X  #endif /* !m68k XXX */
X  			return (EINVAL);
X  
X! #ifdef PT_SYSCALL
X! 		t->p_addr->u_kproc.kp_proc.p_md = t->p_md;
X! #endif
X  		*(int *)((caddr_t)t->p_addr + (u_long)uap->addr) = uap->data;
X+ #ifdef PT_SYSCALL
X+ 		process_write_p_md(&t->p_md,&t->p_addr->u_kproc.kp_proc.p_md);
X+ #endif
X  		return (0);
X  
X+ 	case  PT_CONTINUE:
X+ #ifdef PT_SYSCALL
X+ 			    if (0)
X+ 			     {
X+ 	case  PT_SYSCALL:
X+ 			       flg = P_PTSYSCALL;
X+ 			     }
X+ #endif
X  #ifdef PT_STEP
X+ 			    if (0)
X+ 			     {
X  	case  PT_STEP:
X  		/*
X  		 * From the 4.4BSD PRM:
X***************
X*** 255,263 ****
X  		 * as soon as possible after execution of at least one
X  		 * instruction, execution stops again. [ ... ]"
X  		 */
X! 		step = 1;
X  #endif
X  		/*
X  		 * From the 4.4BSD PRM:
X  		 * "The data argument is taken as a signal number and the
X--- 275,283 ----
X  		 * as soon as possible after execution of at least one
X  		 * instruction, execution stops again. [ ... ]"
X  		 */
X! 			       step = 1;
X! 			     }
X  #endif
X  		/*
X  		 * From the 4.4BSD PRM:
X  		 * "The data argument is taken as a signal number and the
X***************
X*** 288,293 ****
X--- 308,314 ----
X  
X  		/* Finally, deliver the requested signal (or none). */
X  sendsig:
X+ 		t->p_flag |= flg;
X  		t->p_xstat = uap->data;
X  		setrunnable(t);
X  		return (0);
X***************
X*** 411,414 ****
X--- 432,447 ----
X  
X  	/* just return 1 to keep other parts of the system happy */
X  	return (1);
X+ }
X+ 
X+ ptrace_syscall(p)
X+ struct proc *p;
X+ {
X+  int sn;
X+ 
X+  p->p_flag &= ~P_PTSYSCALL;
X+  if (! (p->p_flag & P_TRACED)) return;
X+  if (p != curproc) panic("ptrace_syscall");
X+  psignal(p,SIGTRAP);
X+  while ((sn=CURSIG(curproc))) postsig(sn);
X  }
X*** old/./sys/proc.h	Fri Oct  7 11:12:55 1994
X***************
X*** 203,208 ****
X--- 203,209 ----
X  /* XXX Not sure what to do with these, yet. */
X  #define	P_FSTRACE	0x10000	/* tracing via file system (elsewhere?) */
X  #define	P_SSTEP		0x20000	/* process needs single-step fixup ??? */
X+ #define P_PTSYSCALL     0x40000 /* ptrace(PT_SYSCALL): stop in syscall */
X  
X  /*
X   * Definitions for the p_emul flag.
EOF
if test 11051 -ne "`wc -c PT_SYSCALL.diffs`"
then
echo shar: error transmitting PT_SYSCALL.diffs \(should have been 11051 characters\)
fi
exit 0
# end of shell archive