Reported by Erik van der Kouwe <vdkouwe at cs.vu.nl>:
[minix.git] / kernel / system / do_trace.c
blob0e12f0ba5fdacd0eb417b213827c54dbbe0c4c52
1 /* The kernel call implemented in this file:
2 * m_type: SYS_TRACE
4 * The parameters for this kernel call are:
5 * m2_i1: CTL_ENDPT process that is traced
6 * m2_i2: CTL_REQUEST trace request
7 * m2_l1: CTL_ADDRESS address at traced process' space
8 * m2_l2: CTL_DATA data to be written or returned here
9 */
11 #include "../system.h"
12 #include <sys/ptrace.h>
14 #if USE_TRACE
16 /*==========================================================================*
17 * do_trace *
18 *==========================================================================*/
19 #define TR_VLSIZE ((vir_bytes) sizeof(long))
21 PUBLIC int do_trace(m_ptr)
22 register message *m_ptr;
24 /* Handle the debugging commands supported by the ptrace system call
25 * The commands are:
26 * T_STOP stop the process
27 * T_OK enable tracing by parent for this process
28 * T_GETINS return value from instruction space
29 * T_GETDATA return value from data space
30 * T_GETUSER return value from user process table
31 * T_SETINS set value from instruction space
32 * T_SETDATA set value from data space
33 * T_SETUSER set value in user process table
34 * T_RESUME resume execution
35 * T_EXIT exit
36 * T_STEP set trace bit
38 * The T_OK and T_EXIT commands are handled completely by the process manager,
39 * all others come here.
42 register struct proc *rp;
43 phys_bytes src, dst;
44 vir_bytes tr_addr = (vir_bytes) m_ptr->CTL_ADDRESS;
45 long tr_data = m_ptr->CTL_DATA;
46 int tr_request = m_ptr->CTL_REQUEST;
47 int tr_proc_nr_e = m_ptr->CTL_ENDPT, tr_proc_nr;
48 unsigned char ub;
49 int i;
51 if(!isokendpt(tr_proc_nr_e, &tr_proc_nr)) return(EINVAL);
52 if (iskerneln(tr_proc_nr)) return(EPERM);
54 rp = proc_addr(tr_proc_nr);
55 if (isemptyp(rp)) return(EIO);
56 switch (tr_request) {
57 case T_STOP: /* stop process */
58 RTS_LOCK_SET(rp, P_STOP);
59 rp->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
60 return(OK);
62 case T_GETINS: /* return value from instruction space */
63 if (rp->p_memmap[T].mem_len != 0) {
64 if ((src = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO);
65 phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long));
66 m_ptr->CTL_DATA = tr_data;
67 break;
69 /* Text space is actually data space - fall through. */
71 case T_GETDATA: /* return value from data space */
72 if ((src = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO);
73 phys_copy(src, vir2phys(&tr_data), (phys_bytes) sizeof(long));
74 m_ptr->CTL_DATA= tr_data;
75 break;
77 case T_GETUSER: /* return value from process table */
78 if ((tr_addr & (sizeof(long) - 1)) != 0 ||
79 tr_addr > sizeof(struct proc) - sizeof(long))
80 return(EIO);
81 m_ptr->CTL_DATA = *(long *) ((char *) rp + (int) tr_addr);
82 break;
84 case T_SETINS: /* set value in instruction space */
85 if (rp->p_memmap[T].mem_len != 0) {
86 if ((dst = umap_local(rp, T, tr_addr, TR_VLSIZE)) == 0) return(EIO);
87 phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long));
88 m_ptr->CTL_DATA = 0;
89 break;
91 /* Text space is actually data space - fall through. */
93 case T_SETDATA: /* set value in data space */
94 if ((dst = umap_local(rp, D, tr_addr, TR_VLSIZE)) == 0) return(EIO);
95 phys_copy(vir2phys(&tr_data), dst, (phys_bytes) sizeof(long));
96 m_ptr->CTL_DATA = 0;
97 break;
99 case T_SETUSER: /* set value in process table */
100 if ((tr_addr & (sizeof(reg_t) - 1)) != 0 ||
101 tr_addr > sizeof(struct stackframe_s) - sizeof(reg_t))
102 return(EIO);
103 i = (int) tr_addr;
104 #if (_MINIX_CHIP == _CHIP_INTEL)
105 /* Altering segment registers might crash the kernel when it
106 * tries to load them prior to restarting a process, so do
107 * not allow it.
109 if (i == (int) &((struct proc *) 0)->p_reg.cs ||
110 i == (int) &((struct proc *) 0)->p_reg.ds ||
111 i == (int) &((struct proc *) 0)->p_reg.es ||
112 #if _WORD_SIZE == 4
113 i == (int) &((struct proc *) 0)->p_reg.gs ||
114 i == (int) &((struct proc *) 0)->p_reg.fs ||
115 #endif
116 i == (int) &((struct proc *) 0)->p_reg.ss)
117 return(EIO);
118 #endif
119 if (i == (int) &((struct proc *) 0)->p_reg.psw)
120 /* only selected bits are changeable */
121 SETPSW(rp, tr_data);
122 else
123 *(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data;
124 m_ptr->CTL_DATA = 0;
125 break;
127 case T_RESUME: /* resume execution */
128 RTS_LOCK_UNSET(rp, P_STOP);
129 m_ptr->CTL_DATA = 0;
130 break;
132 case T_STEP: /* set trace bit */
133 rp->p_reg.psw |= TRACEBIT;
134 RTS_LOCK_UNSET(rp, P_STOP);
135 m_ptr->CTL_DATA = 0;
136 break;
138 case T_READB_INS: /* get value from instruction space */
139 if (rp->p_memmap[T].mem_len != 0) {
140 if ((dst = umap_local(rp, T, tr_addr, 1)) == 0) return(EFAULT);
141 phys_copy(dst, vir2phys(&ub), (phys_bytes) 1);
142 m_ptr->CTL_DATA = ub;
143 break;
146 if ((dst = umap_local(rp, D, tr_addr, 1)) == 0) return(EFAULT);
147 phys_copy(dst, vir2phys(&ub), (phys_bytes) 1);
148 m_ptr->CTL_DATA = ub;
149 break;
151 case T_WRITEB_INS: /* set value in instruction space */
152 if (rp->p_memmap[T].mem_len != 0) {
153 if ((dst = umap_local(rp, T, tr_addr, 1)) == 0) return(EFAULT);
154 phys_copy(vir2phys(&tr_data), dst, (phys_bytes) 1);
155 m_ptr->CTL_DATA = 0;
156 break;
159 if ((dst = umap_local(rp, D, tr_addr, 1)) == 0) return(EFAULT);
160 phys_copy(vir2phys(&tr_data), dst, (phys_bytes) 1);
161 m_ptr->CTL_DATA = 0;
162 break;
164 default:
165 return(EIO);
167 return(OK);
170 #endif /* USE_TRACE */