Add test for undocumented 0x4D message sent on F1.
[wine] / server / context_i386.c
1 /*
2  * i386 register context support
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #ifdef __i386__
24
25 #include <assert.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_REG_H
28 #include <sys/reg.h>
29 #endif
30 #include <stdarg.h>
31 #include <unistd.h>
32 #ifdef HAVE_SYS_PTRACE_H
33 # include <sys/ptrace.h>
34 #endif
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38
39 #include "windef.h"
40
41 #include "file.h"
42 #include "thread.h"
43 #include "request.h"
44
45 #ifndef PTRACE_PEEKUSER
46 #  ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
47 #    define PTRACE_PEEKUSER PTRACE_PEEKUSR
48 #  else
49 #    define PTRACE_PEEKUSER PT_READ_U
50 #  endif
51 #endif
52
53 #ifndef PTRACE_POKEUSER
54 #  ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
55 #    define PTRACE_POKEUSER PTRACE_POKEUSR
56 #  else
57 #    define PTRACE_POKEUSER PT_WRITE_U
58 #  endif
59 #endif
60
61 #ifndef PTRACE_GETREGS
62 #define PTRACE_GETREGS PT_GETREGS
63 #endif
64 #ifndef PTRACE_GETFPREGS
65 #define PTRACE_GETFPREGS PT_GETFPREGS
66 #endif
67 #ifndef PTRACE_SETREGS
68 #define PTRACE_SETREGS PT_SETREGS
69 #endif
70 #ifndef PTRACE_SETFPREGS
71 #define PTRACE_SETFPREGS PT_SETFPREGS
72 #endif
73
74 #ifdef PT_GETDBREGS
75 #define PTRACE_GETDBREGS PT_GETDBREGS
76 #endif
77
78 #ifdef PT_SETDBREGS
79 #define PTRACE_SETDBREGS PT_SETDBREGS
80 #endif
81
82 #ifdef linux
83 #ifdef HAVE_SYS_USER_H
84 # include <sys/user.h>
85 #endif
86
87 /* user_regs definitions from asm/user.h */
88 struct kernel_user_regs_struct
89 {
90     long ebx, ecx, edx, esi, edi, ebp, eax;
91     unsigned short ds, __ds, es, __es;
92     unsigned short fs, __fs, gs, __gs;
93     long orig_eax, eip;
94     unsigned short cs, __cs;
95     long eflags, esp;
96     unsigned short ss, __ss;
97 };
98
99 /* debug register offset in struct user */
100 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
101
102 /* retrieve a debug register */
103 static inline int get_debug_reg( int pid, int num, DWORD *data )
104 {
105     int res;
106     errno = 0;
107     res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
108     if ((res == -1) && errno)
109     {
110         file_set_error();
111         return -1;
112     }
113     *data = res;
114     return 0;
115 }
116
117 /* retrieve a thread context */
118 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
119 {
120     int pid = get_ptrace_pid(thread);
121     if (flags & CONTEXT_FULL)
122     {
123         struct kernel_user_regs_struct regs;
124         if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
125         if (flags & CONTEXT_INTEGER)
126         {
127             context->Eax = regs.eax;
128             context->Ebx = regs.ebx;
129             context->Ecx = regs.ecx;
130             context->Edx = regs.edx;
131             context->Esi = regs.esi;
132             context->Edi = regs.edi;
133         }
134         if (flags & CONTEXT_CONTROL)
135         {
136             context->Ebp    = regs.ebp;
137             context->Esp    = regs.esp;
138             context->Eip    = regs.eip;
139             context->SegCs  = regs.cs;
140             context->SegSs  = regs.ss;
141             context->EFlags = regs.eflags;
142         }
143         if (flags & CONTEXT_SEGMENTS)
144         {
145             context->SegDs = regs.ds;
146             context->SegEs = regs.es;
147             context->SegFs = regs.fs;
148             context->SegGs = regs.gs;
149         }
150     }
151     if (flags & CONTEXT_DEBUG_REGISTERS)
152     {
153         if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
154         if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
155         if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
156         if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
157         if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
158         if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
159     }
160     if (flags & CONTEXT_FLOATING_POINT)
161     {
162         /* we can use context->FloatSave directly as it is using the */
163         /* correct structure (the same as fsave/frstor) */
164         if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
165         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
166     }
167     return;
168  error:
169     file_set_error();
170 }
171
172
173 /* set a thread context */
174 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
175 {
176     int pid = get_ptrace_pid(thread);
177     if (flags & CONTEXT_FULL)
178     {
179         struct kernel_user_regs_struct regs;
180
181         /* need to preserve some registers (at a minimum orig_eax must always be preserved) */
182         if (ptrace( PTRACE_GETREGS, pid, 0, &regs ) == -1) goto error;
183
184         if (flags & CONTEXT_INTEGER)
185         {
186             regs.eax = context->Eax;
187             regs.ebx = context->Ebx;
188             regs.ecx = context->Ecx;
189             regs.edx = context->Edx;
190             regs.esi = context->Esi;
191             regs.edi = context->Edi;
192         }
193         if (flags & CONTEXT_CONTROL)
194         {
195             regs.ebp = context->Ebp;
196             regs.esp = context->Esp;
197             regs.eip = context->Eip;
198             regs.cs  = context->SegCs;
199             regs.ss  = context->SegSs;
200             regs.eflags = context->EFlags;
201         }
202         if (flags & CONTEXT_SEGMENTS)
203         {
204             regs.ds = context->SegDs;
205             regs.es = context->SegEs;
206             regs.fs = context->SegFs;
207             regs.gs = context->SegGs;
208         }
209         if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
210     }
211     if (flags & CONTEXT_DEBUG_REGISTERS)
212     {
213         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
214         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
215         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
216         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
217         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
218         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
219     }
220     if (flags & CONTEXT_FLOATING_POINT)
221     {
222         /* we can use context->FloatSave directly as it is using the */
223         /* correct structure (the same as fsave/frstor) */
224         if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
225     }
226     return;
227  error:
228     file_set_error();
229 }
230
231 #elif defined(__sun) || defined(__sun__)
232
233 /* retrieve a thread context */
234 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
235 {
236     int pid = get_ptrace_pid(thread);
237     if (flags & CONTEXT_FULL)
238     {
239         struct regs regs;
240         if (ptrace( PTRACE_GETREGS, pid, (int) &regs, 0 ) == -1) goto error;
241         if (flags & CONTEXT_INTEGER)
242         {
243             context->Eax = regs.r_eax;
244             context->Ebx = regs.r_ebx;
245             context->Ecx = regs.r_ecx;
246             context->Edx = regs.r_edx;
247             context->Esi = regs.r_esi;
248             context->Edi = regs.r_edi;
249         }
250         if (flags & CONTEXT_CONTROL)
251         {
252             context->Ebp    = regs.r_ebp;
253             context->Esp    = regs.r_esp;
254             context->Eip    = regs.r_eip;
255             context->SegCs  = regs.r_cs & 0xffff;
256             context->SegSs  = regs.r_ss & 0xffff;
257             context->EFlags = regs.r_efl;
258         }
259         if (flags & CONTEXT_SEGMENTS)
260         {
261             context->SegDs = regs.r_ds & 0xffff;
262             context->SegEs = regs.r_es & 0xffff;
263             context->SegFs = regs.r_fs & 0xffff;
264             context->SegGs = regs.r_gs & 0xffff;
265         }
266     }
267     if (flags & CONTEXT_DEBUG_REGISTERS)
268     {
269         /* FIXME: How is this done on Solaris? */
270     }
271     if (flags & CONTEXT_FLOATING_POINT)
272     {
273         /* we can use context->FloatSave directly as it is using the */
274         /* correct structure (the same as fsave/frstor) */
275         if (ptrace( PTRACE_GETFPREGS, pid, (int) &context->FloatSave, 0 ) == -1) goto error;
276         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
277     }
278     return;
279  error:
280     file_set_error();
281 }
282
283
284 /* set a thread context */
285 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
286 {
287     int pid = get_ptrace_pid(thread);
288     if (flags & CONTEXT_FULL)
289     {
290         struct regs regs;
291         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
292         {
293             /* need to preserve some registers */
294             if (ptrace( PTRACE_GETREGS, pid, (int) &regs, 0 ) == -1) goto error;
295         }
296         if (flags & CONTEXT_INTEGER)
297         {
298             regs.r_eax = context->Eax;
299             regs.r_ebx = context->Ebx;
300             regs.r_ecx = context->Ecx;
301             regs.r_edx = context->Edx;
302             regs.r_esi = context->Esi;
303             regs.r_edi = context->Edi;
304         }
305         if (flags & CONTEXT_CONTROL)
306         {
307             regs.r_ebp = context->Ebp;
308             regs.r_esp = context->Esp;
309             regs.r_eip = context->Eip;
310             regs.r_cs = context->SegCs;
311             regs.r_ss = context->SegSs;
312             regs.r_efl = context->EFlags;
313         }
314         if (flags & CONTEXT_SEGMENTS)
315         {
316             regs.r_ds = context->SegDs;
317             regs.r_es = context->SegEs;
318             regs.r_fs = context->SegFs;
319             regs.r_gs = context->SegGs;
320         }
321         if (ptrace( PTRACE_SETREGS, pid, (int) &regs, 0 ) == -1) goto error;
322     }
323     if (flags & CONTEXT_DEBUG_REGISTERS)
324     {
325         /* FIXME: How is this done on Solaris? */
326     }
327     if (flags & CONTEXT_FLOATING_POINT)
328     {
329         /* we can use context->FloatSave directly as it is using the */
330         /* correct structure (the same as fsave/frstor) */
331         if (ptrace( PTRACE_SETFPREGS, pid, (int) &context->FloatSave, 0 ) == -1) goto error;
332     }
333     return;
334  error:
335     file_set_error();
336 }
337
338 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
339 #include <machine/reg.h>
340
341 /* retrieve a thread context */
342 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
343 {
344     int pid = get_ptrace_pid(thread);
345     if (flags & CONTEXT_FULL)
346     {
347         struct reg regs;
348         if (ptrace( PTRACE_GETREGS, pid, (caddr_t) &regs, 0 ) == -1) goto error;
349         if (flags & CONTEXT_INTEGER)
350         {
351             context->Eax = regs.r_eax;
352             context->Ebx = regs.r_ebx;
353             context->Ecx = regs.r_ecx;
354             context->Edx = regs.r_edx;
355             context->Esi = regs.r_esi;
356             context->Edi = regs.r_edi;
357         }
358         if (flags & CONTEXT_CONTROL)
359         {
360             context->Ebp    = regs.r_ebp;
361             context->Esp    = regs.r_esp;
362             context->Eip    = regs.r_eip;
363             context->SegCs  = regs.r_cs & 0xffff;
364             context->SegSs  = regs.r_ss & 0xffff;
365             context->EFlags = regs.r_eflags;
366         }
367         if (flags & CONTEXT_SEGMENTS)
368         {
369             context->SegDs = regs.r_ds & 0xffff;
370             context->SegEs = regs.r_es & 0xffff;
371             context->SegFs = regs.r_fs & 0xffff;
372             context->SegGs = regs.r_gs & 0xffff;
373         }
374     }
375     if (flags & CONTEXT_DEBUG_REGISTERS)
376     {
377 #ifdef PTRACE_GETDBREGS
378         struct dbreg dbregs;
379         if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
380                 goto error;
381 #ifdef DBREG_DRX
382         /* needed for FreeBSD, the structure fields have changed under 5.x */
383         context->Dr0 = DBREG_DRX((&dbregs), 0);
384         context->Dr1 = DBREG_DRX((&dbregs), 1);
385         context->Dr2 = DBREG_DRX((&dbregs), 2);
386         context->Dr3 = DBREG_DRX((&dbregs), 3);
387         context->Dr6 = DBREG_DRX((&dbregs), 6);
388         context->Dr7 = DBREG_DRX((&dbregs), 7);
389 #else
390         context->Dr0 = dbregs.dr0;
391         context->Dr1 = dbregs.dr1;
392         context->Dr2 = dbregs.dr2;
393         context->Dr3 = dbregs.dr3;
394         context->Dr6 = dbregs.dr6;
395         context->Dr7 = dbregs.dr7;
396 #endif
397
398 #endif
399     }
400     if (flags & CONTEXT_FLOATING_POINT)
401     {
402         /* we can use context->FloatSave directly as it is using the */
403         /* correct structure (the same as fsave/frstor) */
404         if (ptrace( PTRACE_GETFPREGS, pid, (caddr_t) &context->FloatSave, 0 ) == -1) goto error;
405         context->FloatSave.Cr0NpxState = 0;  /* FIXME */
406     }
407     return;
408  error:
409     file_set_error();
410 }
411
412
413 /* set a thread context */
414 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
415 {
416     int pid = get_ptrace_pid(thread);
417     if (flags & CONTEXT_FULL)
418     {
419         struct reg regs;
420         if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
421         {
422             /* need to preserve some registers */
423             if (ptrace( PTRACE_GETREGS, pid, (caddr_t) &regs, 0 ) == -1) goto error;
424         }
425         if (flags & CONTEXT_INTEGER)
426         {
427             regs.r_eax = context->Eax;
428             regs.r_ebx = context->Ebx;
429             regs.r_ecx = context->Ecx;
430             regs.r_edx = context->Edx;
431             regs.r_esi = context->Esi;
432             regs.r_edi = context->Edi;
433         }
434         if (flags & CONTEXT_CONTROL)
435         {
436             regs.r_ebp = context->Ebp;
437             regs.r_esp = context->Esp;
438             regs.r_eip = context->Eip;
439             regs.r_cs = context->SegCs;
440             regs.r_ss = context->SegSs;
441             regs.r_eflags = context->EFlags;
442         }
443         if (flags & CONTEXT_SEGMENTS)
444         {
445             regs.r_ds = context->SegDs;
446             regs.r_es = context->SegEs;
447             regs.r_fs = context->SegFs;
448             regs.r_gs = context->SegGs;
449         }
450         if (ptrace( PTRACE_SETREGS, pid, (caddr_t) &regs, 0 ) == -1) goto error;
451     }
452     if (flags & CONTEXT_DEBUG_REGISTERS)
453     {
454 #ifdef PTRACE_SETDBREGS
455         struct dbreg dbregs;
456 #ifdef DBREG_DRX
457         /* needed for FreeBSD, the structure fields have changed under 5.x */
458         DBREG_DRX((&dbregs), 0) = context->Dr0;
459         DBREG_DRX((&dbregs), 1) = context->Dr1;
460         DBREG_DRX((&dbregs), 2) = context->Dr2;
461         DBREG_DRX((&dbregs), 3) = context->Dr3;
462         DBREG_DRX((&dbregs), 4) = 0;
463         DBREG_DRX((&dbregs), 5) = 0;
464         DBREG_DRX((&dbregs), 6) = context->Dr6;
465         DBREG_DRX((&dbregs), 7) = context->Dr7;
466 #else
467         dbregs.dr0 = context->Dr0;
468         dbregs.dr1 = context->Dr1;
469         dbregs.dr2 = context->Dr2;
470         dbregs.dr3 = context->Dr3;
471         dbregs.dr4 = 0;
472         dbregs.dr5 = 0;
473         dbregs.dr6 = context->Dr6;
474         dbregs.dr7 = context->Dr7;
475 #endif
476         if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
477                 goto error;
478 #endif
479     }
480     if (flags & CONTEXT_FLOATING_POINT)
481     {
482         /* we can use context->FloatSave directly as it is using the */
483         /* correct structure (the same as fsave/frstor) */
484         if (ptrace( PTRACE_SETFPREGS, pid, (caddr_t) &context->FloatSave, 0 ) == -1) goto error;
485     }
486     return;
487  error:
488     file_set_error();
489 }
490
491 #else  /* linux || __sun__ || __FreeBSD__ */
492 #error You must implement get/set_thread_context for your platform
493 #endif  /* linux || __sun__ || __FreeBSD__ */
494
495
496 /* copy a context structure according to the flags */
497 static void copy_context( CONTEXT *to, const CONTEXT *from, int flags )
498 {
499     if (flags & CONTEXT_CONTROL)
500     {
501         to->Ebp    = from->Ebp;
502         to->Eip    = from->Eip;
503         to->Esp    = from->Esp;
504         to->SegCs  = from->SegCs;
505         to->SegSs  = from->SegSs;
506         to->EFlags = from->EFlags;
507     }
508     if (flags & CONTEXT_INTEGER)
509     {
510         to->Eax = from->Eax;
511         to->Ebx = from->Ebx;
512         to->Ecx = from->Ecx;
513         to->Edx = from->Edx;
514         to->Esi = from->Esi;
515         to->Edi = from->Edi;
516     }
517     if (flags & CONTEXT_SEGMENTS)
518     {
519         to->SegDs = from->SegDs;
520         to->SegEs = from->SegEs;
521         to->SegFs = from->SegFs;
522         to->SegGs = from->SegGs;
523     }
524     if (flags & CONTEXT_FLOATING_POINT)
525     {
526         to->FloatSave = from->FloatSave;
527     }
528     /* we don't bother copying the debug registers, since they */
529     /* always need to be accessed by ptrace anyway */
530 }
531
532 /* retrieve the current instruction pointer of a thread */
533 void *get_thread_ip( struct thread *thread )
534 {
535     CONTEXT context;
536     context.Eip = 0;
537     if (suspend_for_ptrace( thread ))
538     {
539         get_thread_context( thread, CONTEXT_CONTROL, &context );
540         resume_after_ptrace( thread );
541     }
542     return (void *)context.Eip;
543 }
544
545 /* determine if we should continue the thread in single-step mode */
546 int get_thread_single_step( struct thread *thread )
547 {
548     CONTEXT context;
549     if (thread->context) return 0;  /* don't single-step inside exception event */
550     get_thread_context( thread, CONTEXT_CONTROL, &context );
551     return (context.EFlags & 0x100) != 0;
552 }
553
554 /* send a signal to a specific thread */
555 int tkill( int pid, int sig )
556 {
557 #ifdef __linux__
558     int ret;
559     __asm__( "pushl %%ebx\n\t"
560              "movl %2,%%ebx\n\t"
561              "int $0x80\n\t"
562              "popl %%ebx\n\t"
563              : "=a" (ret)
564              : "0" (238) /*SYS_tkill*/, "r" (pid), "c" (sig) );
565     if (ret >= 0) return ret;
566     errno = -ret;
567     return -1;
568 #else
569     errno = ENOSYS;
570     return -1;
571 #endif
572 }
573
574 /* retrieve the current context of a thread */
575 DECL_HANDLER(get_thread_context)
576 {
577     struct thread *thread;
578     void *data;
579     int flags = req->flags & ~CONTEXT_i386;  /* get rid of CPU id */
580
581     if (get_reply_max_size() < sizeof(CONTEXT))
582     {
583         set_error( STATUS_INVALID_PARAMETER );
584         return;
585     }
586     if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
587
588     if ((data = set_reply_data_size( sizeof(CONTEXT) )))
589     {
590         /* copy incoming context into reply */
591         memset( data, 0, sizeof(CONTEXT) );
592         memcpy( data, get_req_data(), min( get_req_data_size(), sizeof(CONTEXT) ));
593
594         if (thread->context)  /* thread is inside an exception event */
595         {
596             copy_context( data, thread->context, flags );
597             flags &= CONTEXT_DEBUG_REGISTERS;
598         }
599         if (flags && suspend_for_ptrace( thread ))
600         {
601             get_thread_context( thread, flags, data );
602             resume_after_ptrace( thread );
603         }
604     }
605     release_object( thread );
606 }
607
608
609 /* set the current context of a thread */
610 DECL_HANDLER(set_thread_context)
611 {
612     struct thread *thread;
613     int flags = req->flags & ~CONTEXT_i386;  /* get rid of CPU id */
614
615     if (get_req_data_size() < sizeof(CONTEXT))
616     {
617         set_error( STATUS_INVALID_PARAMETER );
618         return;
619     }
620     if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
621     {
622         if (thread->context)  /* thread is inside an exception event */
623         {
624             copy_context( thread->context, get_req_data(), flags );
625             flags &= CONTEXT_DEBUG_REGISTERS;
626         }
627         if (flags && suspend_for_ptrace( thread ))
628         {
629             set_thread_context( thread, flags, get_req_data() );
630             resume_after_ptrace( thread );
631         }
632         release_object( thread );
633     }
634 }
635
636 #endif  /* __i386__ */