Version:
~ [ 0.6-2.3.46 ] ~
Architecture:
~ [ um ] ~
** Warning: Cannot open xref database.
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <sched.h>
6 #include <signal.h>
7 #include <errno.h>
8 #include <sys/wait.h>
9 #include <sys/ptrace.h>
10 #include <sys/mman.h>
11 #include <sys/time.h>
12 #include <asm/unistd.h>
13 #include <asm/page.h>
14 #include <asm/ptrace.h>
15 #include "user_util.h"
16 #include "kern_util.h"
17 #include "user.h"
18
19 struct {
20 int syscall;
21 int pid;
22 int result;
23 struct timeval start;
24 struct timeval end;
25 } syscall_record[1024];
26
27 int syscall_index = 0;
28
29 static void really_do_vfork(int sig)
30 {
31 void (*old_handler)(int);
32 unsigned long args[5];
33 int index, result, syscall;
34
35 set_user_thread(NULL, 0);
36 syscall = current_syscall(NULL, args);
37 old_handler = set_signal_handler(SIGSEGV, kern_segv_handler);
38 lock_syscall();
39 if(syscall_index == 1024) syscall_index = 0;
40 index = syscall_index;
41 syscall_index++;
42 unlock_syscall();
43 syscall_record[index].syscall = syscall;
44 syscall_record[index].pid = current_pid(NULL);
45 syscall_record[index].result = 0xdeadbeef;
46 gettimeofday(&syscall_record[index].start, NULL);
47 result = execute_syscall(syscall, args);
48 set_sigstack(current_sigstack(NULL), SIGUSR2, syscall_handler, 0, 1, -1);
49 syscall_record[index].result = result;
50 gettimeofday(&syscall_record[index].end, NULL);
51 set_syscall_result(NULL, result, 0, 1);
52 set_signal_handler(SIGSEGV, old_handler);
53 set_user_thread(NULL, 1);
54 }
55
56 static void really_do_syscall(int sig)
57 {
58 unsigned long args[5];
59 int syscall, result, again;
60
61 syscall = current_syscall(NULL, args);
62 result = execute_syscall(syscall, args);
63 again = 0;
64 if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) ||
65 (result == -ERESTARTNOINTR))
66 again = do_signal(NULL, &result, NULL);
67 ret_from_sys_call(NULL);
68 set_syscall_result(NULL, result, again, 0);
69 }
70
71 void syscall_handler(int sig)
72 {
73 struct sigaction action;
74 void (*old_handler)(int), *task;
75 unsigned long args[5];
76 int index, result, syscall, again;
77
78 #ifdef __SMP__
79 task = cpu_tasks[pid_to_processor_id(getpid())].task;
80 #else
81 task = get_current_task();
82 #endif
83 syscall = current_syscall(task, args);
84 if(syscall == __NR_vfork){
85 set_sigstack(current_sigstack(task), SIGUSR2, really_do_vfork, 1, 1, -1);
86 set_user_thread(task, 1);
87 return;
88 }
89 old_handler = set_signal_handler(SIGSEGV, kern_segv_handler);
90 lock_syscall();
91 if(syscall_index == 1024) syscall_index = 0;
92 index = syscall_index;
93 syscall_index++;
94 unlock_syscall();
95 syscall_record[index].syscall = syscall;
96 syscall_record[index].pid = current_pid(task);
97 syscall_record[index].result = 0xdeadbeef;
98 gettimeofday(&syscall_record[index].start, NULL);
99 sigaction(SIGUSR2, NULL, &action);
100 do {
101 again = 0;
102 store_syscall(task, syscall, args[0], args[1], args[2], args[3], args[4]);
103 set_sigstack(current_sigstack(task), SIGUSR2, really_do_syscall, 1, 1, -1);
104 kill(getpid(), SIGUSR2);
105 result = temp_syscall_result(task, &again);
106 sigaction(SIGUSR2, &action, NULL);
107 deliver_signals(task);
108 } while(again);
109 syscall_record[index].result = result;
110 gettimeofday(&syscall_record[index].end, NULL);
111 set_syscall_result(task, result, 0, 1);
112 set_signal_handler(SIGSEGV, old_handler);
113 set_user_thread(task, 1);
114 }
115
116 #define SIGFRAME_SLOP 512
117
118 void do_syscall(void *task, int pid)
119 {
120 unsigned long args[5], sp;
121 int syscall, result;
122
123 syscall = ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX * 4, NULL);
124 if(syscall == -1){
125 printk("ptrace PTRACE_PEEKUSER failed, errno = %d\n", errno);
126 PROC_UNTESTED();
127 }
128 if(syscall == __NR_sigreturn){
129 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
130 panic("do_syscall : Couldn't continue past sigreturn call");
131 wait_for_stop(pid, SIGTRAP);
132 if(have_syscall_result(task, &result)){
133 if(ptrace(PTRACE_POKEUSER, pid, EAX * 4, result) < 0)
134 panic("do_syscall_result : Couldn't assign syscall result");
135 }
136 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
137 panic("do_syscall : Couldn't continue past sigreturn return");
138 return;
139 }
140 args[0] = ptrace(PTRACE_PEEKUSER, pid, EBX * 4, NULL);
141 args[1] = ptrace(PTRACE_PEEKUSER, pid, ECX * 4, NULL);
142 args[2] = ptrace(PTRACE_PEEKUSER, pid, EDX * 4, NULL);
143 args[3] = ptrace(PTRACE_PEEKUSER, pid, ESI * 4, NULL);
144 args[4] = ptrace(PTRACE_PEEKUSER, pid, EDI * 4, NULL);
145 store_syscall(task, syscall, args[0], args[1], args[2], args[3], args[4]);
146 if((ptrace(PTRACE_POKEUSER, pid, ORIG_EAX * 4, __NR_getpid) < 0) ||
147 (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)){
148 printk("Failed to change syscall number to __NR_getpid\n");
149 if(errno == EIO){
150 printk("You probably didn't apply the ptrace patch to your hosting "
151 "kernel\n");
152 }
153 else printk("errno = %d\n", errno);
154 panic("do_syscall : Couldn't force getpid");
155 }
156 wait_for_stop(pid, SIGTRAP);
157
158 /* In case this is a fork or vfork, save the registers so they can be
159 * restored after the trampoline has finished setting up
160 */
161 if(ptrace(PTRACE_GETREGS, pid, 0, fork_regs(task)) < 0)
162 panic("Couldn't read registers");
163
164 sp = ptrace(PTRACE_PEEKUSER, pid, UESP * 4, 0);
165 if((sp & ~PAGE_MASK) < SIGFRAME_SLOP){
166 set_forced_fault(task, sp - SIGFRAME_SLOP);
167 kill(pid, SIGSEGV);
168 set_tracing(task, 0);
169 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
170 panic("Couldn't force seg fault");
171 wait_for_stop(pid, SIGSEGV);
172 if(ptrace(PTRACE_CONT, pid, 0, SIGSEGV) < 0)
173 panic("Couldn't force process through seg fault");
174 wait_for_stop(pid, SIGSTOP);
175 set_tracing(task, 1);
176 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
177 panic("Couldn't force process beyond seg fault");
178 wait_for_stop(pid, SIGTRAP);
179 }
180
181 if(syscall == __NR_vfork){
182
183 /* The deal here is that vfork can't put a frame on the process stack.
184 If there is one, it will get trashed by the child on the way out, and
185 the parent, who is sharing that stack, will find that it has nothing
186 to return to. This syscall mechanism by default puts a signal frame
187 on the process stack in case there are signals that need to be
188 delivered. For vfork, this can't be allowed to happen, so the code
189 below invokes syscall_handler on the process stack, which just resets
190 the handler to really_do_vfork and returns in this case. Then it
191 sends another SIGUSR2 to invoke really_do_vfork on the signal stack
192 and walks through that until it gets into the vfork. At that point,
193 everything is cool and will work without special treatment. */
194
195 /* Send the first signal */
196 kill(pid, SIGUSR2);
197 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
198 panic("Couldn't continue proc into signal");
199 wait_for_stop(pid, SIGUSR2);
200 if(ptrace(PTRACE_SYSCALL, pid, 0, SIGUSR2) < 0)
201 panic("Couldn't continue proc past first signal");
202 /* In syscall_handler */
203 wait_for_stop(pid, SIGTRAP);
204 /* Tracing-off request */
205 set_tracing(task, 0);
206 /* Reset handler and turn tracing back on */
207 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
208 panic("Couldn't continue proc into syscall_handler");
209 wait_for_stop(pid, SIGTRAP);
210 /* Tracing back on */
211 set_tracing(task, 1);
212 /* Coming out of signal handler */
213 if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
214 panic("Couldn't continue proc out of syscall_handler");
215 wait_for_stop(pid, SIGTRAP);
216 syscall = ptrace(PTRACE_PEEKUSER, pid, ORIG_EAX * 4, NULL);
217 if(syscall != __NR_sigreturn)
218 panic("Expected __NR_sigreturn, got %d", syscall);
219 /* Send second signal */
220 kill(pid, SIGUSR2);
221 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
222 panic("Couldn't continue proc into signal");
223 wait_for_stop(pid, SIGUSR2);
224 if(ptrace(PTRACE_SYSCALL, pid, 0, SIGUSR2) < 0)
225 panic("Couldn't continue proc into really_do_vfork");
226 /* In really_do_vfork */
227 wait_for_stop(pid, SIGTRAP);
228 /* Tracing off */
229 set_tracing(task, 0);
230 /* Execute vfork, which goes to sleep */
231 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
232 panic("Couldn't continue proc into vfork");
233 return;
234 }
235
236 kill(pid, SIGUSR2);
237 if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
238 panic("Couldn't continue proc into signal");
239 wait_for_stop(pid, SIGUSR2);
240 set_tracing(task, 0);
241 if(ptrace(PTRACE_CONT, pid, 0, SIGUSR2) < 0)
242 panic("Couldn't continue proc past first signal");
243 }
244
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.