2 * i386 register context support
4 * Copyright (C) 1999 Alexandre Julliard
17 #include <sys/ptrace.h>
18 #include <sys/param.h>
27 #ifndef PTRACE_PEEKUSER
28 #define PTRACE_PEEKUSER PT_READ_U
30 #ifndef PTRACE_POKEUSER
31 #define PTRACE_POKEUSER PT_WRITE_U
33 #ifndef PTRACE_GETREGS
34 #define PTRACE_GETREGS PT_GETREGS
36 #ifndef PTRACE_GETFPREGS
37 #define PTRACE_GETFPREGS PT_GETFPREGS
39 #ifndef PTRACE_SETREGS
40 #define PTRACE_SETREGS PT_SETREGS
42 #ifndef PTRACE_SETFPREGS
43 #define PTRACE_SETFPREGS PT_SETFPREGS
48 /* user_regs definitions from asm/user.h */
49 struct kernel_user_regs_struct
51 long ebx, ecx, edx, esi, edi, ebp, eax;
52 unsigned short ds, __ds, es, __es;
53 unsigned short fs, __fs, gs, __gs;
55 unsigned short cs, __cs;
57 unsigned short ss, __ss;
60 /* debug register offset in struct user */
61 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
63 /* retrieve a debug register */
64 static inline int get_debug_reg( int pid, int num, DWORD *data )
66 int res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
67 if ((res == -1) && errno)
76 /* retrieve a thread context */
77 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
79 int pid = thread->unix_pid;
80 if (flags & CONTEXT_FULL)
82 struct kernel_user_regs_struct regs;
83 if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
84 if (flags & CONTEXT_INTEGER)
86 context->Eax = regs.eax;
87 context->Ebx = regs.ebx;
88 context->Ecx = regs.ecx;
89 context->Edx = regs.edx;
90 context->Esi = regs.esi;
91 context->Edi = regs.edi;
93 if (flags & CONTEXT_CONTROL)
95 context->Ebp = regs.ebp;
96 context->Esp = regs.esp;
97 context->Eip = regs.eip;
98 context->SegCs = regs.cs;
99 context->SegSs = regs.ss;
100 context->EFlags = regs.eflags;
102 if (flags & CONTEXT_SEGMENTS)
104 context->SegDs = regs.ds;
105 context->SegEs = regs.es;
106 context->SegFs = regs.fs;
107 context->SegGs = regs.gs;
110 if (flags & CONTEXT_DEBUG_REGISTERS)
112 if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
113 if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
114 if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
115 if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
116 if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
117 if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
119 if (flags & CONTEXT_FLOATING_POINT)
121 /* we can use context->FloatSave directly as it is using the */
122 /* correct structure (the same as fsave/frstor) */
123 if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
124 context->FloatSave.Cr0NpxState = 0; /* FIXME */
132 /* set a thread context */
133 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
135 int pid = thread->unix_pid;
136 if (flags & CONTEXT_FULL)
138 struct kernel_user_regs_struct regs;
139 if ((flags & CONTEXT_FULL) != CONTEXT_FULL) /* need to preserve some registers */
141 if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
143 if (flags & CONTEXT_INTEGER)
145 regs.eax = context->Eax;
146 regs.ebx = context->Ebx;
147 regs.ecx = context->Ecx;
148 regs.edx = context->Edx;
149 regs.esi = context->Esi;
150 regs.edi = context->Edi;
152 if (flags & CONTEXT_CONTROL)
154 regs.ebp = context->Ebp;
155 regs.esp = context->Esp;
156 regs.eip = context->Eip;
157 regs.cs = context->SegCs;
158 regs.ss = context->SegSs;
159 regs.eflags = context->EFlags;
161 if (flags & CONTEXT_SEGMENTS)
163 regs.ds = context->SegDs;
164 regs.es = context->SegEs;
165 regs.fs = context->SegFs;
166 regs.gs = context->SegGs;
168 if (ptrace( PTRACE_SETREGS, pid, 0, ®s ) == -1) goto error;
170 if (flags & CONTEXT_DEBUG_REGISTERS)
172 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
173 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
174 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
175 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
176 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
177 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
179 if (flags & CONTEXT_FLOATING_POINT)
181 /* we can use context->FloatSave directly as it is using the */
182 /* correct structure (the same as fsave/frstor) */
183 if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
184 context->FloatSave.Cr0NpxState = 0; /* FIXME */
191 #elif defined(__sun__)
193 /* retrieve a thread context */
194 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
196 int pid = thread->unix_pid;
197 if (flags & CONTEXT_FULL)
200 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
201 if (flags & CONTEXT_INTEGER)
203 context->Eax = regs.r_eax;
204 context->Ebx = regs.r_ebx;
205 context->Ecx = regs.r_ecx;
206 context->Edx = regs.r_edx;
207 context->Esi = regs.r_esi;
208 context->Edi = regs.r_edi;
210 if (flags & CONTEXT_CONTROL)
212 context->Ebp = regs.r_ebp;
213 context->Esp = regs.r_esp;
214 context->Eip = regs.r_eip;
215 context->SegCs = regs.r_cs & 0xffff;
216 context->SegSs = regs.r_ss & 0xffff;
217 context->EFlags = regs.r_efl;
219 if (flags & CONTEXT_SEGMENTS)
221 context->SegDs = regs.r_ds & 0xffff;
222 context->SegEs = regs.r_es & 0xffff;
223 context->SegFs = regs.r_fs & 0xffff;
224 context->SegGs = regs.r_gs & 0xffff;
227 if (flags & CONTEXT_DEBUG_REGISTERS)
229 /* FIXME: How is this done on Solaris? */
231 if (flags & CONTEXT_FLOATING_POINT)
233 /* we can use context->FloatSave directly as it is using the */
234 /* correct structure (the same as fsave/frstor) */
235 if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
236 context->FloatSave.Cr0NpxState = 0; /* FIXME */
244 /* set a thread context */
245 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
247 int pid = thread->unix_pid;
248 if (flags & CONTEXT_FULL)
251 if ((flags & CONTEXT_FULL) != CONTEXT_FULL) /* need to preserve some registers */
253 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
255 if (flags & CONTEXT_INTEGER)
257 regs.r_eax = context->Eax;
258 regs.r_ebx = context->Ebx;
259 regs.r_ecx = context->Ecx;
260 regs.r_edx = context->Edx;
261 regs.r_esi = context->Esi;
262 regs.r_edi = context->Edi;
264 if (flags & CONTEXT_CONTROL)
266 regs.r_ebp = context->Ebp;
267 regs.r_esp = context->Esp;
268 regs.r_eip = context->Eip;
269 regs.r_cs = context->SegCs;
270 regs.r_ss = context->SegSs;
271 regs.r_efl = context->EFlags;
273 if (flags & CONTEXT_SEGMENTS)
275 regs.r_ds = context->SegDs;
276 regs.r_es = context->SegEs;
277 regs.r_fs = context->SegFs;
278 regs.r_gs = context->SegGs;
280 if (ptrace( PTRACE_SETREGS, pid, 0, (int) ®s ) == -1) goto error;
282 if (flags & CONTEXT_DEBUG_REGISTERS)
284 /* FIXME: How is this done on Solaris? */
286 if (flags & CONTEXT_FLOATING_POINT)
288 /* we can use context->FloatSave directly as it is using the */
289 /* correct structure (the same as fsave/frstor) */
290 if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
291 context->FloatSave.Cr0NpxState = 0; /* FIXME */
298 #elif defined(__FreeBSD__)
299 #include <machine/reg.h>
301 /* retrieve a thread context */
302 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
304 int pid = thread->unix_pid;
305 if (flags & CONTEXT_FULL)
308 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
309 if (flags & CONTEXT_INTEGER)
311 context->Eax = regs.r_eax;
312 context->Ebx = regs.r_ebx;
313 context->Ecx = regs.r_ecx;
314 context->Edx = regs.r_edx;
315 context->Esi = regs.r_esi;
316 context->Edi = regs.r_edi;
318 if (flags & CONTEXT_CONTROL)
320 context->Ebp = regs.r_ebp;
321 context->Esp = regs.r_esp;
322 context->Eip = regs.r_eip;
323 context->SegCs = regs.r_cs & 0xffff;
324 context->SegSs = regs.r_ss & 0xffff;
325 context->EFlags = regs.r_eflags;
327 if (flags & CONTEXT_SEGMENTS)
329 context->SegDs = regs.r_ds & 0xffff;
330 context->SegEs = regs.r_es & 0xffff;
331 context->SegFs = regs.r_fs & 0xffff;
332 context->SegGs = regs.r_gs & 0xffff;
335 if (flags & CONTEXT_DEBUG_REGISTERS)
337 /* FIXME: How is this done on FreeBSD? */
339 if (flags & CONTEXT_FLOATING_POINT)
341 /* we can use context->FloatSave directly as it is using the */
342 /* correct structure (the same as fsave/frstor) */
343 if (ptrace( PTRACE_GETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
344 context->FloatSave.Cr0NpxState = 0; /* FIXME */
352 /* set a thread context */
353 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
355 int pid = thread->unix_pid;
356 if (flags & CONTEXT_FULL)
359 if ((flags & CONTEXT_FULL) != CONTEXT_FULL) /* need to preserve some registers */
361 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
363 if (flags & CONTEXT_INTEGER)
365 regs.r_eax = context->Eax;
366 regs.r_ebx = context->Ebx;
367 regs.r_ecx = context->Ecx;
368 regs.r_edx = context->Edx;
369 regs.r_esi = context->Esi;
370 regs.r_edi = context->Edi;
372 if (flags & CONTEXT_CONTROL)
374 regs.r_ebp = context->Ebp;
375 regs.r_esp = context->Esp;
376 regs.r_eip = context->Eip;
377 regs.r_cs = context->SegCs;
378 regs.r_ss = context->SegSs;
379 regs.r_eflags = context->EFlags;
381 if (flags & CONTEXT_SEGMENTS)
383 regs.r_ds = context->SegDs;
384 regs.r_es = context->SegEs;
385 regs.r_fs = context->SegFs;
386 regs.r_gs = context->SegGs;
388 if (ptrace( PTRACE_SETREGS, pid, 0, (int) ®s ) == -1) goto error;
390 if (flags & CONTEXT_DEBUG_REGISTERS)
392 /* FIXME: How is this done on FreeBSD? */
394 if (flags & CONTEXT_FLOATING_POINT)
396 /* we can use context->FloatSave directly as it is using the */
397 /* correct structure (the same as fsave/frstor) */
398 if (ptrace( PTRACE_SETFPREGS, pid, 0, (int) &context->FloatSave ) == -1) goto error;
399 context->FloatSave.Cr0NpxState = 0; /* FIXME */
406 #else /* linux || __sun__ || __FreeBSD__ */
407 #error You must implement get/set_thread_context for your platform
408 #endif /* linux || __sun__ || __FreeBSD__ */
411 /* copy a context structure according to the flags */
412 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
414 if (flags & CONTEXT_CONTROL)
419 to->SegCs = from->SegCs;
420 to->SegSs = from->SegSs;
421 to->EFlags = from->EFlags;
423 if (flags & CONTEXT_INTEGER)
432 if (flags & CONTEXT_SEGMENTS)
434 to->SegDs = from->SegDs;
435 to->SegEs = from->SegEs;
436 to->SegFs = from->SegFs;
437 to->SegGs = from->SegGs;
439 if (flags & CONTEXT_DEBUG_REGISTERS)
448 if (flags & CONTEXT_FLOATING_POINT)
450 to->FloatSave = from->FloatSave;
454 /* retrieve the current context of a thread */
455 DECL_HANDLER(get_thread_context)
457 struct thread *thread;
460 if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
462 if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
464 copy_context( &req->context, context, req->flags );
468 suspend_thread( thread, 0 );
469 if (thread->attached) get_thread_context( thread, req->flags, &req->context );
470 else set_error( STATUS_ACCESS_DENIED );
471 resume_thread( thread );
473 release_object( thread );
478 /* set the current context of a thread */
479 DECL_HANDLER(set_thread_context)
481 struct thread *thread;
484 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
486 if ((context = get_debug_context( thread ))) /* thread is inside an exception event */
488 copy_context( context, &req->context, req->flags );
492 suspend_thread( thread, 0 );
493 if (thread->attached) set_thread_context( thread, req->flags, &req->context );
494 else set_error( STATUS_ACCESS_DENIED );
495 resume_thread( thread );
497 release_object( thread );
501 #endif /* __i386__ */