ioctlsocket() now returns success if the app sets nonblocking mode for
[wine] / server / context_i386.c
1 /*
2  * i386 register context support
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #ifdef __i386__
10
11 #include <assert.h>
12 #include <errno.h>
13 #ifdef HAVE_SYS_REG_H
14 #include <sys/reg.h>
15 #endif
16 #include <unistd.h>
17 #include <sys/ptrace.h>
18 #include <sys/param.h>
19 #include <sys/user.h>
20
21 #include "winbase.h"
22
23 #include "thread.h"
24 #include "request.h"
25
26
27 #ifndef PTRACE_PEEKUSER
28 #define PTRACE_PEEKUSER PT_READ_U
29 #endif
30 #ifndef PTRACE_POKEUSER
31 #define PTRACE_POKEUSER PT_WRITE_U
32 #endif
33 #ifndef PTRACE_GETREGS
34 #define PTRACE_GETREGS PT_GETREGS
35 #endif
36 #ifndef PTRACE_GETFPREGS
37 #define PTRACE_GETFPREGS PT_GETFPREGS
38 #endif
39 #ifndef PTRACE_SETREGS
40 #define PTRACE_SETREGS PT_SETREGS
41 #endif
42 #ifndef PTRACE_SETFPREGS
43 #define PTRACE_SETFPREGS PT_SETFPREGS
44 #endif
45
46 #ifdef linux
47
48 /* user_regs definitions from asm/user.h */
49 struct kernel_user_regs_struct
50 {
51     long ebx, ecx, edx, esi, edi, ebp, eax;
52     unsigned short ds, __ds, es, __es;
53     unsigned short fs, __fs, gs, __gs;
54     long orig_eax, eip;
55     unsigned short cs, __cs;
56     long eflags, esp;
57     unsigned short ss, __ss;
58 };
59
60 /* debug register offset in struct user */
61 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
62
63 /* retrieve a debug register */
64 static inline int get_debug_reg( int pid, int num, DWORD *data )
65 {
66     int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
67     if ((res == -1) && errno)
68     {
69         file_set_error();
70         return -1;
71     }
72     *data = res;
73     return 0;
74 }
75
76 /* retrieve a thread context */
77 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
78 {
79     int pid = thread->unix_pid;
80     if (flags & CONTEXT_FULL)
81     {
82         struct kernel_user_regs_struct regs;
83         if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
84         if (flags & CONTEXT_INTEGER)
85         {
86             context->Eax = regs.eax;
87             context->Ebx = regs.ebx;
88             context->Ecx = regs.ecx;
89             context->Edx = regs.edx;
90             context->Esi = regs.esi;
91             context->Edi = regs.edi;
92         }
93         if (flags & CONTEXT_CONTROL)
94         {
95             context->Ebp    = regs.ebp;
96             context->Esp    = regs.esp;
97             context->Eip    = regs.eip;
98             context->SegCs  = regs.cs;
99             context->SegSs  = regs.ss;
100             context->EFlags = regs.eflags;
101         }
102         if (flags & CONTEXT_SEGMENTS)
103         {
104             context->SegDs = regs.ds;
105             context->SegEs = regs.es;
106             context->SegFs = regs.fs;
107             context->SegGs = regs.gs;
108         }
109     }
110     if (flags & CONTEXT_DEBUG_REGISTERS)
111     {
112         if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
113         if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
114         if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
115         if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
116         if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
117         if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
118     }
119     if (flags & CONTEXT_FLOATING_POINT)
120     {
121         /* we can use context->FloatSave directly as it is using the */
122         /* correct structure (the same as fsave/frstor) */
123         if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
124         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
125     }
126     return;
127  error:
128     file_set_error();
129 }
130
131
132 /* set a thread context */
133 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
134 {
135     int pid = thread->unix_pid;
136     if (flags & CONTEXT_FULL)
137     {
138         struct kernel_user_regs_struct regs;
139         if ((flags & CONTEXT_FULL) != CONTEXT_FULL)  /* need to preserve some registers */
140         {
141             if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
142         }
143         if (flags & CONTEXT_INTEGER)
144         {
145             regs.eax = context->Eax;
146             regs.ebx = context->Ebx;
147             regs.ecx = context->Ecx;
148             regs.edx = context->Edx;
149             regs.esi = context->Esi;
150             regs.edi = context->Edi;
151         }
152         if (flags & CONTEXT_CONTROL)
153         {
154             regs.ebp = context->Ebp;
155             regs.esp = context->Esp;
156             regs.eip = context->Eip;
157             regs.cs  = context->SegCs;
158             regs.ss  = context->SegSs;
159             regs.eflags = context->EFlags;
160         }
161         if (flags & CONTEXT_SEGMENTS)
162         {
163             regs.ds = context->SegDs;
164             regs.es = context->SegEs;
165             regs.fs = context->SegFs;
166             regs.gs = context->SegGs;
167         }
168         if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
169     }
170     if (flags & CONTEXT_DEBUG_REGISTERS)
171     {
172         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
173         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
174         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
175         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
176         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
177         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
178     }
179     if (flags & CONTEXT_FLOATING_POINT)
180     {
181         /* we can use context->FloatSave directly as it is using the */
182         /* correct structure (the same as fsave/frstor) */
183         if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
184         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
185     }
186     return;
187  error:
188     file_set_error();
189 }
190
191 #elif defined(__sun__)
192
193 /* retrieve a thread context */
194 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
195 {
196     int pid = thread->unix_pid;
197     if (flags & CONTEXT_FULL)
198     {
199         struct regs regs;
200         if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
201         if (flags & CONTEXT_INTEGER)
202         {
203             context->Eax = regs.r_eax;
204             context->Ebx = regs.r_ebx;
205             context->Ecx = regs.r_ecx;
206             context->Edx = regs.r_edx;
207             context->Esi = regs.r_esi;
208             context->Edi = regs.r_edi;
209         }
210         if (flags & CONTEXT_CONTROL)
211         {
212             context->Ebp    = regs.r_ebp;
213             context->Esp    = regs.r_esp;
214             context->Eip    = regs.r_eip;
215             context->SegCs  = regs.r_cs & 0xffff;
216             context->SegSs  = regs.r_ss & 0xffff;
217             context->EFlags = regs.r_efl;
218         }
219         if (flags & CONTEXT_SEGMENTS)
220         {
221             context->SegDs = regs.r_ds & 0xffff;
222             context->SegEs = regs.r_es & 0xffff;
223             context->SegFs = regs.r_fs & 0xffff;
224             context->SegGs = regs.r_gs & 0xffff;
225         }
226     }
227     if (flags & CONTEXT_DEBUG_REGISTERS)
228     {
229         /* FIXME: How is this done on Solaris? */
230     }
231     if (flags & CONTEXT_FLOATING_POINT)
232     {
233         /* we can use context->FloatSave directly as it is using the */
234         /* correct structure (the same as fsave/frstor) */
235         if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
236         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
237     }
238     return;
239  error:
240     file_set_error();
241 }
242
243
244 /* set a thread context */
245 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
246 {
247     int pid = thread->unix_pid;
248     if (flags & CONTEXT_FULL)
249     {
250         struct regs regs;
251         if ((flags & CONTEXT_FULL) != CONTEXT_FULL)  /* need to preserve some registers */
252         {
253             if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
254         }
255         if (flags & CONTEXT_INTEGER)
256         {
257             regs.r_eax = context->Eax;
258             regs.r_ebx = context->Ebx;
259             regs.r_ecx = context->Ecx;
260             regs.r_edx = context->Edx;
261             regs.r_esi = context->Esi;
262             regs.r_edi = context->Edi;
263         }
264         if (flags & CONTEXT_CONTROL)
265         {
266             regs.r_ebp = context->Ebp;
267             regs.r_esp = context->Esp;
268             regs.r_eip = context->Eip;
269             regs.r_cs = context->SegCs;
270             regs.r_ss = context->SegSs;
271             regs.r_efl = context->EFlags;
272         }
273         if (flags & CONTEXT_SEGMENTS)
274         {
275             regs.r_ds = context->SegDs;
276             regs.r_es = context->SegEs;
277             regs.r_fs = context->SegFs;
278             regs.r_gs = context->SegGs;
279         }
280         if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
281     }
282     if (flags & CONTEXT_DEBUG_REGISTERS)
283     {
284         /* FIXME: How is this done on Solaris? */
285     }
286     if (flags & CONTEXT_FLOATING_POINT)
287     {
288         /* we can use context->FloatSave directly as it is using the */
289         /* correct structure (the same as fsave/frstor) */
290         if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
291         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
292     }
293     return;
294  error:
295     file_set_error();
296 }
297
298 #elif defined(__FreeBSD__)
299 #include <machine/reg.h>
300
301 /* retrieve a thread context */
302 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
303 {
304     int pid = thread->unix_pid;
305     if (flags & CONTEXT_FULL)
306     {
307         struct reg regs;
308         if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
309         if (flags & CONTEXT_INTEGER)
310         {
311             context->Eax = regs.r_eax;
312             context->Ebx = regs.r_ebx;
313             context->Ecx = regs.r_ecx;
314             context->Edx = regs.r_edx;
315             context->Esi = regs.r_esi;
316             context->Edi = regs.r_edi;
317         }
318         if (flags & CONTEXT_CONTROL)
319         {
320             context->Ebp    = regs.r_ebp;
321             context->Esp    = regs.r_esp;
322             context->Eip    = regs.r_eip;
323             context->SegCs  = regs.r_cs & 0xffff;
324             context->SegSs  = regs.r_ss & 0xffff;
325             context->EFlags = regs.r_eflags;
326         }
327         if (flags & CONTEXT_SEGMENTS)
328         {
329             context->SegDs = regs.r_ds & 0xffff;
330             context->SegEs = regs.r_es & 0xffff;
331             context->SegFs = regs.r_fs & 0xffff;
332             context->SegGs = regs.r_gs & 0xffff;
333         }
334     }
335     if (flags & CONTEXT_DEBUG_REGISTERS)
336     {
337         /* FIXME: How is this done on FreeBSD? */
338     }
339     if (flags & CONTEXT_FLOATING_POINT)
340     {
341         /* we can use context->FloatSave directly as it is using the */
342         /* correct structure (the same as fsave/frstor) */
343         if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
344         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
345     }
346     return;
347  error:
348     file_set_error();
349 }
350
351
352 /* set a thread context */
353 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
354 {
355     int pid = thread->unix_pid;
356     if (flags & CONTEXT_FULL)
357     {
358         struct reg regs;
359         if ((flags & CONTEXT_FULL) != CONTEXT_FULL)  /* need to preserve some registers */
360         {
361             if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
362         }
363         if (flags & CONTEXT_INTEGER)
364         {
365             regs.r_eax = context->Eax;
366             regs.r_ebx = context->Ebx;
367             regs.r_ecx = context->Ecx;
368             regs.r_edx = context->Edx;
369             regs.r_esi = context->Esi;
370             regs.r_edi = context->Edi;
371         }
372         if (flags & CONTEXT_CONTROL)
373         {
374             regs.r_ebp = context->Ebp;
375             regs.r_esp = context->Esp;
376             regs.r_eip = context->Eip;
377             regs.r_cs = context->SegCs;
378             regs.r_ss = context->SegSs;
379             regs.r_eflags = context->EFlags;
380         }
381         if (flags & CONTEXT_SEGMENTS)
382         {
383             regs.r_ds = context->SegDs;
384             regs.r_es = context->SegEs;
385             regs.r_fs = context->SegFs;
386             regs.r_gs = context->SegGs;
387         }
388         if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
389     }
390     if (flags & CONTEXT_DEBUG_REGISTERS)
391     {
392         /* FIXME: How is this done on FreeBSD? */
393     }
394     if (flags & CONTEXT_FLOATING_POINT)
395     {
396         /* we can use context->FloatSave directly as it is using the */
397         /* correct structure (the same as fsave/frstor) */
398         if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
399         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
400     }
401     return;
402  error:
403     file_set_error();
404 }
405
406 #else  /* linux || __sun__ || __FreeBSD__ */
407 #error You must implement get/set_thread_context for your platform
408 #endif  /* linux || __sun__ || __FreeBSD__ */
409
410
411 /* copy a context structure according to the flags */
412 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
413 {
414     if (flags & CONTEXT_CONTROL)
415     {
416         to->Ebp    = from->Ebp;
417         to->Eip    = from->Eip;
418         to->Esp    = from->Esp;
419         to->SegCs  = from->SegCs;
420         to->SegSs  = from->SegSs;
421         to->EFlags = from->EFlags;
422     }
423     if (flags & CONTEXT_INTEGER)
424     {
425         to->Eax = from->Eax;
426         to->Ebx = from->Ebx;
427         to->Ecx = from->Ecx;
428         to->Edx = from->Edx;
429         to->Esi = from->Esi;
430         to->Edi = from->Edi;
431     }
432     if (flags & CONTEXT_SEGMENTS)
433     {
434         to->SegDs = from->SegDs;
435         to->SegEs = from->SegEs;
436         to->SegFs = from->SegFs;
437         to->SegGs = from->SegGs;
438     }
439     if (flags & CONTEXT_DEBUG_REGISTERS)
440     {
441         to->Dr0 = from->Dr0;
442         to->Dr1 = from->Dr1;
443         to->Dr2 = from->Dr2;
444         to->Dr3 = from->Dr3;
445         to->Dr6 = from->Dr6;
446         to->Dr7 = from->Dr7;
447     }
448     if (flags & CONTEXT_FLOATING_POINT)
449     {
450         to->FloatSave = from->FloatSave;
451     }
452 }
453
454 /* retrieve the current context of a thread */
455 DECL_HANDLER(get_thread_context)
456 {
457     struct thread *thread;
458     CONTEXT *context;
459
460     if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
461     {
462         if ((context = get_debug_context( thread )))  /* thread is inside an exception event */
463         {
464             copy_context( &req->context, context, req->flags );
465         }
466         else
467         {
468             suspend_thread( thread, 0 );
469             if (thread->attached) get_thread_context( thread, req->flags, &req->context );
470             else set_error( STATUS_ACCESS_DENIED );
471             resume_thread( thread );
472         }
473         release_object( thread );
474     }
475 }
476
477
478 /* set the current context of a thread */
479 DECL_HANDLER(set_thread_context)
480 {
481     struct thread *thread;
482     CONTEXT *context;
483
484     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
485     {
486         if ((context = get_debug_context( thread )))  /* thread is inside an exception event */
487         {
488             copy_context( context, &req->context, req->flags );
489         }
490         else
491         {
492             suspend_thread( thread, 0 );
493             if (thread->attached) set_thread_context( thread, req->flags, &req->context );
494             else set_error( STATUS_ACCESS_DENIED );
495             resume_thread( thread );
496         }
497         release_object( thread );
498     }
499 }
500
501 #endif  /* __i386__ */