|
|
1.1 root 1: /* ptrace.c */
2: /* By Ross Biro 1/23/92 */
3:
4: #include <linux/head.h>
5: #include <linux/kernel.h>
6: #include <linux/sched.h>
7: #include <linux/mm.h>
8: #include <errno.h>
9: #include <asm/segment.h>
10: #include <asm/system.h>
11: #include <sys/ptrace.h>
12: /* does not yet catch signals sent when the child dies. in
13: exit.c or in signal.c. */
14:
15: /* determines which flags the user has access to. */
16: /* 1 = access 0 = no access */
17: #define FLAG_MASK 0x00000dd9
18:
19: /* set's the trap flag. */
20: #define TRAP_FLAG 0x100
21:
22: /* check's for granularity. */
23: #define GRANULARITY 0x00800000
24:
25: /* this is the number to subtract from the top of the stack. To find
26: the local frame. */
27:
28: #define MAGICNUMBER 68
29:
30: void do_no_page (unsigned long, unsigned long, struct task_struct *);
31: void write_verify (unsigned long);
32:
33: /* change a pid into a task struct. */
34: static inline int get_task(int pid)
35: {
36: int i;
37: for (i =0; i < NR_TASKS; i++)
38: {
39: if (task[i] != NULL && (task[i]->pid == pid)) return (i);
40: }
41: return (-1);
42: }
43:
44: /* this routine will get a word off of the processes priviledged stack.
45: the offset is how far from the base addr as stored in the TSS.
46: this routine assumes that all the priviledged stacks are in our
47: data space. */
48:
49: static inline int
50: get_stack_long(struct task_struct *task, int offset)
51: {
52: unsigned char *stack;
53: stack = (unsigned char *)task->tss.esp0;
54: stack += offset;
55: return (*((int *)stack));
56:
57: }
58:
59: /* this routine will put a word on the processes priviledged stack.
60: the offset is how far from the base addr as stored in the TSS.
61: this routine assumes that all the priviledged stacks are in our
62: data space. */
63:
64: static inline int
65: put_stack_long(struct task_struct *task, int offset, unsigned short data)
66: {
67: unsigned char *stack;
68: stack = (unsigned char *)task->tss.esp0;
69: stack += offset;
70: *(int *)stack = data;
71: return (0);
72:
73: }
74:
75: /* this routine will get a word out of an arbitrary
76: tasks data space. It likes to have the task number
77: rather than the task pointer. Perhaps the number
78: should be included in the pointer. */
79: /* seg = 0 if I space */
80: static inline int get_long (int tsk, long addr, unsigned seg, int *data)
81: {
82: int i;
83: int limit;
84: int cur;
85: unsigned long address;
86: unsigned long page;
87: unsigned oldfs;
88: /* find the task number of the current task. */
89: for (i = 0; i < NR_TASKS ; i ++)
90: {
91: if (task[i] == current) break;
92: }
93: if (i == NR_TASKS)
94: {
95: panic ("PTRACE: Can't find current task\n");
96: }
97: cur = i;
98:
99: /* we will need to check the redaability of the segment
100: and then the byte in order to avoid segment violations. */
101: seg++;
102: limit=(task[tsk]->ldt[seg].a) & 0xffff;
103: /* this should be constant amound all of our segments, but we
104: had better check anyway. */
105: if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12;
106:
107: if (limit <= addr+4) return (-EIO);
108:
109: /* Now compute the address, and make sure that it is present. */
110: address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) |
111: ((task[tsk]->ldt[seg].b & 0xff) << 16 ) |
112: (task[tsk]->ldt[seg].b & 0xff000000);
113:
114: page = *((unsigned long*) ((address >> 20) & 0xffc));
115: /* see if it is present. */
116: if (! (page & PAGE_PRESENT))
117: {
118: do_no_page (0, address, task[tsk]);
119: }
120:
121: oldfs=get_fs();
122: /* now convert seg to the right format. */
123: seg = seg << 3 | 0x4;
124:
125: cli(); /* we are about to change our ldt, we better do it
126: with interrupts off. Perhaps we should call schedule
127: first so that we won't be taking too much extra time. */
128: lldt(tsk);
129: set_fs(seg);
130: *data = get_fs_long((void *)addr); /* we are assuming kernel space
131: is in the gdt here. */
132: lldt(cur);
133: set_fs(oldfs);
134: sti();
135: return (0);
136: }
137:
138: /* this routine will get a word out of an arbitrary
139: tasks data space. It likes to have the task number
140: rather than the task pointer. Perhaps the number
141: should be included in the pointer. */
142: /* seg = 0 if I space */
143: static inline int put_long (int tsk, long addr, int data, unsigned seg)
144: {
145: int i;
146: int limit;
147: unsigned oldfs;
148: unsigned long address;
149: unsigned long page;
150: int cur;
151: /* find the task number of the current task. */
152: for (i = 0; i < NR_TASKS ; i ++)
153: {
154: if (task[i] == current) break;
155: }
156: if (i == NR_TASKS)
157: {
158: panic ("PTRACE: Can't find current task\n");
159: }
160: cur = i;
161:
162: /* we will need to check the readability of the segment
163: and then the byte in order to avoid segment violations. */
164: seg++;
165: limit=(task[tsk]->ldt[seg].a) & 0xffff;
166: /* this should be constant amound all of our segments, but we
167: had better check anyway. */
168: if (task[tsk]->ldt[seg].b & GRANULARITY) limit = limit << 12;
169:
170: if (limit <= addr+4) return (-EIO);
171:
172: /* Now compute the address, and make sure that it is present. */
173: address = ((task[tsk]->ldt[seg].a & 0xffff000) >> 8) |
174: ((task[tsk]->ldt[seg].b & 0xff) << 16 ) |
175: (task[tsk]->ldt[seg].b & 0xff000000);
176:
177: page = *((unsigned long*) ((address >> 20) & 0xffc));
178: /* see if it is present. */
179: if (! (page & PAGE_PRESENT))
180: {
181: do_no_page (0, address, task[tsk]);
182: }
183: write_verify (address);
184:
185: oldfs=get_fs();
186: /* now convert seg to the right format. */
187: seg = seg << 3 | 0x4;
188:
189: cli(); /* we are about to change our ldt, we better do it
190: with interrupts off. Perhaps we should call schedule
191: first so that we won't be taking too much extra time. */
192: lldt(tsk);
193: set_fs(seg);
194: put_fs_long(data,(void *)addr);
195: lldt(cur);
196: set_fs(oldfs);
197: sti();
198: return (0);
199: }
200:
201:
202: int
203: sys_ptrace( unsigned long *buffer)
204: /* Perform ptrace(request, pid, addr, data) syscall */
205: {
206: long request, pid, data;
207: long addr;
208: struct task_struct *child;
209: int childno;
210:
211: request = get_fs_long(buffer++);
212: pid = get_fs_long(buffer++);
213: addr = get_fs_long(buffer++); /* assume long = void * */
214: data = get_fs_long(buffer++);
215:
216: if (request == 0)
217: {
218: /* set the ptrace bit in the proccess flags. */
219: current->flags |= PF_PTRACED;
220: return (0);
221: }
222:
223: childno=get_task(pid);
224:
225: if (childno < 0)
226: return (-ESRCH);
227: else
228: child = task[childno];
229:
230: if (child->p_pptr != current ||
231: !(child->flags & PF_PTRACED) || child->state != TASK_STOPPED)
232: return (-ESRCH);
233:
234: switch (request)
235: {
236: /* when I and D space are seperate, these will need to be fixed. */
237: case 1: /* read word at location addr. */
238: case 2: {
239: int tmp;
240: int res;
241: res = get_long(childno, addr, 1, &tmp);
242: if (res < 0)
243: return res;
244: verify_area(data, 4);
245: put_fs_long( tmp, (unsigned long *)data);
246: return 0;
247: }
248:
249: case 3: /* read the word at location addr in the USER area. */
250: {
251: int tmp;
252: addr = addr >> 2; /* temporary hack. */
253: if (addr < 0 || addr >= 17)
254: return (-EIO);
255: verify_area(data, 4);
256: tmp = get_stack_long (child, 4*addr-MAGICNUMBER);
257: put_fs_long(tmp,(unsigned long *)data);
258: return (0);
259: }
260: case 4: /* write the word at location addr. */
261: case 5:
262: /* when I and D space are seperate, this will have to be fixed. */
263: if (put_long(childno, addr, data, 1)) return (-EIO);
264: return (0);
265:
266: case 6: /* write the word at location addr in the USER area */
267: addr = addr >> 2; /* temproary hack. */
268: if (addr < 0 || addr >= 17) return (-EIO);
269: if (addr == ORIG_EAX) return (-EIO);
270: if (addr == EFL) /* flags. */
271: {
272: data &= FLAG_MASK;
273: data |= get_stack_long(child, EFL*4-MAGICNUMBER) & ~FLAG_MASK;
274: }
275:
276: if (put_stack_long(child, 4*addr-MAGICNUMBER, data)) return (-EIO);
277: return (0);
278:
279: case 7: /* restart after signal. */
280: {
281: long tmp;
282: child->signal=0;
283: if (data > 0 && data <= NSIG)
284: child->signal = 1<<(data-1);
285: child->state = 0;
286: /* make sure the single step bit is not set. */
287: tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
288: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
289: return (0);
290: }
291:
292: case 8: /* make the child exit. Best I can do is send it a sigkill.
293: perhaps it should be put in the status that it want's to
294: exit. */
295: {
296: long tmp;
297: child->state = 0;
298: child->signal = 1 << (SIGKILL -1 );
299: /* make sure the single step bit is not set. */
300: tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) & ~TRAP_FLAG;
301: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
302: return (0);
303: }
304:
305: case 9: /* set the trap flag. */
306: {
307: long tmp;
308: tmp = get_stack_long (child, 4*EFL-MAGICNUMBER) | TRAP_FLAG;
309: put_stack_long(child, 4*EFL-MAGICNUMBER,tmp);
310: child->state = 0;
311: child->signal=0;
312: if (data > 0 && data <NSIG)
313: child->signal= 1<<(data-1);
314: /* give it a chance to run. */
315: return (0);
316: }
317:
318: default:
319: return (-EIO);
320: }
321:
322: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.