|
|
1.1 root 1: /* ptrace.c */
2: /* By Ross Biro 1/23/92 */
1.1.1.3 ! root 3: /* edited by Linus Torvalds */
1.1 root 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>
1.1.1.2 root 13:
14: /*
15: * does not yet catch signals sent when the child dies.
16: * in exit.c or in signal.c.
17: */
1.1 root 18:
19: /* determines which flags the user has access to. */
20: /* 1 = access 0 = no access */
21: #define FLAG_MASK 0x00000dd9
22:
23: /* set's the trap flag. */
24: #define TRAP_FLAG 0x100
25:
1.1.1.2 root 26: /*
27: * this is the number to subtract from the top of the stack. To find
28: * the local frame.
29: */
1.1 root 30: #define MAGICNUMBER 68
31:
1.1.1.2 root 32: void do_no_page(unsigned long, unsigned long, struct task_struct *);
33: void write_verify(unsigned long);
1.1 root 34:
35: /* change a pid into a task struct. */
36: static inline int get_task(int pid)
37: {
1.1.1.2 root 38: int i;
39:
40: for (i = 0; i < NR_TASKS; i++) {
41: if (task[i] != NULL && (task[i]->pid == pid))
42: return i;
43: }
44: return -1;
1.1 root 45: }
46:
1.1.1.2 root 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.
1.1.1.3 ! root 52: */
1.1.1.2 root 53: static inline int get_stack_long(struct task_struct *task, int offset)
1.1 root 54: {
1.1.1.2 root 55: unsigned char *stack;
1.1 root 56:
1.1.1.2 root 57: stack = (unsigned char *)task->tss.esp0;
58: stack += offset;
59: return (*((int *)stack));
1.1 root 60: }
61:
1.1.1.2 root 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: static inline int put_stack_long(struct task_struct *task, int offset,
1.1.1.3 ! root 69: unsigned long data)
1.1 root 70: {
1.1.1.2 root 71: unsigned char * stack;
1.1 root 72:
1.1.1.2 root 73: stack = (unsigned char *) task->tss.esp0;
74: stack += offset;
1.1.1.3 ! root 75: *(unsigned long *) stack = data;
1.1.1.2 root 76: return 0;
1.1 root 77: }
78:
1.1.1.2 root 79: /*
1.1.1.3 ! root 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.
1.1.1.2 root 87: */
1.1.1.3 ! root 88: static unsigned long get_long(struct task_struct * tsk,
! 89: unsigned long addr)
1.1 root 90: {
1.1.1.2 root 91: unsigned long page;
92:
1.1.1.3 ! root 93: addr += tsk->start_code;
! 94: repeat:
! 95: page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
! 96: page = *(unsigned long *) page;
! 97: if (page & PAGE_PRESENT) {
! 98: page &= 0xfffff000;
! 99: page += (addr >> 10) & 0xffc;
! 100: page = *((unsigned long *) page);
1.1.1.2 root 101: }
102: if (!(page & PAGE_PRESENT)) {
1.1.1.3 ! root 103: do_no_page(0,addr,tsk);
! 104: goto repeat;
1.1.1.2 root 105: }
1.1.1.3 ! root 106: page &= 0xfffff000;
! 107: page += addr & 0xfff;
! 108: return *(unsigned long *) page;
1.1 root 109: }
110:
1.1.1.2 root 111: /*
1.1.1.3 ! root 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.
1.1.1.2 root 116: */
1.1.1.3 ! root 117: static void put_long(struct task_struct * tsk, unsigned long addr,
! 118: unsigned long data)
1.1 root 119: {
1.1.1.2 root 120: unsigned long page;
121:
1.1.1.3 ! root 122: addr += tsk->start_code;
! 123: repeat:
! 124: page = tsk->tss.cr3 + ((addr >> 20) & 0xffc);
! 125: page = *(unsigned long *) page;
! 126: if (page & PAGE_PRESENT) {
! 127: page &= 0xfffff000;
! 128: page += (addr >> 10) & 0xffc;
! 129: page = *((unsigned long *) page);
! 130: }
! 131: if (!(page & PAGE_PRESENT)) {
! 132: do_no_page(0,addr,tsk);
! 133: goto repeat;
1.1.1.2 root 134: }
1.1.1.3 ! root 135: if (!(page & PAGE_RW)) {
! 136: write_verify(addr);
! 137: goto repeat;
1.1.1.2 root 138: }
1.1.1.3 ! root 139: page &= 0xfffff000;
! 140: page += addr & 0xfff;
! 141: *(unsigned long *) page = data;
! 142: }
1.1 root 143:
1.1.1.3 ! root 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: static int read_long(struct task_struct * tsk, unsigned long addr,
! 149: unsigned long * result)
! 150: {
! 151: unsigned long low,high;
1.1 root 152:
1.1.1.3 ! root 153: if (addr > TASK_SIZE-4)
1.1.1.2 root 154: return -EIO;
1.1.1.3 ! root 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: }
1.1 root 177:
1.1.1.3 ! root 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: static int write_long(struct task_struct * tsk, unsigned long addr,
! 183: unsigned long data)
! 184: {
! 185: unsigned long low,high;
1.1 root 186:
1.1.1.3 ! root 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);
1.1.1.2 root 219: return 0;
1.1 root 220: }
221:
222: /* Perform ptrace(request, pid, addr, data) syscall */
1.1.1.2 root 223: int sys_ptrace(unsigned long *buffer)
1.1 root 224: {
1.1.1.2 root 225: long request, pid, data;
226: long addr;
227: struct task_struct *child;
228: int childno;
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);
1.1 root 242:
1.1.1.2 root 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) {
1.1 root 253: /* when I and D space are seperate, these will need to be fixed. */
1.1.1.2 root 254: case 1: /* read word at location addr. */
255: case 2: {
256: int tmp,res;
257:
1.1.1.3 ! root 258: res = read_long(task[childno], addr, &tmp);
1.1.1.2 root 259: if (res < 0)
260: return res;
261: verify_area((void *) data, 4);
262: put_fs_long(tmp,(unsigned long *) data);
263: return 0;
264: }
265:
266: /* read the word at location addr in the USER area. */
267: case 3: {
268: int tmp;
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,(unsigned long *) data);
275: return 0;
276: }
1.1 root 277:
278: /* when I and D space are seperate, this will have to be fixed. */
1.1.1.2 root 279: case 4: /* write the word at location addr. */
280: case 5:
1.1.1.3 ! root 281: return write_long(task[childno],addr,data);
1.1.1.2 root 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)
1.1.1.3 ! root 286: return -EIO;
1.1.1.2 root 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: long tmp;
299:
300: child->signal=0;
301: if (data > 0 && data <= NSIG)
302: child->signal = 1<<(data-1);
303: child->state = 0;
1.1 root 304: /* make sure the single step bit is not set. */
1.1.1.2 root 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: long tmp;
317:
318: child->state = 0;
319: child->signal = 1 << (SIGKILL-1);
1.1 root 320: /* make sure the single step bit is not set. */
1.1.1.2 root 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: long tmp;
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);
1.1 root 335: /* give it a chance to run. */
1.1.1.2 root 336: return 0;
337: }
1.1 root 338:
1.1.1.2 root 339: default:
340: return -EIO;
341: }
1.1 root 342: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.