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>
28 #ifndef PTRACE_PEEKUSER
29 # ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
30 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
32 # define PTRACE_PEEKUSER PT_READ_U
36 #ifndef PTRACE_POKEUSER
37 # ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
38 # define PTRACE_POKEUSER PTRACE_POKEUSR
40 # define PTRACE_POKEUSER PT_WRITE_U
44 #ifndef PTRACE_GETREGS
45 #define PTRACE_GETREGS PT_GETREGS
47 #ifndef PTRACE_GETFPREGS
48 #define PTRACE_GETFPREGS PT_GETFPREGS
50 #ifndef PTRACE_SETREGS
51 #define PTRACE_SETREGS PT_SETREGS
53 #ifndef PTRACE_SETFPREGS
54 #define PTRACE_SETFPREGS PT_SETFPREGS
58 #ifdef HAVE_SYS_USER_H
59 # include <sys/user.h>
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
, const 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
;
204 #elif defined(__sun) || defined(__sun__)
206 /* retrieve a thread context */
207 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
209 int pid
= thread
->unix_pid
;
210 if (flags
& CONTEXT_FULL
)
213 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
214 if (flags
& CONTEXT_INTEGER
)
216 context
->Eax
= regs
.r_eax
;
217 context
->Ebx
= regs
.r_ebx
;
218 context
->Ecx
= regs
.r_ecx
;
219 context
->Edx
= regs
.r_edx
;
220 context
->Esi
= regs
.r_esi
;
221 context
->Edi
= regs
.r_edi
;
223 if (flags
& CONTEXT_CONTROL
)
225 context
->Ebp
= regs
.r_ebp
;
226 context
->Esp
= regs
.r_esp
;
227 context
->Eip
= regs
.r_eip
;
228 context
->SegCs
= regs
.r_cs
& 0xffff;
229 context
->SegSs
= regs
.r_ss
& 0xffff;
230 context
->EFlags
= regs
.r_efl
;
232 if (flags
& CONTEXT_SEGMENTS
)
234 context
->SegDs
= regs
.r_ds
& 0xffff;
235 context
->SegEs
= regs
.r_es
& 0xffff;
236 context
->SegFs
= regs
.r_fs
& 0xffff;
237 context
->SegGs
= regs
.r_gs
& 0xffff;
240 if (flags
& CONTEXT_DEBUG_REGISTERS
)
242 /* FIXME: How is this done on Solaris? */
244 if (flags
& CONTEXT_FLOATING_POINT
)
246 /* we can use context->FloatSave directly as it is using the */
247 /* correct structure (the same as fsave/frstor) */
248 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
249 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
257 /* set a thread context */
258 static void set_thread_context( struct thread
*thread
, unsigned int flags
, const CONTEXT
*context
)
260 int pid
= thread
->unix_pid
;
261 if (flags
& CONTEXT_FULL
)
264 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
266 /* need to preserve some registers */
267 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
269 if (flags
& CONTEXT_INTEGER
)
271 regs
.r_eax
= context
->Eax
;
272 regs
.r_ebx
= context
->Ebx
;
273 regs
.r_ecx
= context
->Ecx
;
274 regs
.r_edx
= context
->Edx
;
275 regs
.r_esi
= context
->Esi
;
276 regs
.r_edi
= context
->Edi
;
278 if (flags
& CONTEXT_CONTROL
)
280 regs
.r_ebp
= context
->Ebp
;
281 regs
.r_esp
= context
->Esp
;
282 regs
.r_eip
= context
->Eip
;
283 regs
.r_cs
= context
->SegCs
;
284 regs
.r_ss
= context
->SegSs
;
285 regs
.r_efl
= context
->EFlags
;
287 if (flags
& CONTEXT_SEGMENTS
)
289 regs
.r_ds
= context
->SegDs
;
290 regs
.r_es
= context
->SegEs
;
291 regs
.r_fs
= context
->SegFs
;
292 regs
.r_gs
= context
->SegGs
;
294 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
296 if (flags
& CONTEXT_DEBUG_REGISTERS
)
298 /* FIXME: How is this done on Solaris? */
300 if (flags
& CONTEXT_FLOATING_POINT
)
302 /* we can use context->FloatSave directly as it is using the */
303 /* correct structure (the same as fsave/frstor) */
304 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
311 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
312 #include <machine/reg.h>
314 /* retrieve a thread context */
315 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
317 int pid
= thread
->unix_pid
;
318 if (flags
& CONTEXT_FULL
)
321 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
322 if (flags
& CONTEXT_INTEGER
)
324 context
->Eax
= regs
.r_eax
;
325 context
->Ebx
= regs
.r_ebx
;
326 context
->Ecx
= regs
.r_ecx
;
327 context
->Edx
= regs
.r_edx
;
328 context
->Esi
= regs
.r_esi
;
329 context
->Edi
= regs
.r_edi
;
331 if (flags
& CONTEXT_CONTROL
)
333 context
->Ebp
= regs
.r_ebp
;
334 context
->Esp
= regs
.r_esp
;
335 context
->Eip
= regs
.r_eip
;
336 context
->SegCs
= regs
.r_cs
& 0xffff;
337 context
->SegSs
= regs
.r_ss
& 0xffff;
338 context
->EFlags
= regs
.r_eflags
;
340 if (flags
& CONTEXT_SEGMENTS
)
342 context
->SegDs
= regs
.r_ds
& 0xffff;
343 context
->SegEs
= regs
.r_es
& 0xffff;
344 context
->SegFs
= regs
.r_fs
& 0xffff;
345 context
->SegGs
= regs
.r_gs
& 0xffff;
348 if (flags
& CONTEXT_DEBUG_REGISTERS
)
350 /* FIXME: How is this done on FreeBSD? */
352 if (flags
& CONTEXT_FLOATING_POINT
)
354 /* we can use context->FloatSave directly as it is using the */
355 /* correct structure (the same as fsave/frstor) */
356 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
357 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
365 /* set a thread context */
366 static void set_thread_context( struct thread
*thread
, unsigned int flags
, const CONTEXT
*context
)
368 int pid
= thread
->unix_pid
;
369 if (flags
& CONTEXT_FULL
)
372 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
374 /* need to preserve some registers */
375 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
377 if (flags
& CONTEXT_INTEGER
)
379 regs
.r_eax
= context
->Eax
;
380 regs
.r_ebx
= context
->Ebx
;
381 regs
.r_ecx
= context
->Ecx
;
382 regs
.r_edx
= context
->Edx
;
383 regs
.r_esi
= context
->Esi
;
384 regs
.r_edi
= context
->Edi
;
386 if (flags
& CONTEXT_CONTROL
)
388 regs
.r_ebp
= context
->Ebp
;
389 regs
.r_esp
= context
->Esp
;
390 regs
.r_eip
= context
->Eip
;
391 regs
.r_cs
= context
->SegCs
;
392 regs
.r_ss
= context
->SegSs
;
393 regs
.r_eflags
= context
->EFlags
;
395 if (flags
& CONTEXT_SEGMENTS
)
397 regs
.r_ds
= context
->SegDs
;
398 regs
.r_es
= context
->SegEs
;
399 regs
.r_fs
= context
->SegFs
;
400 regs
.r_gs
= context
->SegGs
;
402 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
404 if (flags
& CONTEXT_DEBUG_REGISTERS
)
406 /* FIXME: How is this done on FreeBSD? */
408 if (flags
& CONTEXT_FLOATING_POINT
)
410 /* we can use context->FloatSave directly as it is using the */
411 /* correct structure (the same as fsave/frstor) */
412 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
419 #else /* linux || __sun__ || __FreeBSD__ */
420 #error You must implement get/set_thread_context for your platform
421 #endif /* linux || __sun__ || __FreeBSD__ */
424 /* copy a context structure according to the flags */
425 static void copy_context( CONTEXT
*to
, const CONTEXT
*from
, int flags
)
427 if (flags
& CONTEXT_CONTROL
)
432 to
->SegCs
= from
->SegCs
;
433 to
->SegSs
= from
->SegSs
;
434 to
->EFlags
= from
->EFlags
;
436 if (flags
& CONTEXT_INTEGER
)
445 if (flags
& CONTEXT_SEGMENTS
)
447 to
->SegDs
= from
->SegDs
;
448 to
->SegEs
= from
->SegEs
;
449 to
->SegFs
= from
->SegFs
;
450 to
->SegGs
= from
->SegGs
;
452 if (flags
& CONTEXT_FLOATING_POINT
)
454 to
->FloatSave
= from
->FloatSave
;
456 /* we don't bother copying the debug registers, since they */
457 /* always need to be accessed by ptrace anyway */
460 /* retrieve the current instruction pointer of a thread */
461 void *get_thread_ip( struct thread
*thread
)
465 if (suspend_for_ptrace( thread
))
467 get_thread_context( thread
, CONTEXT_CONTROL
, &context
);
468 resume_thread( thread
);
470 return (void *)context
.Eip
;
473 /* determine if we should continue the thread in single-step mode */
474 int get_thread_single_step( struct thread
*thread
)
477 if (thread
->context
) return 0; /* don't single-step inside exception event */
478 get_thread_context( thread
, CONTEXT_CONTROL
, &context
);
479 return (context
.EFlags
& 0x100) != 0;
482 /* retrieve the current context of a thread */
483 DECL_HANDLER(get_thread_context
)
485 struct thread
*thread
;
487 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
489 if (get_reply_max_size() < sizeof(CONTEXT
))
491 set_error( STATUS_INVALID_PARAMETER
);
494 if (!(thread
= get_thread_from_handle( req
->handle
, THREAD_GET_CONTEXT
))) return;
496 if ((data
= set_reply_data_size( sizeof(CONTEXT
) )))
498 /* copy incoming context into reply */
499 memset( data
, 0, sizeof(CONTEXT
) );
500 memcpy( data
, get_req_data(), min( get_req_data_size(), sizeof(CONTEXT
) ));
502 if (thread
->context
) /* thread is inside an exception event */
504 copy_context( data
, thread
->context
, flags
);
505 flags
&= CONTEXT_DEBUG_REGISTERS
;
507 if (flags
&& suspend_for_ptrace( thread
))
509 get_thread_context( thread
, flags
, data
);
510 resume_thread( thread
);
513 release_object( thread
);
517 /* set the current context of a thread */
518 DECL_HANDLER(set_thread_context
)
520 struct thread
*thread
;
521 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
523 if (get_req_data_size() < sizeof(CONTEXT
))
525 set_error( STATUS_INVALID_PARAMETER
);
528 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_CONTEXT
)))
530 if (thread
->context
) /* thread is inside an exception event */
532 copy_context( thread
->context
, get_req_data(), flags
);
533 flags
&= CONTEXT_DEBUG_REGISTERS
;
535 if (flags
&& suspend_for_ptrace( thread
))
537 set_thread_context( thread
, flags
, get_req_data() );
538 resume_thread( thread
);
540 release_object( thread
);
544 #endif /* __i386__ */