Weird thing with lcid of library is that if sublang is neutral then we
[wine/testsucceed.git] / server / context_i386.c
blobd72c89d872914660ab91746366a2a74e2ac5e1c4
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
24 #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
58 #ifdef HAVE_SYS_USER_H
59 # include <sys/user.h>
60 #endif
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, const CONTEXT *context )
149 int pid = thread->unix_pid;
150 if (flags & CONTEXT_FULL)
152 struct kernel_user_regs_struct regs;
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;
157 if (flags & CONTEXT_INTEGER)
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;
166 if (flags & CONTEXT_CONTROL)
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;
175 if (flags & CONTEXT_SEGMENTS)
177 regs.ds = context->SegDs;
178 regs.es = context->SegEs;
179 regs.fs = context->SegFs;
180 regs.gs = context->SegGs;
182 if (ptrace( PTRACE_SETREGS, pid, 0, &regs ) == -1) goto error;
184 if (flags & CONTEXT_DEBUG_REGISTERS)
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;
193 if (flags & CONTEXT_FLOATING_POINT)
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;
199 return;
200 error:
201 file_set_error();
204 #elif defined(__sun) || defined(__sun__)
206 /* retrieve a thread context */
207 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
209 int pid = thread->unix_pid;
210 if (flags & CONTEXT_FULL)
212 struct regs regs;
213 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
214 if (flags & CONTEXT_INTEGER)
216 context->Eax = regs.r_eax;
217 context->Ebx = regs.r_ebx;
218 context->Ecx = regs.r_ecx;
219 context->Edx = regs.r_edx;
220 context->Esi = regs.r_esi;
221 context->Edi = regs.r_edi;
223 if (flags & CONTEXT_CONTROL)
225 context->Ebp = regs.r_ebp;
226 context->Esp = regs.r_esp;
227 context->Eip = regs.r_eip;
228 context->SegCs = regs.r_cs & 0xffff;
229 context->SegSs = regs.r_ss & 0xffff;
230 context->EFlags = regs.r_efl;
232 if (flags & CONTEXT_SEGMENTS)
234 context->SegDs = regs.r_ds & 0xffff;
235 context->SegEs = regs.r_es & 0xffff;
236 context->SegFs = regs.r_fs & 0xffff;
237 context->SegGs = regs.r_gs & 0xffff;
240 if (flags & CONTEXT_DEBUG_REGISTERS)
242 /* FIXME: How is this done on Solaris? */
244 if (flags & CONTEXT_FLOATING_POINT)
246 /* we can use context->FloatSave directly as it is using the */
247 /* correct structure (the same as fsave/frstor) */
248 if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
249 context->FloatSave.Cr0NpxState = 0; /* FIXME */
251 return;
252 error:
253 file_set_error();
257 /* set a thread context */
258 static void set_thread_context( struct thread *thread, unsigned int flags, const CONTEXT *context )
260 int pid = thread->unix_pid;
261 if (flags & CONTEXT_FULL)
263 struct regs regs;
264 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
266 /* need to preserve some registers */
267 if (ptrace( PTRACE_GETREGS, pid, 0, (int) &regs ) == -1) goto error;
269 if (flags & CONTEXT_INTEGER)
271 regs.r_eax = context->Eax;
272 regs.r_ebx = context->Ebx;
273 regs.r_ecx = context->Ecx;
274 regs.r_edx = context->Edx;
275 regs.r_esi = context->Esi;
276 regs.r_edi = context->Edi;
278 if (flags & CONTEXT_CONTROL)
280 regs.r_ebp = context->Ebp;
281 regs.r_esp = context->Esp;
282 regs.r_eip = context->Eip;
283 regs.r_cs = context->SegCs;
284 regs.r_ss = context->SegSs;
285 regs.r_efl = context->EFlags;
287 if (flags & CONTEXT_SEGMENTS)
289 regs.r_ds = context->SegDs;
290 regs.r_es = context->SegEs;
291 regs.r_fs = context->SegFs;
292 regs.r_gs = context->SegGs;
294 if (ptrace( PTRACE_SETREGS, pid, 0, (int) &regs ) == -1) goto error;
296 if (flags & CONTEXT_DEBUG_REGISTERS)
298 /* FIXME: How is this done on Solaris? */
300 if (flags & CONTEXT_FLOATING_POINT)
302 /* we can use context->FloatSave directly as it is using the */
303 /* correct structure (the same as fsave/frstor) */
304 if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
306 return;
307 error:
308 file_set_error();
311 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
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, const 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;
414 return;
415 error:
416 file_set_error();
419 #else /* linux || __sun__ || __FreeBSD__ */
420 #error You must implement get/set_thread_context for your platform
421 #endif /* linux || __sun__ || __FreeBSD__ */
424 /* copy a context structure according to the flags */
425 static void copy_context( CONTEXT *to, const CONTEXT *from, int flags )
427 if (flags & CONTEXT_CONTROL)
429 to->Ebp = from->Ebp;
430 to->Eip = from->Eip;
431 to->Esp = from->Esp;
432 to->SegCs = from->SegCs;
433 to->SegSs = from->SegSs;
434 to->EFlags = from->EFlags;
436 if (flags & CONTEXT_INTEGER)
438 to->Eax = from->Eax;
439 to->Ebx = from->Ebx;
440 to->Ecx = from->Ecx;
441 to->Edx = from->Edx;
442 to->Esi = from->Esi;
443 to->Edi = from->Edi;
445 if (flags & CONTEXT_SEGMENTS)
447 to->SegDs = from->SegDs;
448 to->SegEs = from->SegEs;
449 to->SegFs = from->SegFs;
450 to->SegGs = from->SegGs;
452 if (flags & CONTEXT_FLOATING_POINT)
454 to->FloatSave = from->FloatSave;
456 /* we don't bother copying the debug registers, since they */
457 /* always need to be accessed by ptrace anyway */
460 /* retrieve the current instruction pointer of a thread */
461 void *get_thread_ip( struct thread *thread )
463 CONTEXT context;
464 context.Eip = 0;
465 if (suspend_for_ptrace( thread ))
467 get_thread_context( thread, CONTEXT_CONTROL, &context );
468 resume_thread( thread );
470 return (void *)context.Eip;
473 /* determine if we should continue the thread in single-step mode */
474 int get_thread_single_step( struct thread *thread )
476 CONTEXT context;
477 if (thread->context) return 0; /* don't single-step inside exception event */
478 get_thread_context( thread, CONTEXT_CONTROL, &context );
479 return (context.EFlags & 0x100) != 0;
482 /* retrieve the current context of a thread */
483 DECL_HANDLER(get_thread_context)
485 struct thread *thread;
486 void *data;
487 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
489 if (get_reply_max_size() < sizeof(CONTEXT))
491 set_error( STATUS_INVALID_PARAMETER );
492 return;
494 if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
496 if ((data = set_reply_data_size( sizeof(CONTEXT) )))
498 /* copy incoming context into reply */
499 memset( data, 0, sizeof(CONTEXT) );
500 memcpy( data, get_req_data(), min( get_req_data_size(), sizeof(CONTEXT) ));
502 if (thread->context) /* thread is inside an exception event */
504 copy_context( data, thread->context, flags );
505 flags &= CONTEXT_DEBUG_REGISTERS;
507 if (flags && suspend_for_ptrace( thread ))
509 get_thread_context( thread, flags, data );
510 resume_thread( thread );
513 release_object( thread );
517 /* set the current context of a thread */
518 DECL_HANDLER(set_thread_context)
520 struct thread *thread;
521 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
523 if (get_req_data_size() < sizeof(CONTEXT))
525 set_error( STATUS_INVALID_PARAMETER );
526 return;
528 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
530 if (thread->context) /* thread is inside an exception event */
532 copy_context( thread->context, get_req_data(), flags );
533 flags &= CONTEXT_DEBUG_REGISTERS;
535 if (flags && suspend_for_ptrace( thread ))
537 set_thread_context( thread, flags, get_req_data() );
538 resume_thread( thread );
540 release_object( thread );
544 #endif /* __i386__ */