Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / um / kernel / tt / ptproxy / ptrace.c
1 /**********************************************************************
2 ptrace.c
3
4 Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
5 terms and conditions.
6
7 Jeff Dike (jdike@karaya.com) : Modified for integration into uml
8 **********************************************************************/
9
10 #include <errno.h>
11 #include <unistd.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/wait.h>
16
17 #include "ptproxy.h"
18 #include "debug.h"
19 #include "user_util.h"
20 #include "kern_util.h"
21 #include "ptrace_user.h"
22 #include "tt.h"
23 #include "os.h"
24
25 long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
26                   long arg3, long arg4, pid_t child, int *ret)
27 {
28         sigset_t relay;
29         long result;
30         int status;
31
32         *ret = 0;
33         if(debugger->debugee->died) return(-ESRCH);
34
35         switch(arg1){
36         case PTRACE_ATTACH:
37                 if(debugger->debugee->traced) return(-EPERM);
38
39                 debugger->debugee->pid = arg2;
40                 debugger->debugee->traced = 1;
41
42                 if(is_valid_pid(arg2) && (arg2 != child)){
43                         debugger->debugee->in_context = 0;
44                         kill(arg2, SIGSTOP);
45                         debugger->debugee->event = 1;
46                         debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
47                 }
48                 else {
49                         debugger->debugee->in_context = 1;
50                         if(debugger->debugee->stopped) 
51                                 child_proxy(child, W_STOPCODE(SIGSTOP));
52                         else kill(child, SIGSTOP);
53                 }
54
55                 return(0);
56
57         case PTRACE_DETACH:
58                 if(!debugger->debugee->traced) return(-EPERM);
59                 
60                 debugger->debugee->traced = 0;
61                 debugger->debugee->pid = 0;
62                 if(!debugger->debugee->in_context)
63                         kill(child, SIGCONT);
64
65                 return(0);
66
67         case PTRACE_CONT:
68                 if(!debugger->debugee->in_context) return(-EPERM);
69                 *ret = PTRACE_CONT;
70                 return(ptrace(PTRACE_CONT, child, arg3, arg4));
71
72 #ifdef UM_HAVE_GETFPREGS
73         case PTRACE_GETFPREGS:
74         {
75                 long regs[FP_FRAME_SIZE];
76                 int i, result;
77
78                 result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
79                 if(result == -1) return(-errno);
80                 
81                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
82                         ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
83                                regs[i]);
84                 return(result);
85         }
86 #endif
87
88 #ifdef UM_HAVE_GETFPXREGS
89         case PTRACE_GETFPXREGS:
90         {
91                 long regs[FPX_FRAME_SIZE];
92                 int i, result;
93
94                 result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
95                 if(result == -1) return(-errno);
96                 
97                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
98                         ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
99                                regs[i]);
100                 return(result);
101         }
102 #endif
103
104 #ifdef UM_HAVE_GETREGS
105         case PTRACE_GETREGS:
106         {
107                 long regs[FRAME_SIZE];
108                 int i, result;
109
110                 result = ptrace(PTRACE_GETREGS, child, 0, regs);
111                 if(result == -1) return(-errno);
112
113                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
114                         ptrace (PTRACE_POKEDATA, debugger->pid,
115                                 arg4 + 4 * i, regs[i]);
116                 return(result);
117         }
118         break;
119 #endif
120
121         case PTRACE_KILL:
122                 result = ptrace(PTRACE_KILL, child, arg3, arg4);
123                 if(result == -1) return(-errno);
124
125                 return(result);
126
127         case PTRACE_PEEKDATA:
128         case PTRACE_PEEKTEXT:
129         case PTRACE_PEEKUSR:
130                 /* The value being read out could be -1, so we have to 
131                  * check errno to see if there's an error, and zero it
132                  * beforehand so we're not faked out by an old error
133                  */
134
135                 errno = 0;
136                 result = ptrace(arg1, child, arg3, 0);
137                 if((result == -1) && (errno != 0)) return(-errno);
138
139                 result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
140                 if(result == -1) return(-errno);
141                         
142                 return(result);
143
144         case PTRACE_POKEDATA:
145         case PTRACE_POKETEXT:
146         case PTRACE_POKEUSR:
147                 result = ptrace(arg1, child, arg3, arg4);
148                 if(result == -1) return(-errno);
149
150                 if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
151                 return(result);
152
153 #ifdef UM_HAVE_SETFPREGS
154         case PTRACE_SETFPREGS:
155         {
156                 long regs[FP_FRAME_SIZE];
157                 int i;
158
159                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
160                         regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
161                                           arg4 + 4 * i, 0);
162                 result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
163                 if(result == -1) return(-errno);
164
165                 return(result);
166         }
167 #endif
168
169 #ifdef UM_HAVE_SETFPXREGS
170         case PTRACE_SETFPXREGS:
171         {
172                 long regs[FPX_FRAME_SIZE];
173                 int i;
174
175                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
176                         regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
177                                           arg4 + 4 * i, 0);
178                 result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
179                 if(result == -1) return(-errno);
180
181                 return(result);
182         }
183 #endif
184
185 #ifdef UM_HAVE_SETREGS
186         case PTRACE_SETREGS:
187         {
188                 long regs[FRAME_SIZE];
189                 int i;
190
191                 for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
192                         regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
193                                          arg4 + 4 * i, 0);
194                 result = ptrace(PTRACE_SETREGS, child, 0, regs);
195                 if(result == -1) return(-errno);
196
197                 return(result);
198         }
199 #endif
200
201         case PTRACE_SINGLESTEP:
202                 if(!debugger->debugee->in_context) return(-EPERM);
203                 sigemptyset(&relay);
204                 sigaddset(&relay, SIGSEGV);
205                 sigaddset(&relay, SIGILL);
206                 sigaddset(&relay, SIGBUS);
207                 result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
208                 if(result == -1) return(-errno);
209                 
210                 status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
211                                        &relay);
212                 child_proxy(child, status);
213                 return(result);
214
215         case PTRACE_SYSCALL:
216                 if(!debugger->debugee->in_context) return(-EPERM);
217                 result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
218                 if(result == -1) return(-errno);
219
220                 *ret = PTRACE_SYSCALL;
221                 return(result);
222
223         case PTRACE_TRACEME:
224         default:
225                 return(-EINVAL);
226         }
227 }
228
229 /*
230  * Overrides for Emacs so that we follow Linus's tabbing style.
231  * Emacs will notice this stuff at the end of the file and automatically
232  * adjust the settings for this buffer only.  This must remain at the end
233  * of the file.
234  * ---------------------------------------------------------------------------
235  * Local variables:
236  * c-file-style: "linux"
237  * End:
238  */