1 /* ptrace.c */ 2 /* By Ross Biro 1/23/92 */ 3 /* edited by Linus Torvalds */ 4
5 #include <linux/head.h>
6 #include <linux/kernel.h>
7 #include <linux/sched.h>
8 #include <linux/mm.h>
9 #include <errno.h>
10 #include <asm/segment.h>
11 #include <asm/system.h>
12 #include <sys/ptrace.h>
13
14 /* 15 * does not yet catch signals sent when the child dies. 16 * in exit.c or in signal.c. 17 */ 18
19 /* determines which flags the user has access to. */ 20 /* 1 = access 0 = no access */ 21 #defineFLAG_MASK 0x00000dd9
22
23 /* set's the trap flag. */ 24 #defineTRAP_FLAG 0x100
25
26 /* 27 * this is the number to subtract from the top of the stack. To find 28 * the local frame. 29 */ 30 #defineMAGICNUMBER 68
31
32 voiddo_no_page(unsignedlong, unsignedlong, structtask_struct *);
33 voidwrite_verify(unsignedlong);
34
35 /* change a pid into a task struct. */ 36 staticinlineintget_task(intpid)
/* */ 37 { 38 inti;
39
40 for (i = 0; i < NR_TASKS; i++) { 41 if (task[i] != NULL && (task[i]->pid == pid))
42 returni;
43 } 44 return -1;
45 } 46
47 /* 48 * this routine will get a word off of the processes priviledged stack. 49 * the offset is how far from the base addr as stored in the TSS. 50 * this routine assumes that all the priviledged stacks are in our 51 * data space. 52 */ 53 staticinlineintget_stack_long(structtask_struct *task, intoffset)
/* */ 54 { 55 unsignedchar *stack;
56
57 stack = (unsignedchar *)task->tss.esp0;
58 stack += offset;
59 return (*((int *)stack));
60 } 61
62 /* 63 * this routine will put a word on the processes priviledged stack. 64 * the offset is how far from the base addr as stored in the TSS. 65 * this routine assumes that all the priviledged stacks are in our 66 * data space. 67 */ 68 staticinlineintput_stack_long(structtask_struct *task, intoffset,
/* */ 69 unsignedlongdata)
70 { 71 unsignedchar * stack;
72
73 stack = (unsignedchar *) task->tss.esp0;
74 stack += offset;
75 *(unsignedlong *) stack = data;
76 return 0;
77 } 78
79 /* 80 * This routine gets a long from any process space by following the page 81 * tables. NOTE! You should check that the long isn't on a page boundary, 82 * and that it is in the task area before calling this: this routine does 83 * no checking. 84 * 85 * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always 86 * zero. This routine shouldn't have to change when we make a better mm. 87 */ 88 staticunsignedlongget_long(structtask_struct * tsk,
/* */ 89 unsignedlongaddr)
90 { 91 unsignedlongpage;
92
93 addr += tsk->start_code;
94 repeat:
95 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
96 page = *(unsignedlong *) page;
97 if (page & PAGE_PRESENT) { 98 page &= 0xfffff000;
99 page += (addr >> 10) & 0xffc;
100 page = *((unsignedlong *) page);
101 } 102 if (!(page & PAGE_PRESENT)) { 103 do_no_page(0,addr,tsk);
104 gotorepeat;
105 } 106 page &= 0xfffff000;
107 page += addr & 0xfff;
108 return *(unsignedlong *) page;
109 } 110
111 /* 112 * This routine puts a long into any process space by following the page 113 * tables. NOTE! You should check that the long isn't on a page boundary, 114 * and that it is in the task area before calling this: this routine does 115 * no checking. 116 */ 117 staticvoidput_long(structtask_struct * tsk, unsignedlongaddr,
/* */ 118 unsignedlongdata)
119 { 120 unsignedlongpage;
121
122 addr += tsk->start_code;
123 repeat:
124 page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
125 page = *(unsignedlong *) page;
126 if (page & PAGE_PRESENT) { 127 page &= 0xfffff000;
128 page += (addr >> 10) & 0xffc;
129 page = *((unsignedlong *) page);
130 } 131 if (!(page & PAGE_PRESENT)) { 132 do_no_page(0,addr,tsk);
133 gotorepeat;
134 } 135 if (!(page & PAGE_RW)) { 136 write_verify(addr);
137 gotorepeat;
138 } 139 page &= 0xfffff000;
140 page += addr & 0xfff;
141 *(unsignedlong *) page = data;
142 } 143
144 /* 145 * This routine checks the page boundaries, and that the offset is 146 * within the task area. It then calls get_long() to read a long. 147 */ 148 staticintread_long(structtask_struct * tsk, unsignedlongaddr,
/* */ 149 unsignedlong * result)
150 { 151 unsignedlonglow,high;
152
153 if (addr > TASK_SIZE-4)
154 return -EIO;
155 if ((addr & 0xfff) > PAGE_SIZE-4) { 156 low = get_long(tsk,addr & 0xfffffffc);
157 high = get_long(tsk,(addr+4) & 0xfffffffc);
158 switch (addr & 3) { 159 case 1:
160 low >>= 8;
161 low |= high << 24;
162 break;
163 case 2:
164 low >>= 16;
165 low |= high << 16;
166 break;
167 case 3:
168 low >>= 24;
169 low |= high << 8;
170 break;
171 } 172 *result = low;
173 }else 174 *result = get_long(tsk,addr);
175 return 0;
176 } 177
178 /* 179 * This routine checks the page boundaries, and that the offset is 180 * within the task area. It then calls put_long() to write a long. 181 */ 182 staticintwrite_long(structtask_struct * tsk, unsignedlongaddr,
/* */ 183 unsignedlongdata)
184 { 185 unsignedlonglow,high;
186
187 if (addr > TASK_SIZE-4)
188 return -EIO;
189 if ((addr & 0xfff) > PAGE_SIZE-4) { 190 low = get_long(tsk,addr & 0xfffffffc);
191 high = get_long(tsk,(addr+4) & 0xfffffffc);
192 switch (addr & 3) { 193 case 0: /* shouldn't happen, but safety first */ 194 low = data;
195 break;
196 case 1:
197 low &= 0x000000ff;
198 low |= data << 8;
199 high &= 0xffffff00;
200 high |= data >> 24;
201 break;
202 case 2:
203 low &= 0x0000ffff;
204 low |= data << 16;
205 high &= 0xffff0000;
206 high |= data >> 16;
207 break;
208 case 3:
209 low &= 0x00ffffff;
210 low |= data << 24;
211 high &= 0xff000000;
212 high |= data >> 8;
213 break;
214 } 215 put_long(tsk,addr & 0xfffffffc,low);
216 put_long(tsk,(addr+4) & 0xfffffffc,high);
217 }else 218 put_long(tsk,addr,data);
219 return 0;
220 } 221
222 /* Perform ptrace(request, pid, addr, data) syscall */ 223 intsys_ptrace(unsignedlong *buffer)
/* */ 224 { 225 longrequest, pid, data;
226 longaddr;
227 structtask_struct *child;
228 intchildno;
229
230 request = get_fs_long(buffer++);
231 pid = get_fs_long(buffer++);
232 addr = get_fs_long(buffer++); /* assume long = void * */ 233 data = get_fs_long(buffer++);
234
235 if (request == 0) { 236 /* set the ptrace bit in the proccess flags. */ 237 current->flags |= PF_PTRACED;
238 return 0;
239 } 240
241 childno = get_task(pid);
242
243 if (childno < 0)
244 return -ESRCH;
245 else 246 child = task[childno];
247
248 if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
249 child->state != TASK_STOPPED)
250 return -ESRCH;
251
252 switch (request) { 253 /* when I and D space are seperate, these will need to be fixed. */ 254 case 1: /* read word at location addr. */ 255 case 2: { 256 inttmp,res;
257
258 res = read_long(task[childno], addr, &tmp);
259 if (res < 0)
260 returnres;
261 verify_area((void *) data, 4);
262 put_fs_long(tmp,(unsignedlong *) data);
263 return 0;
264 } 265
266 /* read the word at location addr in the USER area. */ 267 case 3: { 268 inttmp;
269 addr = addr >> 2; /* temporary hack. */ 270 if (addr < 0 || addr >= 17)
271 return -EIO;
272 verify_area((void *) data, 4);
273 tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
274 put_fs_long(tmp,(unsignedlong *) data);
275 return 0;
276 } 277
278 /* when I and D space are seperate, this will have to be fixed. */ 279 case 4: /* write the word at location addr. */ 280 case 5:
281 returnwrite_long(task[childno],addr,data);
282
283 case 6: /* write the word at location addr in the USER area */ 284 addr = addr >> 2; /* temproary hack. */ 285 if (addr < 0 || addr >= 17)
286 return -EIO;
287 if (addr == ORIG_EAX)
288 return -EIO;
289 if (addr == EFL) {/* flags. */ 290 data &= FLAG_MASK;
291 data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
292 } 293 if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
294 return -EIO;
295 return 0;
296
297 case 7: {/* restart after signal. */ 298 longtmp;
299
300 child->signal=0;
301 if (data > 0 && data <= NSIG)
302 child->signal = 1<<(data-1);
303 child->state = 0;
304 /* make sure the single step bit is not set. */ 305 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
306 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
307 return 0;
308 } 309
310 /* 311 * make the child exit. Best I can do is send it a sigkill. 312 * perhaps it should be put in the status that it want's to 313 * exit. 314 */ 315 case 8: { 316 longtmp;
317
318 child->state = 0;
319 child->signal = 1 << (SIGKILL-1);
320 /* make sure the single step bit is not set. */ 321 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
322 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
323 return 0;
324 } 325
326 case 9: {/* set the trap flag. */ 327 longtmp;
328
329 tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
330 put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
331 child->state = 0;
332 child->signal = 0;
333 if (data > 0 && data <NSIG)
334 child->signal= 1<<(data-1);
335 /* give it a chance to run. */ 336 return 0;
337 } 338
339 default:
340 return -EIO;
341 } 342 }