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