Use poll() on the client-side during server waits to implement
[wine.git] / server / context_i386.c
blob40fc8940d365bc10446e030788517f03a4fd46d9
1 /*
2 * i386 register context support
4 * Copyright (C) 1999 Alexandre Julliard
5 */
7 #include "config.h"
9 #ifdef __i386__
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 #ifdef HAVE_SYS_PTRACE_H
18 # include <sys/ptrace.h>
19 #endif
20 #ifdef HAVE_SYS_PARAM_H
21 # include <sys/param.h>
22 #endif
23 #ifdef HAVE_SYS_USER_H
24 # include <sys/user.h>
25 #endif
27 #include "winbase.h"
28 #include "thread.h"
29 #include "request.h"
31 #ifndef PTRACE_PEEKUSER
32 # ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
33 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
34 # else
35 # define PTRACE_PEEKUSER PT_READ_U
36 # endif
37 #endif
39 #ifndef PTRACE_POKEUSER
40 # ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
41 # define PTRACE_POKEUSER PTRACE_POKEUSR
42 # else
43 # define PTRACE_POKEUSER PT_WRITE_U
44 # endif
45 #endif
47 #ifndef PTRACE_GETREGS
48 #define PTRACE_GETREGS PT_GETREGS
49 #endif
50 #ifndef PTRACE_GETFPREGS
51 #define PTRACE_GETFPREGS PT_GETFPREGS
52 #endif
53 #ifndef PTRACE_SETREGS
54 #define PTRACE_SETREGS PT_SETREGS
55 #endif
56 #ifndef PTRACE_SETFPREGS
57 #define PTRACE_SETFPREGS PT_SETFPREGS
58 #endif
60 #ifdef linux
62 /* user_regs definitions from asm/user.h */
63 struct kernel_user_regs_struct
65 long ebx, ecx, edx, esi, edi, ebp, eax;
66 unsigned short ds, __ds, es, __es;
67 unsigned short fs, __fs, gs, __gs;
68 long orig_eax, eip;
69 unsigned short cs, __cs;
70 long eflags, esp;
71 unsigned short ss, __ss;
74 /* debug register offset in struct user */
75 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
77 /* retrieve a debug register */
78 static inline int get_debug_reg( int pid, int num, DWORD *data )
80 int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
81 if ((res == -1) && errno)
83 file_set_error();
84 return -1;
86 *data = res;
87 return 0;
90 /* retrieve a thread context */
91 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
93 int pid = thread->unix_pid;
94 if (flags & CONTEXT_FULL)
96 struct kernel_user_regs_struct regs;
97 if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
98 if (flags & CONTEXT_INTEGER)
100 context->Eax = regs.eax;
101 context->Ebx = regs.ebx;
102 context->Ecx = regs.ecx;
103 context->Edx = regs.edx;
104 context->Esi = regs.esi;
105 context->Edi = regs.edi;
107 if (flags & CONTEXT_CONTROL)
109 context->Ebp = regs.ebp;
110 context->Esp = regs.esp;
111 context->Eip = regs.eip;
112 context->SegCs = regs.cs;
113 context->SegSs = regs.ss;
114 context->EFlags = regs.eflags;
116 if (flags & CONTEXT_SEGMENTS)
118 context->SegDs = regs.ds;
119 context->SegEs = regs.es;
120 context->SegFs = regs.fs;
121 context->SegGs = regs.gs;
124 if (flags & CONTEXT_DEBUG_REGISTERS)
126 if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
127 if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
128 if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
129 if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
130 if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
131 if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
133 if (flags & CONTEXT_FLOATING_POINT)
135 /* we can use context->FloatSave directly as it is using the */
136 /* correct structure (the same as fsave/frstor) */
137 if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
138 context->FloatSave.Cr0NpxState = 0; /* FIXME */
140 return;
141 error:
142 file_set_error();
146 /* set a thread context */
147 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
149 int pid = thread->unix_pid;
150 if (flags & CONTEXT_FULL)
152 struct kernel_user_regs_struct regs;
153 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
155 /* need to preserve some registers */
156 if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
158 if (flags & CONTEXT_INTEGER)
160 regs.eax = context->Eax;
161 regs.ebx = context->Ebx;
162 regs.ecx = context->Ecx;
163 regs.edx = context->Edx;
164 regs.esi = context->Esi;
165 regs.edi = context->Edi;
167 if (flags & CONTEXT_CONTROL)
169 regs.ebp = context->Ebp;
170 regs.esp = context->Esp;
171 regs.eip = context->Eip;
172 regs.cs = context->SegCs;
173 regs.ss = context->SegSs;
174 regs.eflags = context->EFlags;
176 if (flags & CONTEXT_SEGMENTS)
178 regs.ds = context->SegDs;
179 regs.es = context->SegEs;
180 regs.fs = context->SegFs;
181 regs.gs = context->SegGs;
183 if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
185 if (flags & CONTEXT_DEBUG_REGISTERS)
187 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
188 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
189 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
190 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
191 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
192 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
194 if (flags & CONTEXT_FLOATING_POINT)
196 /* we can use context->FloatSave directly as it is using the */
197 /* correct structure (the same as fsave/frstor) */
198 if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
199 context->FloatSave.Cr0NpxState = 0; /* FIXME */
201 return;
202 error:
203 file_set_error();
206 #elif defined(__sun) || defined(__sun__)
208 /* retrieve a thread context */
209 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
211 int pid = thread->unix_pid;
212 if (flags & CONTEXT_FULL)
214 struct regs regs;
215 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
216 if (flags & CONTEXT_INTEGER)
218 context->Eax = regs.r_eax;
219 context->Ebx = regs.r_ebx;
220 context->Ecx = regs.r_ecx;
221 context->Edx = regs.r_edx;
222 context->Esi = regs.r_esi;
223 context->Edi = regs.r_edi;
225 if (flags & CONTEXT_CONTROL)
227 context->Ebp = regs.r_ebp;
228 context->Esp = regs.r_esp;
229 context->Eip = regs.r_eip;
230 context->SegCs = regs.r_cs & 0xffff;
231 context->SegSs = regs.r_ss & 0xffff;
232 context->EFlags = regs.r_efl;
234 if (flags & CONTEXT_SEGMENTS)
236 context->SegDs = regs.r_ds & 0xffff;
237 context->SegEs = regs.r_es & 0xffff;
238 context->SegFs = regs.r_fs & 0xffff;
239 context->SegGs = regs.r_gs & 0xffff;
242 if (flags & CONTEXT_DEBUG_REGISTERS)
244 /* FIXME: How is this done on Solaris? */
246 if (flags & CONTEXT_FLOATING_POINT)
248 /* we can use context->FloatSave directly as it is using the */
249 /* correct structure (the same as fsave/frstor) */
250 if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
251 context->FloatSave.Cr0NpxState = 0; /* FIXME */
253 return;
254 error:
255 file_set_error();
259 /* set a thread context */
260 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
262 int pid = thread->unix_pid;
263 if (flags & CONTEXT_FULL)
265 struct regs regs;
266 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
268 /* need to preserve some registers */
269 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
271 if (flags & CONTEXT_INTEGER)
273 regs.r_eax = context->Eax;
274 regs.r_ebx = context->Ebx;
275 regs.r_ecx = context->Ecx;
276 regs.r_edx = context->Edx;
277 regs.r_esi = context->Esi;
278 regs.r_edi = context->Edi;
280 if (flags & CONTEXT_CONTROL)
282 regs.r_ebp = context->Ebp;
283 regs.r_esp = context->Esp;
284 regs.r_eip = context->Eip;
285 regs.r_cs = context->SegCs;
286 regs.r_ss = context->SegSs;
287 regs.r_efl = context->EFlags;
289 if (flags & CONTEXT_SEGMENTS)
291 regs.r_ds = context->SegDs;
292 regs.r_es = context->SegEs;
293 regs.r_fs = context->SegFs;
294 regs.r_gs = context->SegGs;
296 if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
298 if (flags & CONTEXT_DEBUG_REGISTERS)
300 /* FIXME: How is this done on Solaris? */
302 if (flags & CONTEXT_FLOATING_POINT)
304 /* we can use context->FloatSave directly as it is using the */
305 /* correct structure (the same as fsave/frstor) */
306 if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
307 context->FloatSave.Cr0NpxState = 0; /* FIXME */
309 return;
310 error:
311 file_set_error();
314 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
315 #include <machine/reg.h>
317 /* retrieve a thread context */
318 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
320 int pid = thread->unix_pid;
321 if (flags & CONTEXT_FULL)
323 struct reg regs;
324 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
325 if (flags & CONTEXT_INTEGER)
327 context->Eax = regs.r_eax;
328 context->Ebx = regs.r_ebx;
329 context->Ecx = regs.r_ecx;
330 context->Edx = regs.r_edx;
331 context->Esi = regs.r_esi;
332 context->Edi = regs.r_edi;
334 if (flags & CONTEXT_CONTROL)
336 context->Ebp = regs.r_ebp;
337 context->Esp = regs.r_esp;
338 context->Eip = regs.r_eip;
339 context->SegCs = regs.r_cs & 0xffff;
340 context->SegSs = regs.r_ss & 0xffff;
341 context->EFlags = regs.r_eflags;
343 if (flags & CONTEXT_SEGMENTS)
345 context->SegDs = regs.r_ds & 0xffff;
346 context->SegEs = regs.r_es & 0xffff;
347 context->SegFs = regs.r_fs & 0xffff;
348 context->SegGs = regs.r_gs & 0xffff;
351 if (flags & CONTEXT_DEBUG_REGISTERS)
353 /* FIXME: How is this done on FreeBSD? */
355 if (flags & CONTEXT_FLOATING_POINT)
357 /* we can use context->FloatSave directly as it is using the */
358 /* correct structure (the same as fsave/frstor) */
359 if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
360 context->FloatSave.Cr0NpxState = 0; /* FIXME */
362 return;
363 error:
364 file_set_error();
368 /* set a thread context */
369 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
371 int pid = thread->unix_pid;
372 if (flags & CONTEXT_FULL)
374 struct reg regs;
375 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
377 /* need to preserve some registers */
378 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
380 if (flags & CONTEXT_INTEGER)
382 regs.r_eax = context->Eax;
383 regs.r_ebx = context->Ebx;
384 regs.r_ecx = context->Ecx;
385 regs.r_edx = context->Edx;
386 regs.r_esi = context->Esi;
387 regs.r_edi = context->Edi;
389 if (flags & CONTEXT_CONTROL)
391 regs.r_ebp = context->Ebp;
392 regs.r_esp = context->Esp;
393 regs.r_eip = context->Eip;
394 regs.r_cs = context->SegCs;
395 regs.r_ss = context->SegSs;
396 regs.r_eflags = context->EFlags;
398 if (flags & CONTEXT_SEGMENTS)
400 regs.r_ds = context->SegDs;
401 regs.r_es = context->SegEs;
402 regs.r_fs = context->SegFs;
403 regs.r_gs = context->SegGs;
405 if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
407 if (flags & CONTEXT_DEBUG_REGISTERS)
409 /* FIXME: How is this done on FreeBSD? */
411 if (flags & CONTEXT_FLOATING_POINT)
413 /* we can use context->FloatSave directly as it is using the */
414 /* correct structure (the same as fsave/frstor) */
415 if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
416 context->FloatSave.Cr0NpxState = 0; /* FIXME */
418 return;
419 error:
420 file_set_error();
423 #else /* linux || __sun__ || __FreeBSD__ */
424 #error You must implement get/set_thread_context for your platform
425 #endif /* linux || __sun__ || __FreeBSD__ */
428 /* copy a context structure according to the flags */
429 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
431 if (flags & CONTEXT_CONTROL)
433 to->Ebp = from->Ebp;
434 to->Eip = from->Eip;
435 to->Esp = from->Esp;
436 to->SegCs = from->SegCs;
437 to->SegSs = from->SegSs;
438 to->EFlags = from->EFlags;
440 if (flags & CONTEXT_INTEGER)
442 to->Eax = from->Eax;
443 to->Ebx = from->Ebx;
444 to->Ecx = from->Ecx;
445 to->Edx = from->Edx;
446 to->Esi = from->Esi;
447 to->Edi = from->Edi;
449 if (flags & CONTEXT_SEGMENTS)
451 to->SegDs = from->SegDs;
452 to->SegEs = from->SegEs;
453 to->SegFs = from->SegFs;
454 to->SegGs = from->SegGs;
456 if (flags & CONTEXT_FLOATING_POINT)
458 to->FloatSave = from->FloatSave;
460 /* we don't bother copying the debug registers, since they */
461 /* always need to be accessed by ptrace anyway */
464 /* retrieve the current instruction pointer of a thread */
465 void *get_thread_ip( struct thread *thread )
467 CONTEXT context;
468 context.Eip = 0;
469 if (suspend_for_ptrace( thread ))
471 get_thread_context( thread, CONTEXT_CONTROL, &context );
472 resume_thread( thread );
474 return (void *)context.Eip;
477 /* retrieve the current context of a thread */
478 DECL_HANDLER(get_thread_context)
480 struct thread *thread;
481 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
483 if (get_req_data_size(req) < sizeof(CONTEXT))
485 set_error( STATUS_INVALID_PARAMETER );
486 return;
488 if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
490 if (thread->context) /* thread is inside an exception event */
492 copy_context( get_req_data(req), thread->context, flags );
493 flags &= CONTEXT_DEBUG_REGISTERS;
495 if (flags && suspend_for_ptrace( thread ))
497 get_thread_context( thread, flags, get_req_data(req) );
498 resume_thread( thread );
500 release_object( thread );
505 /* set the current context of a thread */
506 DECL_HANDLER(set_thread_context)
508 struct thread *thread;
509 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
511 if (get_req_data_size(req) < sizeof(CONTEXT))
513 set_error( STATUS_INVALID_PARAMETER );
514 return;
516 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
518 if (thread->context) /* thread is inside an exception event */
520 copy_context( thread->context, get_req_data(req), flags );
521 flags &= CONTEXT_DEBUG_REGISTERS;
523 if (flags && suspend_for_ptrace( thread ))
525 set_thread_context( thread, flags, get_req_data(req) );
526 resume_thread( thread );
528 release_object( thread );
532 #endif /* __i386__ */