2 * i386 register context support
4 * Copyright (C) 1999 Alexandre Julliard
17 #include <sys/ptrace.h>
18 #ifdef HAVE_SYS_PARAM_H
19 # include <sys/param.h>
29 #ifndef PTRACE_PEEKUSER
30 #define PTRACE_PEEKUSER PT_READ_U
32 #ifndef PTRACE_POKEUSER
33 #define PTRACE_POKEUSER PT_WRITE_U
35 #ifndef PTRACE_GETREGS
36 #define PTRACE_GETREGS PT_GETREGS
38 #ifndef PTRACE_GETFPREGS
39 #define PTRACE_GETFPREGS PT_GETFPREGS
41 #ifndef PTRACE_SETREGS
42 #define PTRACE_SETREGS PT_SETREGS
44 #ifndef PTRACE_SETFPREGS
45 #define PTRACE_SETFPREGS PT_SETFPREGS
50 /* user_regs definitions from asm/user.h */
51 struct kernel_user_regs_struct
53 long ebx
, ecx
, edx
, esi
, edi
, ebp
, eax
;
54 unsigned short ds
, __ds
, es
, __es
;
55 unsigned short fs
, __fs
, gs
, __gs
;
57 unsigned short cs
, __cs
;
59 unsigned short ss
, __ss
;
62 /* debug register offset in struct user */
63 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
65 /* retrieve a debug register */
66 static inline int get_debug_reg( int pid
, int num
, DWORD
*data
)
68 int res
= ptrace( PTRACE_PEEKUSER
, pid
, DR_OFFSET(num
), 0 );
69 if ((res
== -1) && errno
)
78 /* retrieve a thread context */
79 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
81 int pid
= thread
->unix_pid
;
82 if (flags
& CONTEXT_FULL
)
84 struct kernel_user_regs_struct regs
;
85 if (ptrace( PTRACE_GETREGS
, pid
, 0, ®s
) == -1) goto error
;
86 if (flags
& CONTEXT_INTEGER
)
88 context
->Eax
= regs
.eax
;
89 context
->Ebx
= regs
.ebx
;
90 context
->Ecx
= regs
.ecx
;
91 context
->Edx
= regs
.edx
;
92 context
->Esi
= regs
.esi
;
93 context
->Edi
= regs
.edi
;
95 if (flags
& CONTEXT_CONTROL
)
97 context
->Ebp
= regs
.ebp
;
98 context
->Esp
= regs
.esp
;
99 context
->Eip
= regs
.eip
;
100 context
->SegCs
= regs
.cs
;
101 context
->SegSs
= regs
.ss
;
102 context
->EFlags
= regs
.eflags
;
104 if (flags
& CONTEXT_SEGMENTS
)
106 context
->SegDs
= regs
.ds
;
107 context
->SegEs
= regs
.es
;
108 context
->SegFs
= regs
.fs
;
109 context
->SegGs
= regs
.gs
;
112 if (flags
& CONTEXT_DEBUG_REGISTERS
)
114 if (get_debug_reg( pid
, 0, &context
->Dr0
) == -1) goto error
;
115 if (get_debug_reg( pid
, 1, &context
->Dr1
) == -1) goto error
;
116 if (get_debug_reg( pid
, 2, &context
->Dr2
) == -1) goto error
;
117 if (get_debug_reg( pid
, 3, &context
->Dr3
) == -1) goto error
;
118 if (get_debug_reg( pid
, 6, &context
->Dr6
) == -1) goto error
;
119 if (get_debug_reg( pid
, 7, &context
->Dr7
) == -1) goto error
;
121 if (flags
& CONTEXT_FLOATING_POINT
)
123 /* we can use context->FloatSave directly as it is using the */
124 /* correct structure (the same as fsave/frstor) */
125 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, &context
->FloatSave
) == -1) goto error
;
126 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
134 /* set a thread context */
135 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
137 int pid
= thread
->unix_pid
;
138 if (flags
& CONTEXT_FULL
)
140 struct kernel_user_regs_struct regs
;
141 if ((flags
& CONTEXT_FULL
) != CONTEXT_FULL
) /* need to preserve some registers */
143 if (ptrace( PTRACE_GETREGS
, pid
, 0, ®s
) == -1) goto error
;
145 if (flags
& CONTEXT_INTEGER
)
147 regs
.eax
= context
->Eax
;
148 regs
.ebx
= context
->Ebx
;
149 regs
.ecx
= context
->Ecx
;
150 regs
.edx
= context
->Edx
;
151 regs
.esi
= context
->Esi
;
152 regs
.edi
= context
->Edi
;
154 if (flags
& CONTEXT_CONTROL
)
156 regs
.ebp
= context
->Ebp
;
157 regs
.esp
= context
->Esp
;
158 regs
.eip
= context
->Eip
;
159 regs
.cs
= context
->SegCs
;
160 regs
.ss
= context
->SegSs
;
161 regs
.eflags
= context
->EFlags
;
163 if (flags
& CONTEXT_SEGMENTS
)
165 regs
.ds
= context
->SegDs
;
166 regs
.es
= context
->SegEs
;
167 regs
.fs
= context
->SegFs
;
168 regs
.gs
= context
->SegGs
;
170 if (ptrace( PTRACE_SETREGS
, pid
, 0, ®s
) == -1) goto error
;
172 if (flags
& CONTEXT_DEBUG_REGISTERS
)
174 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(0), context
->Dr0
) == -1) goto error
;
175 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(1), context
->Dr1
) == -1) goto error
;
176 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(2), context
->Dr2
) == -1) goto error
;
177 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(3), context
->Dr3
) == -1) goto error
;
178 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(6), context
->Dr6
) == -1) goto error
;
179 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(7), context
->Dr7
) == -1) goto error
;
181 if (flags
& CONTEXT_FLOATING_POINT
)
183 /* we can use context->FloatSave directly as it is using the */
184 /* correct structure (the same as fsave/frstor) */
185 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, &context
->FloatSave
) == -1) goto error
;
186 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
193 #elif defined(__sun) || defined(__sun__)
195 /* retrieve a thread context */
196 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
198 int pid
= thread
->unix_pid
;
199 if (flags
& CONTEXT_FULL
)
202 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
203 if (flags
& CONTEXT_INTEGER
)
205 context
->Eax
= regs
.r_eax
;
206 context
->Ebx
= regs
.r_ebx
;
207 context
->Ecx
= regs
.r_ecx
;
208 context
->Edx
= regs
.r_edx
;
209 context
->Esi
= regs
.r_esi
;
210 context
->Edi
= regs
.r_edi
;
212 if (flags
& CONTEXT_CONTROL
)
214 context
->Ebp
= regs
.r_ebp
;
215 context
->Esp
= regs
.r_esp
;
216 context
->Eip
= regs
.r_eip
;
217 context
->SegCs
= regs
.r_cs
& 0xffff;
218 context
->SegSs
= regs
.r_ss
& 0xffff;
219 context
->EFlags
= regs
.r_efl
;
221 if (flags
& CONTEXT_SEGMENTS
)
223 context
->SegDs
= regs
.r_ds
& 0xffff;
224 context
->SegEs
= regs
.r_es
& 0xffff;
225 context
->SegFs
= regs
.r_fs
& 0xffff;
226 context
->SegGs
= regs
.r_gs
& 0xffff;
229 if (flags
& CONTEXT_DEBUG_REGISTERS
)
231 /* FIXME: How is this done on Solaris? */
233 if (flags
& CONTEXT_FLOATING_POINT
)
235 /* we can use context->FloatSave directly as it is using the */
236 /* correct structure (the same as fsave/frstor) */
237 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
238 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
246 /* set a thread context */
247 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
249 int pid
= thread
->unix_pid
;
250 if (flags
& CONTEXT_FULL
)
253 if ((flags
& CONTEXT_FULL
) != CONTEXT_FULL
) /* need to preserve some registers */
255 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
257 if (flags
& CONTEXT_INTEGER
)
259 regs
.r_eax
= context
->Eax
;
260 regs
.r_ebx
= context
->Ebx
;
261 regs
.r_ecx
= context
->Ecx
;
262 regs
.r_edx
= context
->Edx
;
263 regs
.r_esi
= context
->Esi
;
264 regs
.r_edi
= context
->Edi
;
266 if (flags
& CONTEXT_CONTROL
)
268 regs
.r_ebp
= context
->Ebp
;
269 regs
.r_esp
= context
->Esp
;
270 regs
.r_eip
= context
->Eip
;
271 regs
.r_cs
= context
->SegCs
;
272 regs
.r_ss
= context
->SegSs
;
273 regs
.r_efl
= context
->EFlags
;
275 if (flags
& CONTEXT_SEGMENTS
)
277 regs
.r_ds
= context
->SegDs
;
278 regs
.r_es
= context
->SegEs
;
279 regs
.r_fs
= context
->SegFs
;
280 regs
.r_gs
= context
->SegGs
;
282 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
284 if (flags
& CONTEXT_DEBUG_REGISTERS
)
286 /* FIXME: How is this done on Solaris? */
288 if (flags
& CONTEXT_FLOATING_POINT
)
290 /* we can use context->FloatSave directly as it is using the */
291 /* correct structure (the same as fsave/frstor) */
292 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
293 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
300 #elif defined(__FreeBSD__)
301 #include <machine/reg.h>
303 /* retrieve a thread context */
304 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
306 int pid
= thread
->unix_pid
;
307 if (flags
& CONTEXT_FULL
)
310 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
311 if (flags
& CONTEXT_INTEGER
)
313 context
->Eax
= regs
.r_eax
;
314 context
->Ebx
= regs
.r_ebx
;
315 context
->Ecx
= regs
.r_ecx
;
316 context
->Edx
= regs
.r_edx
;
317 context
->Esi
= regs
.r_esi
;
318 context
->Edi
= regs
.r_edi
;
320 if (flags
& CONTEXT_CONTROL
)
322 context
->Ebp
= regs
.r_ebp
;
323 context
->Esp
= regs
.r_esp
;
324 context
->Eip
= regs
.r_eip
;
325 context
->SegCs
= regs
.r_cs
& 0xffff;
326 context
->SegSs
= regs
.r_ss
& 0xffff;
327 context
->EFlags
= regs
.r_eflags
;
329 if (flags
& CONTEXT_SEGMENTS
)
331 context
->SegDs
= regs
.r_ds
& 0xffff;
332 context
->SegEs
= regs
.r_es
& 0xffff;
333 context
->SegFs
= regs
.r_fs
& 0xffff;
334 context
->SegGs
= regs
.r_gs
& 0xffff;
337 if (flags
& CONTEXT_DEBUG_REGISTERS
)
339 /* FIXME: How is this done on FreeBSD? */
341 if (flags
& CONTEXT_FLOATING_POINT
)
343 /* we can use context->FloatSave directly as it is using the */
344 /* correct structure (the same as fsave/frstor) */
345 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
346 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
354 /* set a thread context */
355 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
357 int pid
= thread
->unix_pid
;
358 if (flags
& CONTEXT_FULL
)
361 if ((flags
& CONTEXT_FULL
) != CONTEXT_FULL
) /* need to preserve some registers */
363 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
365 if (flags
& CONTEXT_INTEGER
)
367 regs
.r_eax
= context
->Eax
;
368 regs
.r_ebx
= context
->Ebx
;
369 regs
.r_ecx
= context
->Ecx
;
370 regs
.r_edx
= context
->Edx
;
371 regs
.r_esi
= context
->Esi
;
372 regs
.r_edi
= context
->Edi
;
374 if (flags
& CONTEXT_CONTROL
)
376 regs
.r_ebp
= context
->Ebp
;
377 regs
.r_esp
= context
->Esp
;
378 regs
.r_eip
= context
->Eip
;
379 regs
.r_cs
= context
->SegCs
;
380 regs
.r_ss
= context
->SegSs
;
381 regs
.r_eflags
= context
->EFlags
;
383 if (flags
& CONTEXT_SEGMENTS
)
385 regs
.r_ds
= context
->SegDs
;
386 regs
.r_es
= context
->SegEs
;
387 regs
.r_fs
= context
->SegFs
;
388 regs
.r_gs
= context
->SegGs
;
390 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
392 if (flags
& CONTEXT_DEBUG_REGISTERS
)
394 /* FIXME: How is this done on FreeBSD? */
396 if (flags
& CONTEXT_FLOATING_POINT
)
398 /* we can use context->FloatSave directly as it is using the */
399 /* correct structure (the same as fsave/frstor) */
400 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
401 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
408 #else /* linux || __sun__ || __FreeBSD__ */
409 #error You must implement get/set_thread_context for your platform
410 #endif /* linux || __sun__ || __FreeBSD__ */
413 /* copy a context structure according to the flags */
414 static void copy_context( CONTEXT
*to
, CONTEXT
*from
, int flags
)
416 if (flags
& CONTEXT_CONTROL
)
421 to
->SegCs
= from
->SegCs
;
422 to
->SegSs
= from
->SegSs
;
423 to
->EFlags
= from
->EFlags
;
425 if (flags
& CONTEXT_INTEGER
)
434 if (flags
& CONTEXT_SEGMENTS
)
436 to
->SegDs
= from
->SegDs
;
437 to
->SegEs
= from
->SegEs
;
438 to
->SegFs
= from
->SegFs
;
439 to
->SegGs
= from
->SegGs
;
441 if (flags
& CONTEXT_DEBUG_REGISTERS
)
450 if (flags
& CONTEXT_FLOATING_POINT
)
452 to
->FloatSave
= from
->FloatSave
;
456 /* retrieve the current context of a thread */
457 DECL_HANDLER(get_thread_context
)
459 struct thread
*thread
;
462 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_GET_CONTEXT
)))
464 if ((context
= get_debug_context( thread
))) /* thread is inside an exception event */
466 copy_context( &req
->context
, context
, req
->flags
);
470 suspend_thread( thread
, 0 );
471 if (thread
->attached
) get_thread_context( thread
, req
->flags
, &req
->context
);
472 else set_error( STATUS_ACCESS_DENIED
);
473 resume_thread( thread
);
475 release_object( thread
);
480 /* set the current context of a thread */
481 DECL_HANDLER(set_thread_context
)
483 struct thread
*thread
;
486 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_CONTEXT
)))
488 if ((context
= get_debug_context( thread
))) /* thread is inside an exception event */
490 copy_context( context
, &req
->context
, req
->flags
);
494 suspend_thread( thread
, 0 );
495 if (thread
->attached
) set_thread_context( thread
, req
->flags
, &req
->context
);
496 else set_error( STATUS_ACCESS_DENIED
);
497 resume_thread( thread
);
499 release_object( thread
);
503 #endif /* __i386__ */