- Implement autopaging.
[wine] / server / context_powerpc.c
1 /*
2  * PowerPC register context support
3  *
4  * Copyright (C) 2002 Marcus Meissner, SuSE Linux AG.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #ifdef __powerpc__
24
25 #include <assert.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_REG_H
29 # include <sys/reg.h>
30 #endif
31 #include <unistd.h>
32 #ifdef HAVE_SYS_PTRACE_H
33 # include <sys/ptrace.h>
34 #endif
35
36 #include "winbase.h"
37
38 #include "thread.h"
39 #include "request.h"
40
41 /* retrieve a thread context */
42 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
43 {
44     int pid = thread->unix_pid;
45     if (flags & CONTEXT_FULL)
46     {
47         if (flags & CONTEXT_INTEGER)
48         {
49 #define XREG(x,y) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
50 #define IREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
51             IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
52             IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
53             IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
54             IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
55             IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
56 #undef IREG
57             XREG(37,Xer);
58             XREG(38,Cr);
59         }
60         if (flags & CONTEXT_CONTROL)
61         {
62             XREG(32,Iar);
63             XREG(33,Msr);
64             XREG(35,Ctr);
65             XREG(36,Lr); /* 36 is LNK ... probably Lr ? */
66         }
67     }
68     if (flags & CONTEXT_FLOATING_POINT)
69     {
70 #define FREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
71         FREG(0);
72         FREG(1);
73         FREG(2);
74         FREG(3);
75         FREG(4);
76         FREG(5);
77         FREG(6);
78         FREG(7);
79         FREG(8);
80         FREG(9);
81         FREG(10);
82         FREG(11);
83         FREG(12);
84         FREG(13);
85         FREG(14);
86         FREG(15);
87         FREG(16);
88         FREG(17);
89         FREG(18);
90         FREG(19);
91         FREG(20);
92         FREG(21);
93         FREG(22);
94         FREG(23);
95         FREG(24);
96         FREG(25);
97         FREG(26);
98         FREG(27);
99         FREG(28);
100         FREG(29);
101         FREG(30);
102         FREG(31);
103         XREG((48+32*2),Fpscr);
104     }
105     return;
106  error:
107     file_set_error();
108 }
109 #undef XREG
110 #undef IREG
111 #undef FREG
112
113 #define XREG(x,y) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
114 #define IREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
115 #define FREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
116 /* set a thread context */
117 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
118 {
119     int pid = thread->unix_pid;
120     if (flags & CONTEXT_FULL)
121     {
122         if (flags & CONTEXT_INTEGER)
123         {
124             IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
125             IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
126             IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
127             IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
128             IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
129             XREG(37,Xer);
130             XREG(38,Cr);
131
132         }
133         if (flags & CONTEXT_CONTROL)
134         {
135             XREG(32,Iar);
136             XREG(33,Msr);
137             XREG(35,Ctr);
138             XREG(36,Lr);
139         }
140     }
141     if (flags & CONTEXT_FLOATING_POINT)
142     {
143         FREG(0);
144         FREG(1);
145         FREG(2);
146         FREG(3);
147         FREG(4);
148         FREG(5);
149         FREG(6);
150         FREG(7);
151         FREG(8);
152         FREG(9);
153         FREG(10);
154         FREG(11);
155         FREG(12);
156         FREG(13);
157         FREG(14);
158         FREG(15);
159         FREG(16);
160         FREG(17);
161         FREG(18);
162         FREG(19);
163         FREG(20);
164         FREG(21);
165         FREG(22);
166         FREG(23);
167         FREG(24);
168         FREG(25);
169         FREG(26);
170         FREG(27);
171         FREG(28);
172         FREG(29);
173         FREG(30);
174         FREG(31);
175 #undef FREG
176         XREG((48+32*2),Fpscr);
177     }
178     return;
179  error:
180     file_set_error();
181 }
182 #undef XREG
183 #undef IREG
184 #undef FREG
185
186 #define IREG(x) to->Gpr##x = from->Gpr##x;
187 #define FREG(x) to->Fpr##x = from->Fpr##x;
188 #define CREG(x) to->x = from->x;
189 /* copy a context structure according to the flags */
190 static void copy_context( CONTEXT *to, const CONTEXT *from, int flags )
191 {
192     if (flags & CONTEXT_CONTROL)
193     {
194         CREG(Msr);
195         CREG(Ctr);
196         CREG(Iar);
197     }
198     if (flags & CONTEXT_INTEGER)
199     {
200         IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
201         IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
202         IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
203         IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
204         IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
205         CREG(Xer);
206         CREG(Cr);
207     }
208     if (flags & CONTEXT_FLOATING_POINT)
209     {
210         FREG(0);
211         FREG(1);
212         FREG(2);
213         FREG(3);
214         FREG(4);
215         FREG(5);
216         FREG(6);
217         FREG(7);
218         FREG(8);
219         FREG(9);
220         FREG(10);
221         FREG(11);
222         FREG(12);
223         FREG(13);
224         FREG(14);
225         FREG(15);
226         FREG(16);
227         FREG(17);
228         FREG(18);
229         FREG(19);
230         FREG(20);
231         FREG(21);
232         FREG(22);
233         FREG(23);
234         FREG(24);
235         FREG(25);
236         FREG(26);
237         FREG(27);
238         FREG(28);
239         FREG(29);
240         FREG(30);
241         FREG(31);
242         CREG(Fpscr);
243     }
244 }
245
246 /* retrieve the current instruction pointer of a thread */
247 void *get_thread_ip( struct thread *thread )
248 {
249     CONTEXT context;
250     context.Iar = 0;
251     if (suspend_for_ptrace( thread ))
252     {
253         get_thread_context( thread, CONTEXT_CONTROL, &context );
254         resume_thread( thread );
255     }
256     return (void *)context.Iar;
257 }
258
259 /* determine if we should continue the thread in single-step mode */
260 int get_thread_single_step( struct thread *thread )
261 {
262     CONTEXT context;
263     if (thread->context) return 0;
264     get_thread_context( thread, CONTEXT_CONTROL, &context );
265 #ifndef MSR_SE
266 # define MSR_SE (1<<10)
267 #endif
268     return (context.Msr & MSR_SE) != 0;
269 }
270
271 /* retrieve the current context of a thread */
272 DECL_HANDLER(get_thread_context)
273 {
274     struct thread *thread;
275     void *data;
276     int flags = req->flags;
277
278     if (get_reply_max_size() < sizeof(CONTEXT))
279     {
280         set_error( STATUS_INVALID_PARAMETER );
281         return;
282     }
283     if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
284
285     if ((data = set_reply_data_size( sizeof(CONTEXT) )))
286     {
287         if (thread->context)  /* thread is inside an exception event */
288         {
289             copy_context( data, thread->context, flags );
290             flags = 0;
291         }
292         if (flags && suspend_for_ptrace( thread ))
293         {
294             get_thread_context( thread, flags, data );
295             resume_thread( thread );
296         }
297     }
298     release_object( thread );
299 }
300
301
302 /* set the current context of a thread */
303 DECL_HANDLER(set_thread_context)
304 {
305     struct thread *thread;
306     int flags = req->flags;
307
308     if (get_req_data_size() < sizeof(CONTEXT))
309     {
310         set_error( STATUS_INVALID_PARAMETER );
311         return;
312     }
313     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
314     {
315         if (thread->context)  /* thread is inside an exception event */
316         {
317             copy_context( thread->context, get_req_data(), flags );
318             flags = 0;
319         }
320         if (flags && suspend_for_ptrace( thread ))
321         {
322             set_thread_context( thread, flags, get_req_data() );
323             resume_thread( thread );
324         }
325         release_object( thread );
326     }
327 }
328
329 #endif  /* __powerpc__ */