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