1 /* The kernel call implemented in this file:
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
11 #include "kernel/system.h"
12 #include <sys/ptrace.h>
16 /*==========================================================================*
18 *==========================================================================*/
19 int do_trace(struct proc
* caller
, message
* m_ptr
)
21 /* Handle the debugging commands supported by the ptrace system call
23 * T_STOP stop the process
24 * T_OK enable tracing by parent for this process
25 * T_GETINS return value from instruction space
26 * T_GETDATA return value from data space
27 * T_GETUSER return value from user process table
28 * T_SETINS set value in instruction space
29 * T_SETDATA set value in data space
30 * T_SETUSER set value in user process table
31 * T_RESUME resume execution
33 * T_STEP set trace bit
34 * T_SYSCALL trace system call
35 * T_ATTACH attach to an existing process
36 * T_DETACH detach from a traced process
37 * T_SETOPT set trace options
38 * T_GETRANGE get range of values
39 * T_SETRANGE set range of values
41 * The T_OK, T_ATTACH, T_EXIT, and T_SETOPT commands are handled completely by
42 * the process manager. T_GETRANGE and T_SETRANGE use sys_vircopy(). All others
46 register struct proc
*rp
;
47 vir_bytes tr_addr
= (vir_bytes
) m_ptr
->CTL_ADDRESS
;
48 long tr_data
= m_ptr
->CTL_DATA
;
49 int tr_request
= m_ptr
->CTL_REQUEST
;
50 int tr_proc_nr_e
= m_ptr
->CTL_ENDPT
, tr_proc_nr
;
54 #define COPYTOPROC(addr, myaddr, length) { \
55 struct vir_addr fromaddr, toaddr; \
57 fromaddr.proc_nr_e = KERNEL; \
58 toaddr.proc_nr_e = tr_proc_nr_e; \
59 fromaddr.offset = (myaddr); \
60 toaddr.offset = (addr); \
61 if((r=virtual_copy_vmcheck(caller, &fromaddr, \
62 &toaddr, length)) != OK) { \
63 printf("Can't copy in sys_trace: %d\n", r);\
68 #define COPYFROMPROC(addr, myaddr, length) { \
69 struct vir_addr fromaddr, toaddr; \
71 fromaddr.proc_nr_e = tr_proc_nr_e; \
72 toaddr.proc_nr_e = KERNEL; \
73 fromaddr.offset = (addr); \
74 toaddr.offset = (myaddr); \
75 if((r=virtual_copy_vmcheck(caller, &fromaddr, \
76 &toaddr, length)) != OK) { \
77 printf("Can't copy in sys_trace: %d\n", r);\
82 if(!isokendpt(tr_proc_nr_e
, &tr_proc_nr
)) return(EINVAL
);
83 if (iskerneln(tr_proc_nr
)) return(EPERM
);
85 rp
= proc_addr(tr_proc_nr
);
86 if (isemptyp(rp
)) return(EINVAL
);
88 case T_STOP
: /* stop process */
89 RTS_SET(rp
, RTS_P_STOP
);
90 rp
->p_reg
.psw
&= ~TRACEBIT
; /* clear trace bit */
91 rp
->p_misc_flags
&= ~MF_SC_TRACE
; /* clear syscall trace flag */
94 case T_GETINS
: /* return value from instruction space */
95 COPYFROMPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
96 m_ptr
->CTL_DATA
= tr_data
;
99 case T_GETDATA
: /* return value from data space */
100 COPYFROMPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
101 m_ptr
->CTL_DATA
= tr_data
;
104 case T_GETUSER
: /* return value from process table */
105 if ((tr_addr
& (sizeof(long) - 1)) != 0) return(EFAULT
);
107 if (tr_addr
<= sizeof(struct proc
) - sizeof(long)) {
108 m_ptr
->CTL_DATA
= *(long *) ((char *) rp
+ (int) tr_addr
);
112 /* The process's proc struct is followed by its priv struct.
113 * The alignment here should be unnecessary, but better safe..
115 i
= sizeof(long) - 1;
116 tr_addr
-= (sizeof(struct proc
) + i
) & ~i
;
118 if (tr_addr
> sizeof(struct priv
) - sizeof(long)) return(EFAULT
);
120 m_ptr
->CTL_DATA
= *(long *) ((char *) rp
->p_priv
+ (int) tr_addr
);
123 case T_SETINS
: /* set value in instruction space */
124 COPYTOPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
128 case T_SETDATA
: /* set value in data space */
129 COPYTOPROC(tr_addr
, (vir_bytes
) &tr_data
, sizeof(long));
133 case T_SETUSER
: /* set value in process table */
134 if ((tr_addr
& (sizeof(reg_t
) - 1)) != 0 ||
135 tr_addr
> sizeof(struct stackframe_s
) - sizeof(reg_t
))
138 #if defined(__i386__)
139 /* Altering segment registers might crash the kernel when it
140 * tries to load them prior to restarting a process, so do
143 if (i
== (int) &((struct proc
*) 0)->p_reg
.cs
||
144 i
== (int) &((struct proc
*) 0)->p_reg
.ds
||
145 i
== (int) &((struct proc
*) 0)->p_reg
.es
||
146 i
== (int) &((struct proc
*) 0)->p_reg
.gs
||
147 i
== (int) &((struct proc
*) 0)->p_reg
.fs
||
148 i
== (int) &((struct proc
*) 0)->p_reg
.ss
)
151 if (i
== (int) &((struct proc
*) 0)->p_reg
.psw
)
152 /* only selected bits are changeable */
155 *(reg_t
*) ((char *) &rp
->p_reg
+ i
) = (reg_t
) tr_data
;
159 case T_DETACH
: /* detach tracer */
160 rp
->p_misc_flags
&= ~MF_SC_ACTIVE
;
163 case T_RESUME
: /* resume execution */
164 RTS_UNSET(rp
, RTS_P_STOP
);
168 case T_STEP
: /* set trace bit */
169 rp
->p_reg
.psw
|= TRACEBIT
;
170 RTS_UNSET(rp
, RTS_P_STOP
);
174 case T_SYSCALL
: /* trace system call */
175 rp
->p_misc_flags
|= MF_SC_TRACE
;
176 RTS_UNSET(rp
, RTS_P_STOP
);
180 case T_READB_INS
: /* get value from instruction space */
181 COPYFROMPROC(tr_addr
, (vir_bytes
) &ub
, 1);
182 m_ptr
->CTL_DATA
= ub
;
185 case T_WRITEB_INS
: /* set value in instruction space */
186 ub
= (unsigned char) (tr_data
& 0xff);
187 COPYTOPROC(tr_addr
, (vir_bytes
) &ub
, 1);
197 #endif /* USE_TRACE */