1 /* The kernel call implemented in this file:
4 * The parameters for this kernel call are:
5 * m_lsys_krn_sys_trace.endpt process that is traced
6 * m_lsys_krn_sys_trace.request trace request
7 * m_lsys_krn_sys_trace.address address at traced process' space
8 * m_lsys_krn_sys_trace.data data to be written
9 * m_krn_lsys_sys_trace.data data to be returned
12 #include "kernel/system.h"
13 #include <sys/ptrace.h>
17 /*==========================================================================*
19 *==========================================================================*/
20 int do_trace(struct proc
* caller
, message
* m_ptr
)
22 /* Handle the debugging commands supported by the ptrace system call
24 * T_STOP stop the process
25 * T_OK enable tracing by parent for this process
26 * T_GETINS return value from instruction space
27 * T_GETDATA return value from data space
28 * T_GETUSER return value from user process table
29 * T_SETINS set value in instruction space
30 * T_SETDATA set value in data space
31 * T_SETUSER set value in user process table
32 * T_RESUME resume execution
34 * T_STEP set trace bit
35 * T_SYSCALL trace system call
36 * T_ATTACH attach to an existing process
37 * T_DETACH detach from a traced process
38 * T_SETOPT set trace options
39 * T_GETRANGE get range of values
40 * T_SETRANGE set range of values
42 * The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled completely by
43 * the process manager. T_GETRANGE and T_SETRANGE use sys_vircopy(). All others
47 register struct proc
*rp
;
48 vir_bytes tr_addr
= m_ptr
->m_lsys_krn_sys_trace
.address
;
49 long tr_data
= m_ptr
->m_lsys_krn_sys_trace
.data
;
50 int tr_request
= m_ptr
->m_lsys_krn_sys_trace
.request
;
51 int tr_proc_nr_e
= m_ptr
->m_lsys_krn_sys_trace
.endpt
, tr_proc_nr
;
55 #define COPYTOPROC(addr, myaddr, length) { \
56 struct vir_addr fromaddr, toaddr; \
58 fromaddr.proc_nr_e = KERNEL; \
59 toaddr.proc_nr_e = tr_proc_nr_e; \
60 fromaddr.offset = (myaddr); \
61 toaddr.offset = (addr); \
62 if((r=virtual_copy_vmcheck(caller, &fromaddr, \
63 &toaddr, length)) != OK) { \
64 printf("Can't copy in sys_trace: %d\n", r);\
69 #define COPYFROMPROC(addr, myaddr, length) { \
70 struct vir_addr fromaddr, toaddr; \
72 fromaddr.proc_nr_e = tr_proc_nr_e; \
73 toaddr.proc_nr_e = KERNEL; \
74 fromaddr.offset = (addr); \
75 toaddr.offset = (myaddr); \
76 if((r=virtual_copy_vmcheck(caller, &fromaddr, \
77 &toaddr, length)) != OK) { \
78 printf("Can't copy in sys_trace: %d\n", r);\
83 if(!isokendpt(tr_proc_nr_e
, &tr_proc_nr
)) return(EINVAL
);
84 if (iskerneln(tr_proc_nr
)) return(EPERM
);
86 rp
= proc_addr(tr_proc_nr
);
87 if (isemptyp(rp
)) return(EINVAL
);
89 case T_STOP
: /* stop process */
90 RTS_SET(rp
, RTS_P_STOP
);
91 /* clear syscall trace and single step flags */
92 rp
->p_misc_flags
&= ~(MF_SC_TRACE
| MF_STEP
);
95 case T_GETINS
: /* return value from instruction space */
96 COPYFROMPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
97 m_ptr
->m_krn_lsys_sys_trace
.data
= tr_data
;
100 case T_GETDATA
: /* return value from data space */
101 COPYFROMPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
102 m_ptr
->m_krn_lsys_sys_trace
.data
= tr_data
;
105 case T_GETUSER
: /* return value from process table */
106 if ((tr_addr
& (sizeof(long) - 1)) != 0) return(EFAULT
);
108 if (tr_addr
<= sizeof(struct proc
) - sizeof(long)) {
109 m_ptr
->m_krn_lsys_sys_trace
.data
=
110 *(long *) ((char *) rp
+ (int) tr_addr
);
114 /* The process's proc struct is followed by its priv struct.
115 * The alignment here should be unnecessary, but better safe..
117 i
= sizeof(long) - 1;
118 tr_addr
-= (sizeof(struct proc
) + i
) & ~i
;
120 if (tr_addr
> sizeof(struct priv
) - sizeof(long)) return(EFAULT
);
122 m_ptr
->m_krn_lsys_sys_trace
.data
=
123 *(long *) ((char *) rp
->p_priv
+ (int) tr_addr
);
126 case T_SETINS
: /* set value in instruction space */
127 COPYTOPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
128 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
131 case T_SETDATA
: /* set value in data space */
132 COPYTOPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
133 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
136 case T_SETUSER
: /* set value in process table */
137 if ((tr_addr
& (sizeof(reg_t
) - 1)) != 0 ||
138 tr_addr
> sizeof(struct stackframe_s
) - sizeof(reg_t
))
141 #if defined(__i386__)
142 /* Altering segment registers might crash the kernel when it
143 * tries to load them prior to restarting a process, so do
146 if (i
== (int) &((struct proc
*) 0)->p_reg
.cs
||
147 i
== (int) &((struct proc
*) 0)->p_reg
.ds
||
148 i
== (int) &((struct proc
*) 0)->p_reg
.es
||
149 i
== (int) &((struct proc
*) 0)->p_reg
.gs
||
150 i
== (int) &((struct proc
*) 0)->p_reg
.fs
||
151 i
== (int) &((struct proc
*) 0)->p_reg
.ss
)
154 if (i
== (int) &((struct proc
*) 0)->p_reg
.psw
)
155 /* only selected bits are changeable */
158 *(reg_t
*) ((char *) &rp
->p_reg
+ i
) = (reg_t
) tr_data
;
159 #elif defined(__arm__)
160 if (i
== (int) &((struct proc
*) 0)->p_reg
.psr
) {
161 /* only selected bits are changeable */
162 SET_USR_PSR(rp
, tr_data
);
164 *(reg_t
*) ((char *) &rp
->p_reg
+ i
) = (reg_t
) tr_data
;
167 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
170 case T_DETACH
: /* detach tracer */
171 rp
->p_misc_flags
&= ~MF_SC_ACTIVE
;
174 case T_RESUME
: /* resume execution */
175 RTS_UNSET(rp
, RTS_P_STOP
);
176 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
179 case T_STEP
: /* set trace bit */
180 rp
->p_misc_flags
|= MF_STEP
;
181 RTS_UNSET(rp
, RTS_P_STOP
);
182 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
185 case T_SYSCALL
: /* trace system call */
186 rp
->p_misc_flags
|= MF_SC_TRACE
;
187 RTS_UNSET(rp
, RTS_P_STOP
);
188 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
191 case T_READB_INS
: /* get value from instruction space */
192 COPYFROMPROC(tr_addr
, (vir_bytes
) &ub
, 1);
193 m_ptr
->m_krn_lsys_sys_trace
.data
= ub
;
196 case T_WRITEB_INS
: /* set value in instruction space */
197 ub
= (unsigned char) (tr_data
& 0xff);
198 COPYTOPROC(tr_addr
, (vir_bytes
) &ub
, 1);
199 m_ptr
->m_krn_lsys_sys_trace
.data
= 0;
208 #endif /* USE_TRACE */