vserver 1.9.3
[linux-2.6.git] / arch / um / kernel / frame.c
1 /* 
2  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <signal.h>
11 #include <wait.h>
12 #include <sched.h>
13 #include <errno.h>
14 #include <sys/ptrace.h>
15 #include <sys/syscall.h>
16 #include <sys/mman.h>
17 #include <asm/page.h>
18 #include <asm/ptrace.h>
19 #include <asm/sigcontext.h>
20 #include "sysdep/ptrace.h"
21 #include "sysdep/sigcontext.h"
22 #include "frame_user.h"
23 #include "kern_util.h"
24 #include "user_util.h"
25 #include "ptrace_user.h"
26 #include "os.h"
27
28 static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
29                          unsigned long top, void **data_out)
30 {
31         unsigned long regs[FRAME_SIZE];
32         int pid, status, n, len;
33
34         /* Start the child as a thread */
35         pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);
36         if(pid < 0){
37                 printf("capture_stack : clone failed - errno = %d\n", errno);
38                 exit(1);
39         }
40
41         /* Wait for it to stop itself and continue it with a SIGUSR1 to force 
42          * it into the signal handler.
43          */
44         CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
45         if(n < 0){
46                 printf("capture_stack : waitpid failed - errno = %d\n", errno);
47                 exit(1);
48         }
49         if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
50                 fprintf(stderr, "capture_stack : Expected SIGSTOP, "
51                         "got status = 0x%x\n", status);
52                 exit(1);
53         }
54         if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){
55                 printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
56                        errno);
57                 exit(1);
58         }
59
60         /* Wait for it to stop itself again and grab its registers again.  
61          * At this point, the handler has stuffed the addresses of
62          * sig, sc, and SA_RESTORER in raw.
63          */
64         CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
65         if(n < 0){
66                 printf("capture_stack : waitpid failed - errno = %d\n", errno);
67                 exit(1);
68         }
69         if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
70                 fprintf(stderr, "capture_stack : Expected SIGSTOP, "
71                         "got status = 0x%x\n", status);
72                 exit(1);
73         }
74         if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){
75                 printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 
76                        errno);
77                 exit(1);
78         }
79
80         /* It has outlived its usefulness, so continue it so it can exit */
81         if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){
82                 printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
83                        errno);
84                 exit(1);
85         }
86         CATCH_EINTR(n = waitpid(pid, &status, 0));
87         if(n < 0){
88                 printf("capture_stack : waitpid failed - errno = %d\n", errno);
89                 exit(1);
90         }
91         if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
92                 printf("capture_stack : Expected exit signal 9, "
93                        "got status = 0x%x\n", status);
94                 exit(1);
95         }
96
97         /* The frame that we want is the top of the signal stack */
98
99         len = top - PT_SP(regs);
100         *data_out = malloc(len);
101         if(*data_out == NULL){
102                 printf("capture_stack : malloc failed - errno = %d\n", errno);
103                 exit(1);
104         }
105         memcpy(*data_out, (void *) PT_SP(regs), len);
106
107         return(len);
108 }
109
110 struct common_raw {
111         void *stack;
112         int size;
113         unsigned long sig;
114         unsigned long sr;
115         unsigned long sp;       
116         struct arch_frame_data_raw arch;
117 };
118
119 #define SA_RESTORER (0x04000000)
120
121 typedef unsigned long old_sigset_t;
122
123 struct old_sigaction {
124         __sighandler_t handler;
125         old_sigset_t sa_mask;
126         unsigned long sa_flags;
127         void (*sa_restorer)(void);
128 };
129
130 static void child_common(struct common_raw *common, sighandler_t handler,
131                          int restorer, int flags)
132 {
133         stack_t ss = ((stack_t) { .ss_sp        = common->stack,
134                                   .ss_flags     = 0,
135                                   .ss_size      = common->size });
136         int err;
137
138         if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
139                 printf("PTRACE_TRACEME failed, errno = %d\n", errno);
140         }
141         if(sigaltstack(&ss, NULL) < 0){
142                 printf("sigaltstack failed - errno = %d\n", errno);
143                 kill(getpid(), SIGKILL);
144         }
145
146         if(restorer){
147                 struct sigaction sa;
148
149                 sa.sa_handler = handler;
150                 sigemptyset(&sa.sa_mask);
151                 sa.sa_flags = SA_ONSTACK | flags;
152                 err = sigaction(SIGUSR1, &sa, NULL);
153         }
154         else {
155                 struct old_sigaction sa;
156
157                 sa.handler = handler;
158                 sa.sa_mask = 0;
159                 sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
160                 err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
161         }
162         
163         if(err < 0){
164                 printf("sigaction failed - errno = %d\n", errno);
165                 kill(getpid(), SIGKILL);
166         }
167
168         os_stop_process(os_getpid());
169 }
170
171 /* Changed only during early boot */
172 struct sc_frame signal_frame_sc;
173
174 struct sc_frame signal_frame_sc_sr;
175
176 struct sc_frame_raw {
177         struct common_raw common;
178         unsigned long sc;
179         int restorer;
180 };
181
182 /* Changed only during early boot */
183 static struct sc_frame_raw *raw_sc = NULL;
184
185 static void sc_handler(int sig, struct sigcontext sc)
186 {
187         raw_sc->common.sig = (unsigned long) &sig;
188         raw_sc->common.sr = frame_restorer();
189         raw_sc->common.sp = frame_sp();
190         raw_sc->sc = (unsigned long) &sc;
191         setup_arch_frame_raw(&raw_sc->common.arch, &sc + 1, raw_sc->common.sr);
192
193         os_stop_process(os_getpid());
194         kill(getpid(), SIGKILL);
195 }
196
197 static int sc_child(void *arg)
198 {
199         raw_sc = arg;
200         child_common(&raw_sc->common, (sighandler_t) sc_handler, 
201                      raw_sc->restorer, 0);
202         return(-1);
203 }
204
205 /* Changed only during early boot */
206 struct si_frame signal_frame_si;
207
208 struct si_frame_raw {
209         struct common_raw common;
210         unsigned long sip;
211         unsigned long si;
212         unsigned long ucp;
213         unsigned long uc;
214 };
215
216 /* Changed only during early boot */
217 static struct si_frame_raw *raw_si = NULL;
218
219 static void si_handler(int sig, siginfo_t *si, struct ucontext *ucontext)
220 {
221         raw_si->common.sig = (unsigned long) &sig;
222         raw_si->common.sr = frame_restorer();
223         raw_si->common.sp = frame_sp();
224         raw_si->sip = (unsigned long) &si;
225         raw_si->si = (unsigned long) si;
226         raw_si->ucp = (unsigned long) &ucontext;
227         raw_si->uc = (unsigned long) ucontext;
228         setup_arch_frame_raw(&raw_si->common.arch, 
229                              ucontext->uc_mcontext.fpregs, raw_si->common.sr);
230         
231         os_stop_process(os_getpid());
232         kill(getpid(), SIGKILL);
233 }
234
235 static int si_child(void *arg)
236 {
237         raw_si = arg;
238         child_common(&raw_si->common, (sighandler_t) si_handler, 1, 
239                      SA_SIGINFO);
240         return(-1);
241 }
242
243 static int relative_sr(unsigned long sr, int sr_index, void *stack, 
244                        void *framep)
245 {
246         unsigned long *srp = (unsigned long *) sr;
247         unsigned long frame = (unsigned long) framep;
248
249         if((*srp & PAGE_MASK) == (unsigned long) stack){
250                 *srp -= sr;
251                 *((unsigned long *) (frame + sr_index)) = *srp;
252                 return(1);
253         }
254         else return(0);
255 }
256
257 static unsigned long capture_stack_common(int (*proc)(void *), void *arg, 
258                                           struct common_raw *common_in, 
259                                           void *top, void *sigstack, 
260                                           int stack_len, 
261                                           struct frame_common *common_out)
262 {
263         unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
264
265         common_in->stack = (void *) sigstack;
266         common_in->size = stack_len;
267         common_out->len = capture_stack(proc, arg, top, sig_top, 
268                                         &common_out->data);
269         base = sig_top - common_out->len;
270         common_out->sig_index = common_in->sig - base;
271         common_out->sp_index = common_in->sp - base;
272         common_out->sr_index = common_in->sr - base;
273         common_out->sr_relative = relative_sr(common_in->sr, 
274                                               common_out->sr_index, sigstack, 
275                                               common_out->data);
276         return(base);
277 }
278
279 void capture_signal_stack(void)
280 {
281         struct sc_frame_raw raw_sc;
282         struct si_frame_raw raw_si;
283         void *stack, *sigstack;
284         unsigned long top, base;
285
286         stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
287                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
288         sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
289                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
290         if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){
291                 printf("capture_signal_stack : mmap failed - errno = %d\n", 
292                        errno);
293                 exit(1);
294         }
295
296         top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
297
298         /* Get the sigcontext, no sigrestorer layout */
299         raw_sc.restorer = 0;
300         base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 
301                                     (void *) top, sigstack, PAGE_SIZE, 
302                                     &signal_frame_sc.common);
303
304         signal_frame_sc.sc_index = raw_sc.sc - base;
305         setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc.common.arch);
306
307         /* Ditto for the sigcontext, sigrestorer layout */
308         raw_sc.restorer = 1;
309         base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, 
310                                     (void *) top, sigstack, PAGE_SIZE, 
311                                     &signal_frame_sc_sr.common);
312         signal_frame_sc_sr.sc_index = raw_sc.sc - base;
313         setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc_sr.common.arch);
314
315         /* And the siginfo layout */
316
317         base = capture_stack_common(si_child, &raw_si, &raw_si.common, 
318                                     (void *) top, sigstack, PAGE_SIZE, 
319                                     &signal_frame_si.common);
320         signal_frame_si.sip_index = raw_si.sip - base;
321         signal_frame_si.si_index = raw_si.si - base;
322         signal_frame_si.ucp_index = raw_si.ucp - base;
323         signal_frame_si.uc_index = raw_si.uc - base;
324         setup_arch_frame(&raw_si.common.arch, &signal_frame_si.common.arch);
325
326         if((munmap(stack, PAGE_SIZE) < 0) || 
327            (munmap(sigstack, PAGE_SIZE) < 0)){
328                 printf("capture_signal_stack : munmap failed - errno = %d\n", 
329                        errno);
330                 exit(1);
331         }
332 }
333
334 /*
335  * Overrides for Emacs so that we follow Linus's tabbing style.
336  * Emacs will notice this stuff at the end of the file and automatically
337  * adjust the settings for this buffer only.  This must remain at the end
338  * of the file.
339  * ---------------------------------------------------------------------------
340  * Local variables:
341  * c-file-style: "linux"
342  * End:
343  */