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
;
153 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
155 /* need to preserve some registers */
156 if (ptrace( PTRACE_GETREGS
, pid
, 0, ®s
) == -1) goto error
;
158 if (flags
& CONTEXT_INTEGER
)
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
;
167 if (flags
& CONTEXT_CONTROL
)
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
;
176 if (flags
& CONTEXT_SEGMENTS
)
178 regs
.ds
= context
->SegDs
;
179 regs
.es
= context
->SegEs
;
180 regs
.fs
= context
->SegFs
;
181 regs
.gs
= context
->SegGs
;
183 if (ptrace( PTRACE_SETREGS
, pid
, 0, ®s
) == -1) goto error
;
185 if (flags
& CONTEXT_DEBUG_REGISTERS
)
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
;
194 if (flags
& CONTEXT_FLOATING_POINT
)
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 */
206 #elif defined(__sun) || defined(__sun__)
208 /* retrieve a thread context */
209 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
211 int pid
= thread
->unix_pid
;
212 if (flags
& CONTEXT_FULL
)
215 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
216 if (flags
& CONTEXT_INTEGER
)
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
;
225 if (flags
& CONTEXT_CONTROL
)
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
;
234 if (flags
& CONTEXT_SEGMENTS
)
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;
242 if (flags
& CONTEXT_DEBUG_REGISTERS
)
244 /* FIXME: How is this done on Solaris? */
246 if (flags
& CONTEXT_FLOATING_POINT
)
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 */
259 /* set a thread context */
260 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
262 int pid
= thread
->unix_pid
;
263 if (flags
& CONTEXT_FULL
)
266 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
268 /* need to preserve some registers */
269 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
271 if (flags
& CONTEXT_INTEGER
)
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
;
280 if (flags
& CONTEXT_CONTROL
)
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
;
289 if (flags
& CONTEXT_SEGMENTS
)
291 regs
.r_ds
= context
->SegDs
;
292 regs
.r_es
= context
->SegEs
;
293 regs
.r_fs
= context
->SegFs
;
294 regs
.r_gs
= context
->SegGs
;
296 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
298 if (flags
& CONTEXT_DEBUG_REGISTERS
)
300 /* FIXME: How is this done on Solaris? */
302 if (flags
& CONTEXT_FLOATING_POINT
)
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 */
314 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
315 #include <machine/reg.h>
317 /* retrieve a thread context */
318 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
320 int pid
= thread
->unix_pid
;
321 if (flags
& CONTEXT_FULL
)
324 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
325 if (flags
& CONTEXT_INTEGER
)
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
;
334 if (flags
& CONTEXT_CONTROL
)
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
;
343 if (flags
& CONTEXT_SEGMENTS
)
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;
351 if (flags
& CONTEXT_DEBUG_REGISTERS
)
353 /* FIXME: How is this done on FreeBSD? */
355 if (flags
& CONTEXT_FLOATING_POINT
)
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 */
368 /* set a thread context */
369 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
371 int pid
= thread
->unix_pid
;
372 if (flags
& CONTEXT_FULL
)
375 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
377 /* need to preserve some registers */
378 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
380 if (flags
& CONTEXT_INTEGER
)
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
;
389 if (flags
& CONTEXT_CONTROL
)
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
;
398 if (flags
& CONTEXT_SEGMENTS
)
400 regs
.r_ds
= context
->SegDs
;
401 regs
.r_es
= context
->SegEs
;
402 regs
.r_fs
= context
->SegFs
;
403 regs
.r_gs
= context
->SegGs
;
405 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
407 if (flags
& CONTEXT_DEBUG_REGISTERS
)
409 /* FIXME: How is this done on FreeBSD? */
411 if (flags
& CONTEXT_FLOATING_POINT
)
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 */
423 #else /* linux || __sun__ || __FreeBSD__ */
424 #error You must implement get/set_thread_context for your platform
425 #endif /* linux || __sun__ || __FreeBSD__ */
428 /* copy a context structure according to the flags */
429 static void copy_context( CONTEXT
*to
, CONTEXT
*from
, int flags
)
431 if (flags
& CONTEXT_CONTROL
)
436 to
->SegCs
= from
->SegCs
;
437 to
->SegSs
= from
->SegSs
;
438 to
->EFlags
= from
->EFlags
;
440 if (flags
& CONTEXT_INTEGER
)
449 if (flags
& CONTEXT_SEGMENTS
)
451 to
->SegDs
= from
->SegDs
;
452 to
->SegEs
= from
->SegEs
;
453 to
->SegFs
= from
->SegFs
;
454 to
->SegGs
= from
->SegGs
;
456 if (flags
& CONTEXT_FLOATING_POINT
)
458 to
->FloatSave
= from
->FloatSave
;
460 /* we don't bother copying the debug registers, since they */
461 /* always need to be accessed by ptrace anyway */
464 /* retrieve the current instruction pointer of a thread */
465 void *get_thread_ip( struct thread
*thread
)
469 if (suspend_for_ptrace( thread
))
471 get_thread_context( thread
, CONTEXT_CONTROL
, &context
);
472 resume_thread( thread
);
474 return (void *)context
.Eip
;
477 /* retrieve the current context of a thread */
478 DECL_HANDLER(get_thread_context
)
480 struct thread
*thread
;
481 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
483 if (get_req_data_size(req
) < sizeof(CONTEXT
))
485 set_error( STATUS_INVALID_PARAMETER
);
488 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_GET_CONTEXT
)))
490 if (thread
->context
) /* thread is inside an exception event */
492 copy_context( get_req_data(req
), thread
->context
, flags
);
493 flags
&= CONTEXT_DEBUG_REGISTERS
;
495 if (flags
&& suspend_for_ptrace( thread
))
497 get_thread_context( thread
, flags
, get_req_data(req
) );
498 resume_thread( thread
);
500 release_object( thread
);
505 /* set the current context of a thread */
506 DECL_HANDLER(set_thread_context
)
508 struct thread
*thread
;
509 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
511 if (get_req_data_size(req
) < sizeof(CONTEXT
))
513 set_error( STATUS_INVALID_PARAMETER
);
516 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_CONTEXT
)))
518 if (thread
->context
) /* thread is inside an exception event */
520 copy_context( thread
->context
, get_req_data(req
), flags
);
521 flags
&= CONTEXT_DEBUG_REGISTERS
;
523 if (flags
&& suspend_for_ptrace( thread
))
525 set_thread_context( thread
, flags
, get_req_data(req
) );
526 resume_thread( thread
);
528 release_object( thread
);
532 #endif /* __i386__ */