[comp.os.minix] Ptrace system call

bds@lzaz.ATT.COM (B.SZABLAK) (12/21/88)

Following is a shell archive that contains context diff files for 
implementing the ptrace (2) system call. It was written and tested
on an ATARI ST, but should be readily adapted to the PC 1.3 version.
THIS HAS NOT BEEN TRIED. A program, tstprg, that performs a sanity test
is included in the distribution.

The ptrace() system call as implemented differs from the normal definition:
	int ptrace(int, int, int, int)
since the third argument must be capable of holding a virtual address
(which on the ATARI ST is 32 bits long while an int is 16 bits long).
Consequently it is defined as:
	long ptrace(int, int, long, long)
The long return and fourth argument permit easy access to the
68000's registers. 

On the PC, it should be possible to change the ptrace() to the normal
definition with few changes to the actual implementation, and with a 32 bit
C compiler for the ST such as GNU C the library interface routine would be
the only change.

To install, unshar the following file in the directory containing the
various MINIX source directories. Use patch to update the files, or if
it makes you feel better do it by hand.

PLEASE NOTE: COPY h/com.h TO /usr/include/minix/com.h

I will posting shortly, a debugger that makes use of ptrace to debug
programs generated with the MINIX ST C compiler. Feel free to send me
mail if you have any problems/questions.

----------------------------------CUT HERE-------------------------------------
echo x - ptrace.2
gres '^X' '' > ptrace.2 << '/'
X
X
X     SYSTEM CALL
X	ptrace - process trace
X
X     INVOCATION
X	long ptrace (request, pid, addr, data)
X	int request, pid;
X	long addr, data;
X
X     EXPLANATION
X	Ptrace provides a mean of controlling a child process
X	with the specified process identifier, pid, for the purposes
X	of debugging. Request may have the following values:
X
X	0 -	This request should be made by the child process
X		that wishes to be traced by its parent.
X	
X	1 -	This request is made by the parent to fetch data
X		from the text space of the child starting at the
X		address contained in addr.
X	
X	2 -	This request is made by the parent to fetch data
X		from the data space of the child starting at the
X		address contained in addr.
X
X	3 -	This request is made by the parent to fetch data
X		from the child's proc table entry starting at the
X		byte offset from the beginning of the table contained
X		in addr. See user.h
X	
X	4 -	This request is made by the parent to set data
X		in the text space of the child starting at the
X		address contained in addr.
X	
X	5 -	This request is made by the parent to set data
X		in the data space of the child starting at the
X		address contained in addr.
X
X	6 -	This request is made by the parent to set a field
X		in the child's proc table entry starting at the
X		byte offset from the beginning of the table contained
X		in addr. Only the registers, pc, and psw may be modified.
X	
X	7 -	This request results in the child resuming execution.
X		If data contains a valid signal number, the child is
X		sent that signal upon resumption. Otherwise, all pending
X		signals are canceled.
X
X	8 -	This request results in the child exiting with a status
X		value equal to the value in data.
X
X	9 -	This request results in the child executing the next
X		instruction (unless it is a trap - then the next two
X		instructions are executed) and halting because of a
X		SIGTRAP signal.
X	
X	For security reasons, the set user ID and set group ID exec
X	features are suppressed for processes that have permitted tracing.
X
X	The parent process may issue one of the above requests (1 to 9)
X	only when the child process has stopped. A child process will
X	stop whenever a signal is sent to it. A traced process will have
X	a SIGTRAP sent to it when it performs an exec. The parent process
X	will be notified of the child stopping when it calls the wait()
X	function. Wait() will return the process ID of the child and
X	fill the status variable whose address it is passed with the
X	signal number that stopped the child in the upper 8 bits. The
X	lower 8 bits will contain the value 0177.
X
X     RESULTS
X	Ptrace will in fail and return a -1 if:
X
X	[EIO]		Request is an illegal number, or addr is
X			invalid for the number given.
X
X	[ESRCH]		Pid identifies a child that does not exist or
X			has not executed a ptrace with request 0.
/
echo x - ./h/callnr.h.cdif
gres '^X' '' > ./h/callnr.h.cdif << '/'
X*** callnr.h	Thu Dec 13 18:57:06 1988
X--- ../h/callnr.h	Thu Dec 13 19:10:54 1988
X***************
X*** 24,29 ****
X--- 24,30 ----
X  #define SETUID	          23
X  #define GETUID	          24
X  #define STIME	          25
X+ #define PTRACE		  26
X  #define ALARM	          27
X  #define FSTAT	          28 
X  #define PAUSE	          29
/
echo x - ./h/com.h.cdif
gres '^X' '' > ./h/com.h.cdif << '/'
X*** com.h	Thu Dec 13 18:57:07 1988
X--- ../h/com.h	Thu Nov 15 19:48:46 1988
X***************
X*** 21,26 ****
X--- 21,27 ----
X  #	define SYS_FRESH  10	/* fcn code for sys_fresh() */
X  #endif
X  #	define SYS_KILL   11	/* fcn code for sys_kill(proc, sig) */
X+ #	define SYS_TRACE  12	/* fcn code for sys_trace(req,pid,addr,data) */
X  
X  #define CLOCK             -3	/* clock class */
X  #	define SET_ALARM   1	/* fcn code to CLOCK, set up alarm */
/
echo x - ./kernel/const.h.cdif
gres '^X' '' > ./kernel/const.h.cdif << '/'
X*** const.h	Thu Dec 13 19:41:29 1988
X--- ../kernel/const.h	Thu Dec 13 19:39:09 1988
X***************
X*** 7,12 ****
X--- 7,16 ----
X  #define NR_REGS           11	/* number of general regs in each proc slot */
X  #define INIT_PSW      0x0200	/* initial psw */
X  #define INIT_SP (int*)0x0010	/* initial sp: 3 words pushed by kernel */
X+ #define TRACEBIT      0x100	/* or this with psw in proc[] for tracing */
X+ #define SETBITS(rp, new) { 	/* permits only certain bits to be set */ \
X+ 				rp->p_pcpsw.psw |= (new & 0xFF); \
X+ 				rp->p_pcpsw.psw &= (new | ~0xFF); \
X  
X  /* The following values are used in the assembly code.  Do not change the
X   * values of 'ES_REG', 'DS_REG', 'CS_REG', or 'SS_REG' without making the 
/
echo x - ./kernel/proc.h.cdif
gres '^X' '' > ./kernel/proc.h.cdif << '/'
X*** proc.h	Thu Dec 13 19:22:57 1988
X--- ../kernel/proc.h	Thu Nov 21 20:33:26 1988
X***************
X*** 53,58 ****
X--- 53,59 ----
X  #define SENDING          004	/* set when process blocked trying to send */
X  #define RECEIVING        010	/* set when process blocked trying to recv */
X  #define PENDING          020	/* set when process has signals pending */
X+ #define P_STOP		 040	/* set when process is being traced */
X  
X  #define proc_addr(n) &proc[NR_TASKS + n]
X  #define NIL_PROC (struct proc *) 0
/
echo x - ./kernel/stmpx.s.cdif
gres '^X' '' > ./kernel/stmpx.s.cdif << '/'
X*** stmpx.s	Thu Dec 13 19:23:03 1988
X--- ../kernel/stmpx.s	Thu Dec  9 18:11:18 1988
X***************
X*** 77,83 ****
X  !
X  .data2	0,	0,	0,	start,	0x0200,	err,	0x0300,	err
X  .data2	0x0400,	trp,	0x0500,	trp,	0x0600,	trp,	0x0700,	trp
X! .data2	0x0800,	trp,	0x0900,	trp,	0x0A00,	trp,	0x0B00,	trp
X  .data2	0x0C00,	trp,	0x0D00,	trp,	0x0E00,	trp,	0x0F00,	trp
X  .data2	0x1000,	non,	0x1100,	non,	0x1200,	non,	0x1300,	non
X  .data2	0x1400,	non,	0x1500,	non,	0x1600,	non,	0,	conf
X--- 77,83 ----
X  !
X  .data2	0,	0,	0,	start,	0x0200,	err,	0x0300,	err
X  .data2	0x0400,	trp,	0x0500,	trp,	0x0600,	trp,	0x0700,	trp
X! .data2	0x0800,	trp,	0x0900,	trc,	0x0A00,	trp,	0x0B00,	trp
X  .data2	0x0C00,	trp,	0x0D00,	trp,	0x0E00,	trp,	0x0F00,	trp
X  .data2	0x1000,	non,	0x1100,	non,	0x1200,	non,	0x1300,	non
X  .data2	0x1400,	non,	0x1500,	non,	0x1600,	non,	0,	conf
X***************
X*** 172,177 ****
X--- 172,181 ----
X  	jsr	save
X  	jsr	_trap
X  	bra	restart
X+ trc:
X+ 	btst	#5,(sp)		! tracing through trap?
X+ 	beq	trp		! No, do normal trace processing
X+ 	rte			! don't trace; execute system call
X  int:
X  	jsr	save
X  	jsr	_rupt
/
echo x - ./kernel/system.c.cdif
gres '^X' '' > ./kernel/system.c.cdif << '/'
X*** system.c	Thu Dec 13 19:23:07 1988
X--- ../kernel/system.c	Thu Dec 11 18:56:38 1988
X***************
X*** 18,23 ****
X--- 18,24 ----
X   *   SYS_SIG	 send a signal to a process
X   *   SYS_KILL	 cause a signal to be sent via MM
X   *   SYS_COPY	 requests a block of data to be copied between processes
X+  *   SYS_TRACE	 request a trace operation
X   *
X   * Message type m1 is used for all except SYS_SIG and SYS_COPY, both of
X   * which need special parameter types.
X***************
X*** 28,34 ****
X   * |------------+---------+---------+---------+---------|
X   * | SYS_NEWMAP | proc nr |         |         | map ptr |
X   * |------------+---------+---------+---------+---------|
X!  * | SYS_EXEC   | proc nr |         | new sp  |         |
X   * |------------+---------+---------+---------+---------|
X   * | SYS_XIT    | parent  | exitee  |         |         |
X   * |------------+---------+---------+---------+---------|
X--- 29,35 ----
X   * |------------+---------+---------+---------+---------|
X   * | SYS_NEWMAP | proc nr |         |         | map ptr |
X   * |------------+---------+---------+---------+---------|
X!  * | SYS_EXEC   | proc nr | traced  | new sp  |         |
X   * |------------+---------+---------+---------+---------|
X   * | SYS_XIT    | parent  | exitee  |         |         |
X   * |------------+---------+---------+---------+---------|
X***************
X*** 43,48 ****
X--- 44,54 ----
X  #endif
X   * ------------------------------------------------------
X   *
X+  *    m_type       m2_i1     m2_i2     m2_l1     m2_l2     
X+  * ------------------------------------------------------
X+  * | SYS_TRACE  | proc_nr | request |  addr   |  data   |
X+  * ------------------------------------------------------
X+  *
X   *
X   *    m_type       m6_i1     m6_i2     m6_i3     m6_f1     
X   * ------------------------------------------------------
X***************
X*** 108,113 ****
X--- 114,120 ----
X  	    case SYS_SIG:	r = do_sig(&m);		break;
X  	    case SYS_KILL:	r = do_kill(&m);	break;
X  	    case SYS_COPY:	r = do_copy(&m);	break;
X+ 	    case SYS_TRACE:	r = do_trace(&m);	break;
X  	    default:		r = E_BAD_FCN;
X  	}
X  
X***************
X*** 231,236 ****
X--- 238,244 ----
X    k = m_ptr->PROC1;		/* 'k' tells which process did EXEC */
X    sp = (int *) m_ptr->STACK_PTR;
X    if (k < 0 || k >= NR_PROCS) return(E_BAD_PROC);
X+   if (m_ptr->PROC2) cause_sig(k, SIGTRAP);
X    rp = proc_addr(k);
X    rp->p_sp = sp;		/* set the stack pointer */
X  #ifdef ATARI_ST
X***************
X*** 496,501 ****
X--- 504,618 ----
X    return(OK);
X  }
X  
X+ /*===========================================================================*
X+  *				do_trace				     * 
X+  *===========================================================================*/
X+ 
X+ #define PROCNR	m->m2_i1
X+ #define REQUEST m->m2_i2	
X+ #define ADDR	(vir_bytes)m->m2_l1
X+ #define DATA	m->m2_l2
X+ #define VLSIZE	((vir_bytes)sizeof(long))
X+ 
X+ PRIVATE do_trace(m)
X+   message *m;
X+ {
X+   register struct proc *rp;
X+   phys_bytes umap(), src, dst;
X+   int i;
X+ 
X+   rp = proc_addr(PROCNR);
X+   if (rp->p_flags & P_SLOT_FREE) return OK;
X+   switch (REQUEST) {
X+ 	case -1: /* stop process */
X+ 		unready(rp);
X+ 		rp->p_flags |= P_STOP;
X+ 		rp->p_pcpsw.psw &= ~TRACEBIT; /* clear trace bit */
X+ 		return OK;
X+ 	case 1: /* return value from instruction space */
X+ 		if ((src = umap(rp, T, ADDR, VLSIZE)) == 0)
X+ #ifdef ATARI_ST
X+ 			goto getdata; /* something should be done about this */
X+ #else
X+ 			return EIO;
X+ #endif
X+ 		dst = umap(proc_addr(HARDWARE), D, (vir_bytes)&DATA, VLSIZE);
X+ 		phys_copy(src, dst, (phys_bytes)sizeof(long));
X+ 		break;
X+ 	case 2: /* return value from data space */
X+ 	getdata:
X+ 		if ((src = umap(rp, D, ADDR, VLSIZE)) == 0)
X+ 			return EIO;
X+ 		dst = umap(proc_addr(HARDWARE), D, (vir_bytes)&DATA, VLSIZE);
X+ 		phys_copy(src, dst, (phys_bytes)sizeof(long));
X+ 		break;
X+ 	case 3: /* return value from process table */
X+ 		if ((int)ADDR >= sizeof(struct proc))
X+ 			return EIO;
X+ 		DATA = *(long *)((char *)rp + (int)ADDR);
X+ 		break;
X+ 	case 4: /* set value from instruction space */
X+ 		if ((dst = umap(rp, T, ADDR, VLSIZE)) == 0)
X+ #ifdef ATARI_ST
X+ 			goto setdata;
X+ #else
X+ 			return EIO;
X+ #endif
X+ 		src = umap(proc_addr(HARDWARE), D, (vir_bytes)&DATA, VLSIZE);
X+ 		phys_copy(src, dst, (phys_bytes)sizeof(long));
X+ 		DATA = 0;
X+ 		break;
X+ 	case 5: /* set value from data space */
X+ 	setdata:
X+ 		if ((dst = umap(rp, D, ADDR, VLSIZE)) == 0)
X+ 			return EIO;
X+ 		src = umap(proc_addr(HARDWARE), D, (vir_bytes)&DATA, VLSIZE);
X+ 		phys_copy(src, dst, (phys_bytes)sizeof(long));
X+ 		DATA = 0;
X+ 		break;
X+ 	case 6: /* set value in process table */
X+ 		i = (int)ADDR / sizeof(rp->p_reg[0]);
X+ 		if (i >= NR_REGS)
X+ 		{
X+ 			if (i == NR_REGS)
X+ 			{
X+ 				rp->p_sp = DATA;
X+ 				DATA = 0;
X+ 				break;
X+ 			}
X+ 			if ((int)ADDR == (int)&((struct proc *)0)->p_pcpsw.psw)
X+ 			{
X+ 				/* only selected bits are changeable */
X+ 				SETBITS(rp, DATA);
X+ 				DATA = 0;
X+ 				break;
X+ 			}
X+ 			if ((int)ADDR == (int)&((struct proc *)0)->p_pcpsw.pc)
X+ 			{
X+ 				rp->p_pcpsw.pc = DATA;
X+ 				DATA = 0;
X+ 				break;
X+ 			}
X+ 			return EIO;
X+ 		}
X+ 		rp->p_reg[i] = DATA;
X+ 		DATA = 0;
X+ 		break;
X+ 	case 7: /* resume execution */
X+ 		rp->p_flags &= ~P_STOP;
X+ 		if (rp->p_flags == 0) ready(rp);
X+ 		DATA = 0;
X+ 		break;
X+ 	case 9: /* set trace bit */
X+ 		rp->p_pcpsw.psw |= TRACEBIT;
X+ 		rp->p_flags &= ~P_STOP;
X+ 		if (rp->p_flags == 0) ready(rp);
X+ 		DATA = 0;
X+ 		break;
X+ 	default: return EIO;
X+   }
X+   return OK;
X+ }
X  
X  /*===========================================================================*
X   *				cause_sig				     * 
/
echo x - ./mm/exec.c.cdif
gres '^X' '' > ./mm/exec.c.cdif << '/'
X*** exec.c	Thu Dec 13 19:59:07 1988
X--- ../mm/exec.c	Thu Nov 21 18:08:45 1988
X***************
X*** 120,132 ****
X    close(fd);			/* don't need exec file any more */
X  
X    /* Take care of setuid/setgid bits. */
X!   if (s_buf.st_mode & I_SET_UID_BIT) {
X! 	rmp->mp_effuid = s_buf.st_uid;
X! 	tell_fs(SETUID, who, (int) rmp->mp_realuid, (int) rmp->mp_effuid);
X!   }
X!   if (s_buf.st_mode & I_SET_GID_BIT) {
X! 	rmp->mp_effgid = s_buf.st_gid;
X! 	tell_fs(SETGID, who, (int) rmp->mp_realgid, (int) rmp->mp_effgid);
X    }
X  
X    /* Fix up some 'mproc' fields and tell kernel that exec is done. */
X--- 120,134 ----
X    close(fd);			/* don't need exec file any more */
X  
X    /* Take care of setuid/setgid bits. */
X!   if ((rmp->mp_flags & TRACED) == 0) { /* suppress if tracing */
X! 	if (s_buf.st_mode & I_SET_UID_BIT) {
X! 		rmp->mp_effuid = s_buf.st_uid;
X! 		tell_fs(SETUID, who, (int) rmp->mp_realuid, (int) rmp->mp_effuid);
X! 	}
X! 	if (s_buf.st_mode & I_SET_GID_BIT) {
X! 		rmp->mp_effgid = s_buf.st_gid;
X! 		tell_fs(SETGID, who, (int) rmp->mp_realgid, (int) rmp->mp_effgid);
X! 	}
X    }
X  
X    /* Fix up some 'mproc' fields and tell kernel that exec is done. */
X***************
X*** 134,140 ****
X    rmp->mp_flags &= ~SEPARATE;	/* turn off SEPARATE bit */
X    rmp->mp_flags |= ft;		/* turn it on for separate I & D files */
X    new_sp = (char *) vsp;
X!   sys_exec(who, new_sp);
X    return(OK);
X  }
X  
X--- 136,142 ----
X    rmp->mp_flags &= ~SEPARATE;	/* turn off SEPARATE bit */
X    rmp->mp_flags |= ft;		/* turn it on for separate I & D files */
X    new_sp = (char *) vsp;
X!   sys_exec(who, new_sp, rmp->mp_flags & TRACED);
X    return(OK);
X  }
X  
/
echo x - ./mm/forkexit.c.cdi
gres '^X' '' > ./mm/forkexit.c.cdi << '/'
X*** forkexit.c	Thu Dec 13 19:59:09 1988
X--- ../mm/forkexit.c	Thu Nov 22 20:56:24 1988
X***************
X*** 207,212 ****
X--- 207,219 ----
X  			dont_reply = TRUE;
X  			return(OK);
X  		}
X+ 		if (rp->mp_flags & STOPPED && rp->mp_sigstatus) {
X+ 			reply(who, rp->mp_pid, 0177 | (rp->mp_sigstatus << 8),
X+ 				NIL_PTR);
X+ 			dont_reply = TRUE;
X+ 			rp->mp_sigstatus = 0;
X+ 			return(OK);
X+ 		}
X  	}
X    }
X  
X***************
X*** 259,264 ****
X--- 266,272 ----
X  #endif
X  
X    /* Update flags. */
X+   child->mp_flags  &= ~TRACED;	/* turn off TRACED bit */
X    child->mp_flags  &= ~HANGING;	/* turn off HANGING bit */
X    child->mp_flags  &= ~PAUSED;	/* turn off PAUSED bit */
X    parent->mp_flags &= ~WAITING;	/* parent is no longer waiting */
/
echo x - ./mm/mproc.h.cdif
gres '^X' '' > ./mm/mproc.h.cdif << '/'
X*** mproc.h	Thu Dec 13 19:59:10 1988
X--- ../mm/mproc.h	Thu Nov 19 09:13:23 1988
X***************
X*** 34,36 ****
X--- 34,38 ----
X  #define PAUSED           010	/* set by PAUSE system call */
X  #define ALARM_ON         020	/* set when SIGALRM timer started */
X  #define SEPARATE	 040	/* set if file is separate I & D space */
X+ #define	TRACED		0100	/* set if process is to be traced */
X+ #define STOPPED		0200	/* set if process stopped for tracing */
/
echo x - ./mm/param.h.cdif
gres '^X' '' > ./mm/param.h.cdif << '/'
X*** param.h	Thu Dec 13 19:59:11 1988--- ../mm/param.h	Thu Nov 23 19:40:17 1988
X***************
X*** 13,18 ****
X--- 13,21 ----
X  #define stack_ptr	mm_in.m1_p2
X  #define status		mm_in.m1_i1
X  #define usr_id		(uid) mm_in.m1_i1
X+ #define request		mm_in.m2_i2
X+ #define taddr		mm_in.m2_l1
X+ #define data		mm_in.m2_l2
X  
X  /* The following names are synonyms for the variables in the output message. */
X  #define reply_type      mm_out.m_type
/
echo x - ./mm/signal.c.cdif
gres '^X' '' > ./mm/signal.c.cdif << '/'
X*** signal.c	Thu Dec 13 19:59:13 1988
X--- ../mm/signal.c	Thu Nov 21 18:06:42 1988
X***************
X*** 208,213 ****
X--- 208,217 ----
X    extern unshort core_bits;
X  
X    if ( (rmp->mp_flags & IN_USE) == 0) return;	/* if already dead forget it */
X+   if (rmp->mp_flags & TRACED) { /* a traced process has special handling */
X+ 	stop_proc(rmp, sig_nr); /* a signal causes it to stop */
X+ 	return;
X+   }
X    mask = 1 << (sig_nr - 1);
X    if (rmp->mp_catch & mask) {
X  	/* Signal should be caught. */
/
echo x - ./mm/table.c.cdif
gres '^X' '' > ./mm/table.c.cdif << '/'
X*** table.c	Thu Dec 13 19:59:14 1988
X--- ../mm/table.c	Thu Nov 15 19:55:10 1988
X***************
X*** 26,32 ****
X  char *stackpt = &mm_stack[MM_STACK_BYTES];	/* initial stack pointer */
X  
X  extern do_mm_exit(), do_fork(), do_wait(), do_brk(), do_getset(), do_exec();
X! extern do_signal(), do_kill(), do_pause(), do_alarm();
X  extern no_sys(), unpause(), do_ksig(), do_brk2();
X  
X  int (*call_vec[NCALLS])() = {
X--- 26,32 ----
X  char *stackpt = &mm_stack[MM_STACK_BYTES];	/* initial stack pointer */
X  
X  extern do_mm_exit(), do_fork(), do_wait(), do_brk(), do_getset(), do_exec();
X! extern do_signal(), do_kill(), do_pause(), do_alarm(), do_trace();
X  extern no_sys(), unpause(), do_ksig(), do_brk2();
X  
X  int (*call_vec[NCALLS])() = {
X***************
X*** 56,62 ****
X  	do_getset,	/* 23 = setuid	*/
X  	do_getset,	/* 24 = getuid	*/
X  	no_sys,		/* 25 = stime	*/
X! 	no_sys,		/* 26 = (ptrace)*/
X  	do_alarm,	/* 27 = alarm	*/
X  	no_sys,		/* 28 = fstat	*/
X  	do_pause,	/* 29 = pause	*/
X--- 56,62 ----
X  	do_getset,	/* 23 = setuid	*/
X  	do_getset,	/* 24 = getuid	*/
X  	no_sys,		/* 25 = stime	*/
X! 	do_trace,	/* 26 = ptrace	*/
X  	do_alarm,	/* 27 = alarm	*/
X  	no_sys,		/* 28 = fstat	*/
X  	do_pause,	/* 29 = pause	*/
/
echo x - ./mm/Makefile.cdif
gres '^X' '' > ./mm/Makefile.cdif << '/'
X*** Makefile	Thu Dec 13 20:15:00 1988
X--- ../mm/Makefile	Thu Nov 21 21:01:11 1988
X***************
X*** 6,12 ****
X  CFLAGS	= -O -DATARI_ST
X  
X  OBJ	= main.o forkexit.o break.o exec.o signal.o getset.o \
X! 	  alloc.o utility.o table.o putc.o 
X  HDR	= ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \
X  	  ../h/signal.h ../h/stat.h ../h/type.h \
X  	  const.h glo.h mproc.h param.h
X--- 6,12 ----
X  CFLAGS	= -O -DATARI_ST
X  
X  OBJ	= main.o forkexit.o break.o exec.o signal.o getset.o \
X! 	  alloc.o utility.o table.o putc.o trace.o
X  HDR	= ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \
X  	  ../h/signal.h ../h/stat.h ../h/type.h \
X  	  const.h glo.h mproc.h param.h
/
echo x - ./mm/trace.c
gres '^X' '' > ./mm/trace.c << '/'
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/error.h"
X#include "../h/signal.h"
X#include "const.h"
X#include "glo.h"
X#include "mproc.h"
X#include "param.h"
X
Xextern errno;
X
X/*===========================================================================*
X *				findproc  				     *
X *===========================================================================*/
XPUBLIC struct mproc *findproc(lpid)
X{
X  register struct mproc *rmp;
X
X  for (rmp = &mproc[INIT_PROC_NR + 1]; rmp < &mproc[NR_PROCS]; rmp++ )
X	if (rmp->mp_flags & IN_USE && rmp->mp_pid == lpid) return rmp;
X
X  return 0;
X}
X
X/*===========================================================================*
X *				do_trace  				     *
X *===========================================================================*/
XPUBLIC int do_trace()
X{
X  register struct mproc *child;
X  int r;
X
X  if (request == 0) {  /* enable tracing by parent for this process */
X	mp->mp_flags |= TRACED;
X	mm_out.m2_l2 = 0;
X	return OK;
X  }
X  if ((child = findproc(pid)) == 0 || (child->mp_flags & STOPPED) == 0) {
X	return ESRCH;
X  }
X  if (request == 8) { /* exit */
X	mm_exit(child, data);
X	mm_out.m2_l2 = 0;
X	return OK;
X  }
X  if (request == 7) { /* resume execution */
X	if (data > NR_SIGS) {
X		return EIO;
X	}
X	if (data > 0) { /* issue signal */
X		child->mp_flags &= ~TRACED; /* so signal is not diverted */
X		sig_proc(child, (int)data);
X		child->mp_flags |= TRACED;
X	}
X	child->mp_flags &= ~STOPPED;
X  }	
X  if (sys_trace(request, child - mproc, (long)taddr, (long *)&data) != OK)
X	return -errno;
X  mm_out.m2_l2 = data;
X  return OK;
X}
X
X/*===========================================================================*
X *				stop_proc  				     *
X *===========================================================================*/
XPUBLIC int stop_proc(rmp, sig_nr) /* a traced process got a signal so stop */
Xregister struct mproc *rmp;
X{
X  register struct mproc *rpmp = mproc + rmp->mp_parent;
X
X  if (sys_trace(-1, rmp - mproc, 0L, (long *)0) != OK) return;
X  rmp->mp_flags |= STOPPED;
X  if (rpmp->mp_flags & WAITING) {
X	rpmp->mp_flags &= ~WAITING;	/* parent is no longer waiting */
X	reply(rmp->mp_parent, rmp->mp_pid, 0177 | (sig_nr << 8), NIL_PTR);
X  }
X  else {
X	rmp->mp_sigstatus = sig_nr;
X  }
X  return;
X}
/
echo x - ./lib/Makefile.cdif
gres '^X' '' > ./lib/Makefile.cdif << '/'
X*** Makefile	Thu Dec 13 19:49:11 1988
X--- ../lib/Makefile	Thu Nov 15 19:27:02 1988
X***************
X*** 20,26 ****
X  	  strcat.o strcmp.o strcpy.o strlen.o strncat.o strncmp.o strncpy.o
X  O4	= sync.o syslib.o time.o times.o umask.o umount.o ungetc.o \
X  	  unlink.o utime.o wait.o write.o call.o message.o stbrksz.o \
X! 	  stsndrec.o stsetjmp.o
X  O5	= _ara.o _cii.o _cmi.o _cmp.o _cms.o \
X  	  _cmu.o _csa.o _csb.o _cuu.o _cvf.o \
X  	  _dvi.o _dvu.o _exg.o _fat.o _ffp.o \
X--- 20,26 ----
X  	  strcat.o strcmp.o strcpy.o strlen.o strncat.o strncmp.o strncpy.o
X  O4	= sync.o syslib.o time.o times.o umask.o umount.o ungetc.o \
X  	  unlink.o utime.o wait.o write.o call.o message.o stbrksz.o \
X! 	  stsndrec.o stsetjmp.o ptrace.o
X  O5	= _ara.o _cii.o _cmi.o _cmp.o _cms.o \
X  	  _cmu.o _csa.o _csb.o _cuu.o _cvf.o \
X  	  _dvi.o _dvu.o _exg.o _fat.o _ffp.o \
/
echo x - ./lib/syslib.c.cdif
gres '^X' '' > ./lib/syslib.c.cdif << '/'
X*** syslib.c	Thu Dec 13 19:45:02 1988
X--- ../lib/syslib.c	Thu Nov 25 07:32:29 1988
X***************
X*** 81,93 ****
X  }
X  
X  
X! PUBLIC sys_exec(proc, ptr)
X! int proc;			/* proc that did exec */
X! char *ptr;			/* new stack pointer */
X  {
X  /* A proc has exec'd.  Tell the kernel. */
X  
X!   callm1(SYSTASK, SYS_EXEC, proc, 0, 0, ptr, NIL_PTR, NIL_PTR);
X  }
X  
X  PUBLIC sys_newmap(proc, ptr)
X--- 81,94 ----
X  }
X  
X  
X! PUBLIC sys_exec(proc, ptr, traced)
X! int proc;			/* proc that did exec */
X! char *ptr;			/* new stack pointer */
X! int traced;			/* is tracing enabled? */
X  {
X  /* A proc has exec'd.  Tell the kernel. */
X  
X!   callm1(SYSTASK, SYS_EXEC, proc, traced, 0, ptr, NIL_PTR, NIL_PTR);
X  }
X  
X  PUBLIC sys_newmap(proc, ptr)
X***************
X*** 161,166 ****
X--- 162,180 ----
X    callx(SYSTASK, SYS_KILL);
X  }
X  
X+ PUBLIC sys_trace(req, procnr, addr, data_p)
X+ long addr, *data_p;
X+ {
X+   int r;
X+ 
X+   M.m2_i1 = procnr;
X+   M.m2_i2 = req;
X+   M.m2_l1 = addr;
X+   if (data_p) M.m2_l2 = *data_p;
X+   r = callx(SYSTASK, SYS_TRACE);
X+   if (data_p) *data_p = M.m2_l2;
X+   return r;
X+ }
X  
X  PUBLIC int tell_fs(what, p1, p2, p3)
X  int what, p1, p2, p3;
/
echo x - ./lib/ptrace.c
gres '^X' '' > ./lib/ptrace.c << '/'
X#include "lib.h"
X
XPUBLIC long ptrace(req, pid, addr, data)
Xlong addr, data;
X{
X  M.m2_i1 = pid;
X  M.m2_i2 = req;
X  M.m2_l1 = addr;
X  M.m2_l2 = data;
X  if (callx(MM, PTRACE) == -1) return -1;
X  if (M.m2_l2 == -1) {errno = OK; return -1;}
X  return M.m2_l2;
X}
/
echo x - tstprg.c
gres '^X' '' > tstprg.c << '/'
X/*
X * Ptrace sanity test
X *
X * compile using: cc -o tstprg -DATARI_ST -I<source dir> tstprg.c
X */
X
X#define T_OK		0
X#define T_GETINS	1
X#define T_GETDATA	2
X#define T_GETUSER	3
X#define	T_SETINS	4
X#define T_SETDATA	5
X#define T_SETUSER	6
X#define T_RESUME	7
X#define T_EXIT		8
X#define T_STEP		9
X
X#include "stdio.h"
X#include "signal.h"
X#include "h/type.h"
X#include "h/const.h"
X#include "kernel/type.h"
X#include "kernel/const.h"
X#undef printf
X
Xstruct proc {
X  long p_reg[NR_REGS];		/* process' registers */
X  int *p_sp;			/* stack pointer */
X  struct pc_psw p_pcpsw;	/* pc and psw as pushed by interrupt */
X  int *p_splow;			/* lowest observed stack value */
X  int p_trap;			/* trap type (only low byte) */
X  int p_flags;			/* P_SLOT_FREE, SENDING, RECEIVING, etc. */
X  struct mem_map p_map[NR_SEGS];/* memory map */
X  phys_clicks p_shadow;		/* set if shadowed process image */
X  int p_nflips;			/* statistics */
X  char p_physio;		/* cannot be (un)shadowed now if set */
X  int p_pid;			/* process id passed in from MM */
X
X  real_time user_time;		/* user time in ticks */
X  real_time sys_time;		/* sys time in ticks */
X  real_time child_utime;	/* cumulative user time of children */
X  real_time child_stime;	/* cumulative sys time of children */
X  real_time p_alarm;		/* time of next alarm in ticks, or 0 */
X
X  struct proc *p_callerq;	/* head of list of procs wishing to send */
X  struct proc *p_sendlink;	/* link to next proc wishing to send */
X  message *p_messbuf;		/* pointer to message buffer */
X  int p_getfrom;		/* from whom does process want to receive? */
X
X  struct proc *p_nextready;	/* pointer to next ready process */
X  int p_pending;		/* bit map for pending signals 1-16 */
X};
X
X#define SIZ (1 + sizeof(struct proc)/sizeof(long))
X
Xlong ptrace(), p[SIZ];
Xextern errno;
X
Xgetinfo(pid)
X{
X	int i, rc, stat, ls, hs;
X	struct proc *prc;
X
X	prc  = p;
X	while ((rc = wait(&stat)) == -1);
X	ls = stat & 0xFF;
X	hs = (stat >> 8) & 0xFF;
X	if (ls == 0)
X	{
X		printf("\nchild %d exited with status %d\n", rc, hs);
X		exit(0);
X	}
X	if (hs == 0)
X	{
X		printf("\nchild %d terminated by signal %d\n", rc, ls & 0x7F);
X		if (ls & 0x80) printf("(core dumped)\n");
X		exit(0);
X	}
X	printf("\nchild %d stopped on signal %d\n", rc, hs);
X	for (i = 0; i < (SIZ-1); i++)
X	{
X		p[i] = ptrace(T_GETUSER, pid, (long)(i*sizeof(long)), 0L);
X	}
X	printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw);
X	printf(
X"      0        1        2        3        4        5        6        7\nD");
X	for (i = 0; i < 8; i++) printf(" %08lx", prc->p_reg[i]);
X	printf("\nA");
X	for (; i < NR_REGS; i++) printf(" %08lx", prc->p_reg[i]);
X	printf(" %08lx\n\n   vir     phys     len\n", (long)prc->p_sp);
X	for (i = 0; i < NR_SEGS; i++)
X	{
X		printf("%08lx %08lx %08lx\n",
X			(long)prc->p_map[i].mem_vir,
X			(long)prc->p_map[i].mem_phys,
X			(long)prc->p_map[i].mem_len);
X	}
X}
X
Xlong global = 11;
X
Xcatch() { signal(SIGIOT,catch); global++; return; }
X
Xmain(argc, argv)
X	char *argv[];
X{
X	int p_pid, c_pid;
X
X	p_pid = getpid();
X	c_pid = fork();
X	if (c_pid) parent(p_pid, c_pid);
X	else child(p_pid, getpid());
X}
X
X/*
X * The child just loops sending signals to itself. It keeps track
X * of the number of times it actually receives a SIGIOT in global
X */
X
Xchild(p_pid, my_pid)
X{
X	signal(SIGIOT,catch);
X	/* enable tracing */
X	if (ptrace(T_OK, my_pid, 0L, 0L) == -1) perror("child: ");
X	for(;;) kill(my_pid, SIGIOT);
X}
X
Xparent(my_pid, c_pid)
X{
X	long i;
X
X	if (c_pid < 0) { perror("fork:"); exit(0); }
X	printf("starting test\n");
X
X	/* restart child with a SIGIOT signal pending */
X	getinfo(c_pid);
X	if (ptrace(T_RESUME, c_pid, 0L, (long)SIGIOT) == -1)
X		perror("resume");
X        /*
X	 * Note that although the child has a different data space
X	 * the virtual addresses are the same as for the parent
X	 */
X	getinfo(c_pid);
X	printf("global=%ld - expected 12, (errno=%d)\n",
X		ptrace(T_GETDATA, c_pid, (long)&global, 0L), errno);
X
X	if (ptrace(T_SETDATA, c_pid, (long)&global, 0L) == -1)
X		perror("setdata");
X	if (ptrace(T_RESUME, c_pid, 0L, 0L) == -1)
X		perror("resume");
X	getinfo(c_pid);
X	printf("global=%ld - expected 0, (errno=%d)\n",
X		ptrace(T_GETDATA, c_pid, (long)&global, 0L), errno);
X	printf("func getinfo=%lx - expected 4E56FFF2 (errno=%d)\n",
X		ptrace(T_GETINS, c_pid, (long)getinfo, 0L), errno);
X	if (ptrace(T_RESUME, c_pid, 0L, 0L) == -1)
X		perror("resume");
X
X	getinfo(c_pid);
X	if (ptrace(T_SETUSER, c_pid, 0L, 0xABCDL) == -1)
X		perror("setuser");
X	if (ptrace(T_STEP, c_pid, 0L, 0L) == -1)
X		perror("step");
X	getinfo(c_pid);
X	if (ptrace(T_STEP, c_pid, 0L, 0L) == -1)
X		perror("step");
X	getinfo(c_pid);
X	if (ptrace(T_EXIT, c_pid, 0L, 0L) == -1)
X		perror("exit");
X	getinfo(c_pid);
X}
/