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