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} /