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