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