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__ */