2 * i386 register context support
4 * Copyright (C) 1999 Alexandre Julliard
17 #ifdef HAVE_SYS_PTRACE_H
18 # include <sys/ptrace.h>
20 #ifdef HAVE_SYS_PARAM_H
21 # include <sys/param.h>
23 #ifdef HAVE_SYS_USER_H
24 # include <sys/user.h>
31 #ifndef PTRACE_PEEKUSER
32 # ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
33 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
35 # define PTRACE_PEEKUSER PT_READ_U
39 #ifndef PTRACE_POKEUSER
40 # ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
41 # define PTRACE_POKEUSER PTRACE_POKEUSR
43 # define PTRACE_POKEUSER PT_WRITE_U
47 #ifndef PTRACE_GETREGS
48 #define PTRACE_GETREGS PT_GETREGS
50 #ifndef PTRACE_GETFPREGS
51 #define PTRACE_GETFPREGS PT_GETFPREGS
53 #ifndef PTRACE_SETREGS
54 #define PTRACE_SETREGS PT_SETREGS
56 #ifndef PTRACE_SETFPREGS
57 #define PTRACE_SETFPREGS PT_SETFPREGS
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;
69 unsigned short cs, __cs;
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)
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, ®s ) == -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 */
146 /* set a thread context */
147 static void set_thread_context( struct thread *thread, unsigned int flags, 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, ®s ) == -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, ®s ) == -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;
198 context->FloatSave.Cr0NpxState = 0; /* FIXME */
205 #elif defined(__sun) || defined(__sun__)
207 /* retrieve a thread context */
208 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
210 int pid = thread->unix_pid;
211 if (flags & CONTEXT_FULL)
214 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
215 if (flags & CONTEXT_INTEGER)
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;
224 if (flags & CONTEXT_CONTROL)
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;
233 if (flags & CONTEXT_SEGMENTS)
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;
241 if (flags & CONTEXT_DEBUG_REGISTERS)
243 /* FIXME: How is this done on Solaris? */
245 if (flags & CONTEXT_FLOATING_POINT)
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 */
258 /* set a thread context */
259 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
261 int pid = thread->unix_pid;
262 if (flags & CONTEXT_FULL)
265 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
267 /* need to preserve some registers */
268 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
270 if (flags & CONTEXT_INTEGER)
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;
279 if (flags & CONTEXT_CONTROL)
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;
288 if (flags & CONTEXT_SEGMENTS)
290 regs.r_ds = context->SegDs;
291 regs.r_es = context->SegEs;
292 regs.r_fs = context->SegFs;
293 regs.r_gs = context->SegGs;
295 if (ptrace( PTRACE_SETREGS, pid, 0, (int) ®s ) == -1) goto error;
297 if (flags & CONTEXT_DEBUG_REGISTERS)
299 /* FIXME: How is this done on Solaris? */
301 if (flags & CONTEXT_FLOATING_POINT)
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 */
313 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
314 #include <machine/reg.h>
316 /* retrieve a thread context */
317 static void get_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
319 int pid = thread->unix_pid;
320 if (flags & CONTEXT_FULL)
323 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
324 if (flags & CONTEXT_INTEGER)
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;
333 if (flags & CONTEXT_CONTROL)
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;
342 if (flags & CONTEXT_SEGMENTS)
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;
350 if (flags & CONTEXT_DEBUG_REGISTERS)
352 /* FIXME: How is this done on FreeBSD? */
354 if (flags & CONTEXT_FLOATING_POINT)
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 */
367 /* set a thread context */
368 static void set_thread_context( struct thread *thread, unsigned int flags, CONTEXT *context )
370 int pid = thread->unix_pid;
371 if (flags & CONTEXT_FULL)
374 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
376 /* need to preserve some registers */
377 if (ptrace( PTRACE_GETREGS, pid, 0, (int) ®s ) == -1) goto error;
379 if (flags & CONTEXT_INTEGER)
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;
388 if (flags & CONTEXT_CONTROL)
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;
397 if (flags & CONTEXT_SEGMENTS)
399 regs.r_ds = context->SegDs;
400 regs.r_es = context->SegEs;
401 regs.r_fs = context->SegFs;
402 regs.r_gs = context->SegGs;
404 if (ptrace( PTRACE_SETREGS, pid, 0, (int) ®s ) == -1) goto error;
406 if (flags & CONTEXT_DEBUG_REGISTERS)
408 /* FIXME: How is this done on FreeBSD? */
410 if (flags & CONTEXT_FLOATING_POINT)
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 */
422 #else /* linux || __sun__ || __FreeBSD__ */
423 #error You must implement get/set_thread_context for your platform
424 #endif /* linux || __sun__ || __FreeBSD__ */
427 /* copy a context structure according to the flags */
428 static void copy_context( CONTEXT *to, CONTEXT *from, int flags )
430 if (flags & CONTEXT_CONTROL)
435 to->SegCs = from->SegCs;
436 to->SegSs = from->SegSs;
437 to->EFlags = from->EFlags;
439 if (flags & CONTEXT_INTEGER)
448 if (flags & CONTEXT_SEGMENTS)
450 to->SegDs = from->SegDs;
451 to->SegEs = from->SegEs;
452 to->SegFs = from->SegFs;
453 to->SegGs = from->SegGs;
455 if (flags & CONTEXT_FLOATING_POINT)
457 to->FloatSave = from->FloatSave;
459 /* we don't bother copying the debug registers, since they */
460 /* always need to be accessed by ptrace anyway */
463 /* retrieve the current instruction pointer of a thread */
464 void *get_thread_ip( struct thread *thread )
468 if (suspend_for_ptrace( thread ))
470 get_thread_context( thread, CONTEXT_CONTROL, &context );
471 resume_thread( thread );
473 return (void *)context.Eip;
476 /* determine if we should continue the thread in single-step mode */
477 int get_thread_single_step( struct thread *thread )
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;
485 /* retrieve the current context of a thread */
486 DECL_HANDLER(get_thread_context)
488 struct thread *thread;
489 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
491 if (get_req_data_size(req) < sizeof(CONTEXT))
493 set_error( STATUS_INVALID_PARAMETER );
496 if ((thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT )))
498 if (thread->context) /* thread is inside an exception event */
500 copy_context( get_req_data(req), thread->context, flags );
501 flags &= CONTEXT_DEBUG_REGISTERS;
503 if (flags && suspend_for_ptrace( thread ))
505 get_thread_context( thread, flags, get_req_data(req) );
506 resume_thread( thread );
508 release_object( thread );
513 /* set the current context of a thread */
514 DECL_HANDLER(set_thread_context)
516 struct thread *thread;
517 int flags = req->flags & ~CONTEXT_i386; /* get rid of CPU id */
519 if (get_req_data_size(req) < sizeof(CONTEXT))
521 set_error( STATUS_INVALID_PARAMETER );
524 if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
526 if (thread->context) /* thread is inside an exception event */
528 copy_context( thread->context, get_req_data(req), flags );
529 flags &= CONTEXT_DEBUG_REGISTERS;
531 if (flags && suspend_for_ptrace( thread ))
533 set_thread_context( thread, flags, get_req_data(req) );
534 resume_thread( thread );
536 release_object( thread );
540 #endif /* __i386__ */