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_lsys_krn_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_lsys_krn_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_lsys_krn_sys_trace.data = *(long *) ((char *) rp + (int) tr_addr); 110 break; 111 } 112 113 /* The process's proc struct is followed by its priv struct. 114 * The alignment here should be unnecessary, but better safe.. 115 */ 116 i = sizeof(long) - 1; 117 tr_addr -= (sizeof(struct proc) + i) & ~i; 118 119 if (tr_addr > sizeof(struct priv) - sizeof(long)) return(EFAULT); 120 121 m_ptr->m_lsys_krn_sys_trace.data = *(long *) ((char *) rp->p_priv + (int) tr_addr); 122 break; 123 124 case T_SETINS: /* set value in instruction space */ 125 COPYTOPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long)); 126 m_ptr->m_krn_lsys_sys_trace.data = 0; 127 break; 128 129 case T_SETDATA: /* set value in data space */ 130 COPYTOPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long)); 131 m_ptr->m_krn_lsys_sys_trace.data = 0; 132 break; 133 134 case T_SETUSER: /* set value in process table */ 135 if ((tr_addr & (sizeof(reg_t) - 1)) != 0 || 136 tr_addr > sizeof(struct stackframe_s) - sizeof(reg_t)) 137 return(EFAULT); 138 i = (int) tr_addr; 139 #if defined(__i386__) 140 /* Altering segment registers might crash the kernel when it 141 * tries to load them prior to restarting a process, so do 142 * not allow it. 143 */ 144 if (i == (int) &((struct proc *) 0)->p_reg.cs || 145 i == (int) &((struct proc *) 0)->p_reg.ds || 146 i == (int) &((struct proc *) 0)->p_reg.es || 147 i == (int) &((struct proc *) 0)->p_reg.gs || 148 i == (int) &((struct proc *) 0)->p_reg.fs || 149 i == (int) &((struct proc *) 0)->p_reg.ss) 150 return(EFAULT); 151 152 if (i == (int) &((struct proc *) 0)->p_reg.psw) 153 /* only selected bits are changeable */ 154 SETPSW(rp, tr_data); 155 else 156 *(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data; 157 #elif defined(__arm__) 158 if (i == (int) &((struct proc *) 0)->p_reg.psr) { 159 /* only selected bits are changeable */ 160 SET_USR_PSR(rp, tr_data); 161 } else { 162 *(reg_t *) ((char *) &rp->p_reg + i) = (reg_t) tr_data; 163 } 164 #endif 165 m_ptr->m_krn_lsys_sys_trace.data = 0; 166 break; 167 168 case T_DETACH: /* detach tracer */ 169 rp->p_misc_flags &= ~MF_SC_ACTIVE; 170 171 /* fall through */ 172 case T_RESUME: /* resume execution */ 173 RTS_UNSET(rp, RTS_P_STOP); 174 m_ptr->m_krn_lsys_sys_trace.data = 0; 175 break; 176 177 case T_STEP: /* set trace bit */ 178 rp->p_misc_flags |= MF_STEP; 179 RTS_UNSET(rp, RTS_P_STOP); 180 m_ptr->m_krn_lsys_sys_trace.data = 0; 181 break; 182 183 case T_SYSCALL: /* trace system call */ 184 rp->p_misc_flags |= MF_SC_TRACE; 185 RTS_UNSET(rp, RTS_P_STOP); 186 m_ptr->m_krn_lsys_sys_trace.data = 0; 187 break; 188 189 case T_READB_INS: /* get value from instruction space */ 190 COPYFROMPROC(tr_addr, (vir_bytes) &ub, 1); 191 m_ptr->m_krn_lsys_sys_trace.data = ub; 192 break; 193 194 case T_WRITEB_INS: /* set value in instruction space */ 195 ub = (unsigned char) (tr_data & 0xff); 196 COPYTOPROC(tr_addr, (vir_bytes) &ub, 1); 197 m_ptr->m_krn_lsys_sys_trace.data = 0; 198 break; 199 200 default: 201 return(EINVAL); 202 } 203 return(OK); 204 } 205 206 #endif /* USE_TRACE */ 207