Moved the platform-independent part of the get/set_thread_context
[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 <stdarg.h>
32 #include <unistd.h>
33 #ifdef HAVE_SYS_PTRACE_H
34 # include <sys/ptrace.h>
35 #endif
36
37 #ifndef PTRACE_PEEKUSER
38 # ifdef PT_READ_D
39 #  define PTRACE_PEEKUSER PT_READ_D
40 # endif
41 #endif /* PTRACE_PEEKUSER */
42
43 #ifndef PTRACE_POKEUSER
44 # ifdef PT_WRITE_D
45 #  define PTRACE_POKEUSER PT_WRITE_D
46 # endif
47 #endif /* PTRACE_POKEUSER */
48
49 #include "windef.h"
50
51 #include "file.h"
52 #include "thread.h"
53 #include "request.h"
54
55 /* retrieve a thread context */
56 static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
57 {
58     int pid = get_ptrace_pid(thread);
59     if (flags & CONTEXT_FULL)
60     {
61         if (flags & CONTEXT_INTEGER)
62         {
63 #define XREG(x,y) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
64 #define IREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
65             IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
66             IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
67             IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
68             IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
69             IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
70 #undef IREG
71             XREG(37,Xer);
72             XREG(38,Cr);
73         }
74         if (flags & CONTEXT_CONTROL)
75         {
76             XREG(32,Iar);
77             XREG(33,Msr);
78             XREG(35,Ctr);
79             XREG(36,Lr); /* 36 is LNK ... probably Lr ? */
80         }
81     }
82     if (flags & CONTEXT_FLOATING_POINT)
83     {
84 #define FREG(x) if (ptrace( PTRACE_PEEKUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
85         FREG(0);
86         FREG(1);
87         FREG(2);
88         FREG(3);
89         FREG(4);
90         FREG(5);
91         FREG(6);
92         FREG(7);
93         FREG(8);
94         FREG(9);
95         FREG(10);
96         FREG(11);
97         FREG(12);
98         FREG(13);
99         FREG(14);
100         FREG(15);
101         FREG(16);
102         FREG(17);
103         FREG(18);
104         FREG(19);
105         FREG(20);
106         FREG(21);
107         FREG(22);
108         FREG(23);
109         FREG(24);
110         FREG(25);
111         FREG(26);
112         FREG(27);
113         FREG(28);
114         FREG(29);
115         FREG(30);
116         FREG(31);
117         XREG((48+32*2),Fpscr);
118     }
119     return;
120  error:
121     file_set_error();
122 }
123 #undef XREG
124 #undef IREG
125 #undef FREG
126
127 #define XREG(x,y) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->y) == -1) goto error;
128 #define IREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)(x<<2), &context->Gpr##x) == -1) goto error;
129 #define FREG(x) if (ptrace( PTRACE_POKEUSER, pid, (void*)((48+x*2)<<2), &context->Fpr##x) == -1) goto error;
130 /* set a thread context */
131 static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
132 {
133     int pid = get_ptrace_pid(thread);
134     if (flags & CONTEXT_FULL)
135     {
136         if (flags & CONTEXT_INTEGER)
137         {
138             IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
139             IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
140             IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
141             IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
142             IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
143             XREG(37,Xer);
144             XREG(38,Cr);
145
146         }
147         if (flags & CONTEXT_CONTROL)
148         {
149             XREG(32,Iar);
150             XREG(33,Msr);
151             XREG(35,Ctr);
152             XREG(36,Lr);
153         }
154     }
155     if (flags & CONTEXT_FLOATING_POINT)
156     {
157         FREG(0);
158         FREG(1);
159         FREG(2);
160         FREG(3);
161         FREG(4);
162         FREG(5);
163         FREG(6);
164         FREG(7);
165         FREG(8);
166         FREG(9);
167         FREG(10);
168         FREG(11);
169         FREG(12);
170         FREG(13);
171         FREG(14);
172         FREG(15);
173         FREG(16);
174         FREG(17);
175         FREG(18);
176         FREG(19);
177         FREG(20);
178         FREG(21);
179         FREG(22);
180         FREG(23);
181         FREG(24);
182         FREG(25);
183         FREG(26);
184         FREG(27);
185         FREG(28);
186         FREG(29);
187         FREG(30);
188         FREG(31);
189 #undef FREG
190         XREG((48+32*2),Fpscr);
191     }
192     return;
193  error:
194     file_set_error();
195 }
196 #undef XREG
197 #undef IREG
198 #undef FREG
199
200 #define IREG(x) to->Gpr##x = from->Gpr##x;
201 #define FREG(x) to->Fpr##x = from->Fpr##x;
202 #define CREG(x) to->x = from->x;
203 /* copy a context structure according to the flags */
204 static void copy_context( CONTEXT *to, const CONTEXT *from, int flags )
205 {
206     if (flags & CONTEXT_CONTROL)
207     {
208         CREG(Msr);
209         CREG(Ctr);
210         CREG(Iar);
211     }
212     if (flags & CONTEXT_INTEGER)
213     {
214         IREG(0); IREG(1); IREG(2); IREG(3); IREG(4); IREG(5); IREG(6);
215         IREG(7); IREG(8); IREG(9); IREG(10); IREG(11); IREG(12); IREG(13);
216         IREG(14); IREG(15); IREG(16); IREG(17); IREG(18); IREG(19);
217         IREG(20); IREG(21); IREG(22); IREG(23); IREG(24); IREG(25);
218         IREG(26); IREG(27); IREG(28); IREG(29); IREG(30); IREG(31);
219         CREG(Xer);
220         CREG(Cr);
221     }
222     if (flags & CONTEXT_FLOATING_POINT)
223     {
224         FREG(0);
225         FREG(1);
226         FREG(2);
227         FREG(3);
228         FREG(4);
229         FREG(5);
230         FREG(6);
231         FREG(7);
232         FREG(8);
233         FREG(9);
234         FREG(10);
235         FREG(11);
236         FREG(12);
237         FREG(13);
238         FREG(14);
239         FREG(15);
240         FREG(16);
241         FREG(17);
242         FREG(18);
243         FREG(19);
244         FREG(20);
245         FREG(21);
246         FREG(22);
247         FREG(23);
248         FREG(24);
249         FREG(25);
250         FREG(26);
251         FREG(27);
252         FREG(28);
253         FREG(29);
254         FREG(30);
255         FREG(31);
256         CREG(Fpscr);
257     }
258 }
259
260 /* retrieve the current instruction pointer of a thread */
261 void *get_thread_ip( struct thread *thread )
262 {
263     CONTEXT context;
264     context.Iar = 0;
265     if (suspend_for_ptrace( thread ))
266     {
267         get_thread_context_ptrace( thread, CONTEXT_CONTROL, &context );
268         resume_after_ptrace( thread );
269     }
270     return (void *)context.Iar;
271 }
272
273 /* determine if we should continue the thread in single-step mode */
274 int get_thread_single_step( struct thread *thread )
275 {
276     CONTEXT context;
277     if (thread->context) return 0;
278     get_thread_context_ptrace( thread, CONTEXT_CONTROL, &context );
279 #ifndef MSR_SE
280 # define MSR_SE (1<<10)
281 #endif
282     return (context.Msr & MSR_SE) != 0;
283 }
284
285 /* send a signal to a specific thread */
286 int tkill( int pid, int sig )
287 {
288     /* FIXME: should do something here */
289     errno = ENOSYS;
290     return -1;
291 }
292
293 /* retrieve the thread context */
294 void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
295 {
296     if (thread->context)  /* thread is inside an exception event or suspended */
297     {
298         copy_context( context, thread->context, flags );
299     }
300     else if (flags && suspend_for_ptrace( thread ))
301     {
302         get_thread_context_ptrace( thread, flags, context );
303         resume_after_ptrace( thread );
304     }
305 }
306
307 /* set the thread context */
308 void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
309 {
310     if (thread->context)  /* thread is inside an exception event or suspended */
311     {
312         copy_context( thread->context, context, flags );
313     }
314     else if (flags && suspend_for_ptrace( thread ))
315     {
316         set_thread_context_ptrace( thread, flags, context );
317         resume_after_ptrace( thread );
318     }
319 }
320
321 #endif  /* __powerpc__ */