Fixed a couple of file descriptor leaks.
[wine/wine-kai.git] / server / context_i386.c
blob821b5287faa98e7ce07854031a5eaca43b8be852
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 #include <sys/ptrace.h>
18 #ifdef HAVE_SYS_PARAM_H
19 # include <sys/param.h>
20 #endif
21 #include <sys/user.h>
23 #include "winbase.h"
25 #include "thread.h"
26 #include "request.h"
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
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
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
57 #ifdef linux
59 /* user_regs definitions from asm/user.h */
60 struct kernel_user_regs_struct
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;
71 /* debug register offset in struct user */
72 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
74 /* retrieve a debug register */
75 static inline int get_debug_reg( int pid, int num, DWORD *data )
77 int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
78 if ((res == -1) && errno)
80 file_set_error();
81 return -1;
83 *data = res;
84 return 0;
87 /* retrieve a thread context */
88 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
90 int pid = thread->unix_pid;
91 if (flags & CONTEXT_FULL)
93 struct kernel_user_regs_struct regs;
94 if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
95 if (flags & CONTEXT_INTEGER)
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;
104 if (flags & CONTEXT_CONTROL)
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;
113 if (flags & CONTEXT_SEGMENTS)
115 context->SegDs = regs.ds;
116 context->SegEs = regs.es;
117 context->SegFs = regs.fs;
118 context->SegGs = regs.gs;
121 if (flags & CONTEXT_DEBUG_REGISTERS)
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;
130 if (flags & CONTEXT_FLOATING_POINT)
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 */
137 return;
138 error:
139 file_set_error();
143 /* set a thread context */
144 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
146 int pid = thread->unix_pid;
147 if (flags & CONTEXT_FULL)
149 struct kernel_user_regs_struct regs;
150 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
152 /* need to preserve some registers */
153 if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
155 if (flags & CONTEXT_INTEGER)
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;
164 if (flags & CONTEXT_CONTROL)
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;
173 if (flags & CONTEXT_SEGMENTS)
175 regs.ds = context->SegDs;
176 regs.es = context->SegEs;
177 regs.fs = context->SegFs;
178 regs.gs = context->SegGs;
180 if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
182 if (flags & CONTEXT_DEBUG_REGISTERS)
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;
191 if (flags & CONTEXT_FLOATING_POINT)
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 */
198 return;
199 error:
200 file_set_error();
203 #elif defined(__sun) || defined(__sun__)
205 /* retrieve a thread context */
206 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
208 int pid = thread->unix_pid;
209 if (flags & CONTEXT_FULL)
211 struct regs regs;
212 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
213 if (flags & CONTEXT_INTEGER)
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;
222 if (flags & CONTEXT_CONTROL)
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;
231 if (flags & CONTEXT_SEGMENTS)
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;
239 if (flags & CONTEXT_DEBUG_REGISTERS)
241 /* FIXME: How is this done on Solaris? */
243 if (flags & CONTEXT_FLOATING_POINT)
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 */
250 return;
251 error:
252 file_set_error();
256 /* set a thread context */
257 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
259 int pid = thread->unix_pid;
260 if (flags & CONTEXT_FULL)
262 struct regs regs;
263 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
265 /* need to preserve some registers */
266 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
268 if (flags & CONTEXT_INTEGER)
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;
277 if (flags & CONTEXT_CONTROL)
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;
286 if (flags & CONTEXT_SEGMENTS)
288 regs.r_ds = context->SegDs;
289 regs.r_es = context->SegEs;
290 regs.r_fs = context->SegFs;
291 regs.r_gs = context->SegGs;
293 if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
295 if (flags & CONTEXT_DEBUG_REGISTERS)
297 /* FIXME: How is this done on Solaris? */
299 if (flags & CONTEXT_FLOATING_POINT)
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 */
306 return;
307 error:
308 file_set_error();
311 #elif defined(__FreeBSD__)
312 #include <machine/reg.h>
314 /* retrieve a thread context */
315 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
317 int pid = thread->unix_pid;
318 if (flags & CONTEXT_FULL)
320 struct reg regs;
321 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
322 if (flags & CONTEXT_INTEGER)
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;
331 if (flags & CONTEXT_CONTROL)
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;
340 if (flags & CONTEXT_SEGMENTS)
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;
348 if (flags & CONTEXT_DEBUG_REGISTERS)
350 /* FIXME: How is this done on FreeBSD? */
352 if (flags & CONTEXT_FLOATING_POINT)
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 */
359 return;
360 error:
361 file_set_error();
365 /* set a thread context */
366 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
368 int pid = thread->unix_pid;
369 if (flags & CONTEXT_FULL)
371 struct reg regs;
372 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
374 /* need to preserve some registers */
375 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
377 if (flags & CONTEXT_INTEGER)
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;
386 if (flags & CONTEXT_CONTROL)
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;
395 if (flags & CONTEXT_SEGMENTS)
397 regs.r_ds = context->SegDs;
398 regs.r_es = context->SegEs;
399 regs.r_fs = context->SegFs;
400 regs.r_gs = context->SegGs;
402 if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
404 if (flags & CONTEXT_DEBUG_REGISTERS)
406 /* FIXME: How is this done on FreeBSD? */
408 if (flags & CONTEXT_FLOATING_POINT)
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 */
415 return;
416 error:
417 file_set_error();
420 #else /* linux || __sun__ || __FreeBSD__ */
421 #error You must implement get/set_thread_context for your platform
422 #endif /* linux || __sun__ || __FreeBSD__ */
425 /* copy a context structure according to the flags */
426 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
428 if (flags & CONTEXT_CONTROL)
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;
437 if (flags & CONTEXT_INTEGER)
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;
446 if (flags & CONTEXT_SEGMENTS)
448 to->SegDs = from->SegDs;
449 to->SegEs = from->SegEs;
450 to->SegFs = from->SegFs;
451 to->SegGs = from->SegGs;
453 if (flags & CONTEXT_FLOATING_POINT)
455 to->FloatSave = from->FloatSave;
457 /* we don't bother copying the debug registers, since they */
458 /* always need to be accessed by ptrace anyway */
461 /* retrieve the current context of a thread */
462 DECL_HANDLER(get_thread_context)
464 struct thread *thread;
465 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
467 if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
469 if (thread->context) /* thread is inside an exception event */
471 copy_context( &req->context, thread->context, flags );
472 flags &= CONTEXT_DEBUG_REGISTERS;
474 if (flags && suspend_for_ptrace( thread ))
476 get_thread_context( thread, flags, &req->context );
477 resume_thread( thread );
479 release_object( thread );
484 /* set the current context of a thread */
485 DECL_HANDLER(set_thread_context)
487 struct thread *thread;
488 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
490 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
492 if (thread->context) /* thread is inside an exception event */
494 copy_context( thread->context, &req->context, flags );
495 flags &= CONTEXT_DEBUG_REGISTERS;
497 if (flags && suspend_for_ptrace( thread ))
499 set_thread_context( thread, flags, &req->context );
500 resume_thread( thread );
502 release_object( thread );
506 #endif /* __i386__ */