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