Fixed test so 0xffffffff is properly recognized.
[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 #ifdef HAVE_SYS_USER_H
24 # include <sys/user.h>
25 #endif
26
27 #include "winbase.h"
28 #include "thread.h"
29 #include "request.h"
30
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
38
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
46
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
59
60 #ifdef linux
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         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
154         {
155             /* need to preserve some registers */
156             if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
157         }
158         if (flags & CONTEXT_INTEGER)
159         {
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;
166         }
167         if (flags & CONTEXT_CONTROL)
168         {
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;
175         }
176         if (flags & CONTEXT_SEGMENTS)
177         {
178             regs.ds = context->SegDs;
179             regs.es = context->SegEs;
180             regs.fs = context->SegFs;
181             regs.gs = context->SegGs;
182         }
183         if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
184     }
185     if (flags & CONTEXT_DEBUG_REGISTERS)
186     {
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;
193     }
194     if (flags & CONTEXT_FLOATING_POINT)
195     {
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 */
200     }
201     return;
202  error:
203     file_set_error();
204 }
205
206 #elif defined(__sun) || defined(__sun__)
207
208 /* retrieve a thread context */
209 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
210 {
211     int pid = thread->unix_pid;
212     if (flags & CONTEXT_FULL)
213     {
214         struct regs regs;
215         if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
216         if (flags & CONTEXT_INTEGER)
217         {
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;
224         }
225         if (flags & CONTEXT_CONTROL)
226         {
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;
233         }
234         if (flags & CONTEXT_SEGMENTS)
235         {
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;
240         }
241     }
242     if (flags & CONTEXT_DEBUG_REGISTERS)
243     {
244         /* FIXME: How is this done on Solaris? */
245     }
246     if (flags & CONTEXT_FLOATING_POINT)
247     {
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 */
252     }
253     return;
254  error:
255     file_set_error();
256 }
257
258
259 /* set a thread context */
260 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
261 {
262     int pid = thread->unix_pid;
263     if (flags & CONTEXT_FULL)
264     {
265         struct regs regs;
266         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
267         {
268             /* need to preserve some registers */
269             if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
270         }
271         if (flags & CONTEXT_INTEGER)
272         {
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;
279         }
280         if (flags & CONTEXT_CONTROL)
281         {
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;
288         }
289         if (flags & CONTEXT_SEGMENTS)
290         {
291             regs.r_ds = context->SegDs;
292             regs.r_es = context->SegEs;
293             regs.r_fs = context->SegFs;
294             regs.r_gs = context->SegGs;
295         }
296         if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
297     }
298     if (flags & CONTEXT_DEBUG_REGISTERS)
299     {
300         /* FIXME: How is this done on Solaris? */
301     }
302     if (flags & CONTEXT_FLOATING_POINT)
303     {
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 */
308     }
309     return;
310  error:
311     file_set_error();
312 }
313
314 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
315 #include <machine/reg.h>
316
317 /* retrieve a thread context */
318 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
319 {
320     int pid = thread->unix_pid;
321     if (flags & CONTEXT_FULL)
322     {
323         struct reg regs;
324         if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
325         if (flags & CONTEXT_INTEGER)
326         {
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;
333         }
334         if (flags & CONTEXT_CONTROL)
335         {
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;
342         }
343         if (flags & CONTEXT_SEGMENTS)
344         {
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;
349         }
350     }
351     if (flags & CONTEXT_DEBUG_REGISTERS)
352     {
353         /* FIXME: How is this done on FreeBSD? */
354     }
355     if (flags & CONTEXT_FLOATING_POINT)
356     {
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 */
361     }
362     return;
363  error:
364     file_set_error();
365 }
366
367
368 /* set a thread context */
369 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
370 {
371     int pid = thread->unix_pid;
372     if (flags & CONTEXT_FULL)
373     {
374         struct reg regs;
375         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
376         {
377             /* need to preserve some registers */
378             if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
379         }
380         if (flags & CONTEXT_INTEGER)
381         {
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;
388         }
389         if (flags & CONTEXT_CONTROL)
390         {
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;
397         }
398         if (flags & CONTEXT_SEGMENTS)
399         {
400             regs.r_ds = context->SegDs;
401             regs.r_es = context->SegEs;
402             regs.r_fs = context->SegFs;
403             regs.r_gs = context->SegGs;
404         }
405         if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
406     }
407     if (flags & CONTEXT_DEBUG_REGISTERS)
408     {
409         /* FIXME: How is this done on FreeBSD? */
410     }
411     if (flags & CONTEXT_FLOATING_POINT)
412     {
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 */
417     }
418     return;
419  error:
420     file_set_error();
421 }
422
423 #else  /* linux || __sun__ || __FreeBSD__ */
424 #error You must implement get/set_thread_context for your platform
425 #endif  /* linux || __sun__ || __FreeBSD__ */
426
427
428 /* copy a context structure according to the flags */
429 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
430 {
431     if (flags & CONTEXT_CONTROL)
432     {
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;
439     }
440     if (flags & CONTEXT_INTEGER)
441     {
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;
448     }
449     if (flags & CONTEXT_SEGMENTS)
450     {
451         to->SegDs = from->SegDs;
452         to->SegEs = from->SegEs;
453         to->SegFs = from->SegFs;
454         to->SegGs = from->SegGs;
455     }
456     if (flags & CONTEXT_FLOATING_POINT)
457     {
458         to->FloatSave = from->FloatSave;
459     }
460     /* we don't bother copying the debug registers, since they */
461     /* always need to be accessed by ptrace anyway */
462 }
463
464 /* retrieve the current instruction pointer of a thread */
465 void *get_thread_ip( struct thread *thread )
466 {
467     CONTEXT context;
468     context.Eip = 0;
469     if (suspend_for_ptrace( thread ))
470     {
471         get_thread_context( thread, CONTEXT_CONTROL, &context );
472         resume_thread( thread );
473     }
474     return (void *)context.Eip;
475 }
476
477 /* determine if we should continue the thread in single-step mode */
478 int get_thread_single_step( struct thread *thread )
479 {
480     CONTEXT context;
481     if (thread->context) return 0;  /* don't single-step inside exception event */
482     get_thread_context( thread, CONTEXT_CONTROL, &context );
483     return (context.EFlags & 0x100) != 0;
484 }
485
486 /* retrieve the current context of a thread */
487 DECL_HANDLER(get_thread_context)
488 {
489     struct thread *thread;
490     int flags = req->flags & ~CONTEXT_i386;  /* get rid of CPU id */
491
492     if (get_req_data_size(req) < sizeof(CONTEXT))
493     {
494         set_error( STATUS_INVALID_PARAMETER );
495         return;
496     }
497     if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
498     {
499         if (thread->context)  /* thread is inside an exception event */
500         {
501             copy_context( get_req_data(req), thread->context, flags );
502             flags &= CONTEXT_DEBUG_REGISTERS;
503         }
504         if (flags && suspend_for_ptrace( thread ))
505         {
506             get_thread_context( thread, flags, get_req_data(req) );
507             resume_thread( thread );
508         }
509         release_object( thread );
510     }
511 }
512
513
514 /* set the current context of a thread */
515 DECL_HANDLER(set_thread_context)
516 {
517     struct thread *thread;
518     int flags = req->flags & ~CONTEXT_i386;  /* get rid of CPU id */
519
520     if (get_req_data_size(req) < sizeof(CONTEXT))
521     {
522         set_error( STATUS_INVALID_PARAMETER );
523         return;
524     }
525     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
526     {
527         if (thread->context)  /* thread is inside an exception event */
528         {
529             copy_context( thread->context, get_req_data(req), flags );
530             flags &= CONTEXT_DEBUG_REGISTERS;
531         }
532         if (flags && suspend_for_ptrace( thread ))
533         {
534             set_thread_context( thread, flags, get_req_data(req) );
535             resume_thread( thread );
536         }
537         release_object( thread );
538     }
539 }
540
541 #endif  /* __i386__ */