|
|
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.4 ! root 32: void do_no_page(unsigned long, unsigned long, struct task_struct *, unsigned long);
1.1.1.2 root 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.4 ! root 103: do_no_page(0,addr,tsk,0);
1.1.1.3 root 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)) {
1.1.1.4 ! root 132: do_no_page(0,addr,tsk,0);
1.1.1.3 root 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:
1.1.1.4 ! root 222: int sys_ptrace(long request, long pid, long addr, long data)
1.1 root 223: {
1.1.1.2 root 224: struct task_struct *child;
225: int childno;
226:
227: if (request == 0) {
228: /* set the ptrace bit in the proccess flags. */
229: current->flags |= PF_PTRACED;
230: return 0;
231: }
232:
233: childno = get_task(pid);
1.1 root 234:
1.1.1.2 root 235: if (childno < 0)
236: return -ESRCH;
237: else
238: child = task[childno];
239:
240: if (child->p_pptr != current || !(child->flags & PF_PTRACED) ||
241: child->state != TASK_STOPPED)
242: return -ESRCH;
243:
244: switch (request) {
1.1 root 245: /* when I and D space are seperate, these will need to be fixed. */
1.1.1.2 root 246: case 1: /* read word at location addr. */
247: case 2: {
248: int tmp,res;
249:
1.1.1.3 root 250: res = read_long(task[childno], addr, &tmp);
1.1.1.2 root 251: if (res < 0)
252: return res;
253: verify_area((void *) data, 4);
254: put_fs_long(tmp,(unsigned long *) data);
255: return 0;
256: }
257:
258: /* read the word at location addr in the USER area. */
259: case 3: {
260: int tmp;
261: addr = addr >> 2; /* temporary hack. */
262: if (addr < 0 || addr >= 17)
263: return -EIO;
264: verify_area((void *) data, 4);
265: tmp = get_stack_long(child, 4*addr - MAGICNUMBER);
266: put_fs_long(tmp,(unsigned long *) data);
267: return 0;
268: }
1.1 root 269:
270: /* when I and D space are seperate, this will have to be fixed. */
1.1.1.2 root 271: case 4: /* write the word at location addr. */
272: case 5:
1.1.1.3 root 273: return write_long(task[childno],addr,data);
1.1.1.2 root 274:
275: case 6: /* write the word at location addr in the USER area */
276: addr = addr >> 2; /* temproary hack. */
277: if (addr < 0 || addr >= 17)
1.1.1.3 root 278: return -EIO;
1.1.1.2 root 279: if (addr == ORIG_EAX)
280: return -EIO;
281: if (addr == EFL) { /* flags. */
282: data &= FLAG_MASK;
283: data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
284: }
285: if (put_stack_long(child, 4*addr-MAGICNUMBER, data))
286: return -EIO;
287: return 0;
288:
289: case 7: { /* restart after signal. */
290: long tmp;
291:
292: child->signal=0;
293: if (data > 0 && data <= NSIG)
294: child->signal = 1<<(data-1);
295: child->state = 0;
1.1 root 296: /* make sure the single step bit is not set. */
1.1.1.2 root 297: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
298: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
299: return 0;
300: }
301:
302: /*
303: * make the child exit. Best I can do is send it a sigkill.
304: * perhaps it should be put in the status that it want's to
305: * exit.
306: */
307: case 8: {
308: long tmp;
309:
310: child->state = 0;
311: child->signal = 1 << (SIGKILL-1);
1.1 root 312: /* make sure the single step bit is not set. */
1.1.1.2 root 313: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
314: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
315: return 0;
316: }
317:
318: case 9: { /* set the trap flag. */
319: long tmp;
320:
321: tmp = get_stack_long(child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
322: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
323: child->state = 0;
324: child->signal = 0;
325: if (data > 0 && data <NSIG)
326: child->signal= 1<<(data-1);
1.1 root 327: /* give it a chance to run. */
1.1.1.2 root 328: return 0;
329: }
1.1 root 330:
1.1.1.2 root 331: default:
332: return -EIO;
333: }
1.1 root 334: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.