1 /* The kernel call implemented in this file: 2 * m_type: SYS_TRACE 3 * 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 10 */ 11 12 #include "kernel/system.h" 13 #include <sys/ptrace.h> 14 15 #if USE_TRACE 16 17 /*==========================================================================* 18 * do_trace * 19 *==========================================================================*/ 20 int do_trace(struct proc * caller, message * m_ptr) 21 { 22 /* Handle the debugging commands supported by the ptrace system call 23 * The commands are: 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 33 * T_EXIT exit 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 41 * 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 44 * come here. 45 */ 46 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; 52 unsigned char ub; 53 int i; 54 55 #define COPYTOPROC(addr, myaddr, length) { \ 56 struct vir_addr fromaddr, toaddr; \ 57 int r; \ 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);\ 65 return r;\ 66 } \ 67 } 68 69 #define COPYFROMPROC(addr, myaddr, length) { \ 70 struct vir_addr fromaddr, toaddr; \ 71 int r; \ 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);\ 79 return r;\ 80 } \ 81 } 82 83 if(!isokendpt(tr_proc_nr_e, &tr_proc_nr)) return(EINVAL); 84 if (iskerneln(tr_proc_nr)) return(EPERM); 85 86 rp = proc_addr(tr_proc_nr); 87 if (isemptyp(rp)) return(EINVAL); 88 switch (tr_request) { 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); 93 return(OK); 94 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; 98 break; 99 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; 103 break; 104 105 case T_GETUSER: /* return value from process table */ 106 if ((tr_addr & (sizeof(long) - 1)) != 0) return(EFAULT); 107 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); 111 break; 112 } 113 114 /* The process's proc struct is followed by its priv struct. 115 * The alignment here should be unnecessary, but better safe.. 116 */ 117 i = sizeof(long) - 1; 118 tr_addr -= (sizeof(struct proc) + i) & ~i; 119 120 if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EFAULT); 121 122 m_ptr->m_krn_lsys_sys_trace.data = 123 *(long *) ((char *) rp->p_priv + (int) tr_addr); 124 break; 125 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; 129 break; 130 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; 134 break; 135 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)) 139 return(EFAULT); 140 i = (int) tr_addr; 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 144 * not allow it. 145 */ 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) 152 return(EFAULT); 153 154 if (i == (int) &((struct proc *) 0)->p_reg.psw) 155 /* only selected bits are changeable */ 156 SETPSW(rp, tr_data); 157 else 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); 163 } else { 164 *(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data; 165 } 166 #endif 167 m_ptr->m_krn_lsys_sys_trace.data = 0; 168 break; 169 170 case T_DETACH: /* detach tracer */ 171 rp->p_misc_flags &= ~MF_SC_ACTIVE; 172 173 /* fall through */ 174 case T_RESUME: /* resume execution */ 175 RTS_UNSET(rp, RTS_P_STOP); 176 m_ptr->m_krn_lsys_sys_trace.data = 0; 177 break; 178 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; 183 break; 184 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; 189 break; 190 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; 194 break; 195 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; 200 break; 201 202 default: 203 return(EINVAL); 204 } 205 return(OK); 206 } 207 208 #endif /* USE_TRACE */ 209