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>
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
59 /* user_regs definitions from asm/user.h */
60 struct kernel_user_regs_struct
62 long ebx
, ecx
, edx
, esi
, edi
, ebp
, eax
;
63 unsigned short ds
, __ds
, es
, __es
;
64 unsigned short fs
, __fs
, gs
, __gs
;
66 unsigned short cs
, __cs
;
68 unsigned short ss
, __ss
;
71 /* debug register offset in struct user */
72 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
74 /* retrieve a debug register */
75 static inline int get_debug_reg( int pid
, int num
, DWORD
*data
)
77 int res
= ptrace( PTRACE_PEEKUSER
, pid
, DR_OFFSET(num
), 0 );
78 if ((res
== -1) && errno
)
87 /* retrieve a thread context */
88 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
90 int pid
= thread
->unix_pid
;
91 if (flags
& CONTEXT_FULL
)
93 struct kernel_user_regs_struct regs
;
94 if (ptrace( PTRACE_GETREGS
, pid
, 0, ®s
) == -1) goto error
;
95 if (flags
& CONTEXT_INTEGER
)
97 context
->Eax
= regs
.eax
;
98 context
->Ebx
= regs
.ebx
;
99 context
->Ecx
= regs
.ecx
;
100 context
->Edx
= regs
.edx
;
101 context
->Esi
= regs
.esi
;
102 context
->Edi
= regs
.edi
;
104 if (flags
& CONTEXT_CONTROL
)
106 context
->Ebp
= regs
.ebp
;
107 context
->Esp
= regs
.esp
;
108 context
->Eip
= regs
.eip
;
109 context
->SegCs
= regs
.cs
;
110 context
->SegSs
= regs
.ss
;
111 context
->EFlags
= regs
.eflags
;
113 if (flags
& CONTEXT_SEGMENTS
)
115 context
->SegDs
= regs
.ds
;
116 context
->SegEs
= regs
.es
;
117 context
->SegFs
= regs
.fs
;
118 context
->SegGs
= regs
.gs
;
121 if (flags
& CONTEXT_DEBUG_REGISTERS
)
123 if (get_debug_reg( pid
, 0, &context
->Dr0
) == -1) goto error
;
124 if (get_debug_reg( pid
, 1, &context
->Dr1
) == -1) goto error
;
125 if (get_debug_reg( pid
, 2, &context
->Dr2
) == -1) goto error
;
126 if (get_debug_reg( pid
, 3, &context
->Dr3
) == -1) goto error
;
127 if (get_debug_reg( pid
, 6, &context
->Dr6
) == -1) goto error
;
128 if (get_debug_reg( pid
, 7, &context
->Dr7
) == -1) goto error
;
130 if (flags
& CONTEXT_FLOATING_POINT
)
132 /* we can use context->FloatSave directly as it is using the */
133 /* correct structure (the same as fsave/frstor) */
134 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, &context
->FloatSave
) == -1) goto error
;
135 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
143 /* set a thread context */
144 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
146 int pid
= thread
->unix_pid
;
147 if (flags
& CONTEXT_FULL
)
149 struct kernel_user_regs_struct regs
;
150 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
152 /* need to preserve some registers */
153 if (ptrace( PTRACE_GETREGS
, pid
, 0, ®s
) == -1) goto error
;
155 if (flags
& CONTEXT_INTEGER
)
157 regs
.eax
= context
->Eax
;
158 regs
.ebx
= context
->Ebx
;
159 regs
.ecx
= context
->Ecx
;
160 regs
.edx
= context
->Edx
;
161 regs
.esi
= context
->Esi
;
162 regs
.edi
= context
->Edi
;
164 if (flags
& CONTEXT_CONTROL
)
166 regs
.ebp
= context
->Ebp
;
167 regs
.esp
= context
->Esp
;
168 regs
.eip
= context
->Eip
;
169 regs
.cs
= context
->SegCs
;
170 regs
.ss
= context
->SegSs
;
171 regs
.eflags
= context
->EFlags
;
173 if (flags
& CONTEXT_SEGMENTS
)
175 regs
.ds
= context
->SegDs
;
176 regs
.es
= context
->SegEs
;
177 regs
.fs
= context
->SegFs
;
178 regs
.gs
= context
->SegGs
;
180 if (ptrace( PTRACE_SETREGS
, pid
, 0, ®s
) == -1) goto error
;
182 if (flags
& CONTEXT_DEBUG_REGISTERS
)
184 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(0), context
->Dr0
) == -1) goto error
;
185 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(1), context
->Dr1
) == -1) goto error
;
186 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(2), context
->Dr2
) == -1) goto error
;
187 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(3), context
->Dr3
) == -1) goto error
;
188 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(6), context
->Dr6
) == -1) goto error
;
189 if (ptrace( PTRACE_POKEUSER
, pid
, DR_OFFSET(7), context
->Dr7
) == -1) goto error
;
191 if (flags
& CONTEXT_FLOATING_POINT
)
193 /* we can use context->FloatSave directly as it is using the */
194 /* correct structure (the same as fsave/frstor) */
195 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, &context
->FloatSave
) == -1) goto error
;
196 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
203 #elif defined(__sun) || defined(__sun__)
205 /* retrieve a thread context */
206 static void get_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
208 int pid
= thread
->unix_pid
;
209 if (flags
& CONTEXT_FULL
)
212 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
213 if (flags
& CONTEXT_INTEGER
)
215 context
->Eax
= regs
.r_eax
;
216 context
->Ebx
= regs
.r_ebx
;
217 context
->Ecx
= regs
.r_ecx
;
218 context
->Edx
= regs
.r_edx
;
219 context
->Esi
= regs
.r_esi
;
220 context
->Edi
= regs
.r_edi
;
222 if (flags
& CONTEXT_CONTROL
)
224 context
->Ebp
= regs
.r_ebp
;
225 context
->Esp
= regs
.r_esp
;
226 context
->Eip
= regs
.r_eip
;
227 context
->SegCs
= regs
.r_cs
& 0xffff;
228 context
->SegSs
= regs
.r_ss
& 0xffff;
229 context
->EFlags
= regs
.r_efl
;
231 if (flags
& CONTEXT_SEGMENTS
)
233 context
->SegDs
= regs
.r_ds
& 0xffff;
234 context
->SegEs
= regs
.r_es
& 0xffff;
235 context
->SegFs
= regs
.r_fs
& 0xffff;
236 context
->SegGs
= regs
.r_gs
& 0xffff;
239 if (flags
& CONTEXT_DEBUG_REGISTERS
)
241 /* FIXME: How is this done on Solaris? */
243 if (flags
& CONTEXT_FLOATING_POINT
)
245 /* we can use context->FloatSave directly as it is using the */
246 /* correct structure (the same as fsave/frstor) */
247 if (ptrace( PTRACE_GETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
248 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
256 /* set a thread context */
257 static void set_thread_context( struct thread
*thread
, unsigned int flags
, CONTEXT
*context
)
259 int pid
= thread
->unix_pid
;
260 if (flags
& CONTEXT_FULL
)
263 if (((flags
| CONTEXT_i386
) & CONTEXT_FULL
) != CONTEXT_FULL
)
265 /* need to preserve some registers */
266 if (ptrace( PTRACE_GETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
268 if (flags
& CONTEXT_INTEGER
)
270 regs
.r_eax
= context
->Eax
;
271 regs
.r_ebx
= context
->Ebx
;
272 regs
.r_ecx
= context
->Ecx
;
273 regs
.r_edx
= context
->Edx
;
274 regs
.r_esi
= context
->Esi
;
275 regs
.r_edi
= context
->Edi
;
277 if (flags
& CONTEXT_CONTROL
)
279 regs
.r_ebp
= context
->Ebp
;
280 regs
.r_esp
= context
->Esp
;
281 regs
.r_eip
= context
->Eip
;
282 regs
.r_cs
= context
->SegCs
;
283 regs
.r_ss
= context
->SegSs
;
284 regs
.r_efl
= context
->EFlags
;
286 if (flags
& CONTEXT_SEGMENTS
)
288 regs
.r_ds
= context
->SegDs
;
289 regs
.r_es
= context
->SegEs
;
290 regs
.r_fs
= context
->SegFs
;
291 regs
.r_gs
= context
->SegGs
;
293 if (ptrace( PTRACE_SETREGS
, pid
, 0, (int) ®s
) == -1) goto error
;
295 if (flags
& CONTEXT_DEBUG_REGISTERS
)
297 /* FIXME: How is this done on Solaris? */
299 if (flags
& CONTEXT_FLOATING_POINT
)
301 /* we can use context->FloatSave directly as it is using the */
302 /* correct structure (the same as fsave/frstor) */
303 if (ptrace( PTRACE_SETFPREGS
, pid
, 0, (int) &context
->FloatSave
) == -1) goto error
;
304 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
311 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
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
, 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
;
413 context
->FloatSave
.Cr0NpxState
= 0; /* FIXME */
420 #else /* linux || __sun__ || __FreeBSD__ */
421 #error You must implement get/set_thread_context for your platform
422 #endif /* linux || __sun__ || __FreeBSD__ */
425 /* copy a context structure according to the flags */
426 static void copy_context( CONTEXT
*to
, CONTEXT
*from
, int flags
)
428 if (flags
& CONTEXT_CONTROL
)
433 to
->SegCs
= from
->SegCs
;
434 to
->SegSs
= from
->SegSs
;
435 to
->EFlags
= from
->EFlags
;
437 if (flags
& CONTEXT_INTEGER
)
446 if (flags
& CONTEXT_SEGMENTS
)
448 to
->SegDs
= from
->SegDs
;
449 to
->SegEs
= from
->SegEs
;
450 to
->SegFs
= from
->SegFs
;
451 to
->SegGs
= from
->SegGs
;
453 if (flags
& CONTEXT_FLOATING_POINT
)
455 to
->FloatSave
= from
->FloatSave
;
457 /* we don't bother copying the debug registers, since they */
458 /* always need to be accessed by ptrace anyway */
461 /* retrieve the current instruction pointer of a thread */
462 void *get_thread_ip( struct thread
*thread
)
466 if (suspend_for_ptrace( thread
))
468 get_thread_context( thread
, CONTEXT_CONTROL
, &context
);
469 resume_thread( thread
);
471 return (void *)context
.Eip
;
474 /* retrieve the current context of a thread */
475 DECL_HANDLER(get_thread_context
)
477 struct thread
*thread
;
478 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
480 if (get_req_data_size(req
) < sizeof(CONTEXT
))
482 set_error( STATUS_INVALID_PARAMETER
);
485 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_GET_CONTEXT
)))
487 if (thread
->context
) /* thread is inside an exception event */
489 copy_context( get_req_data(req
), thread
->context
, flags
);
490 flags
&= CONTEXT_DEBUG_REGISTERS
;
492 if (flags
&& suspend_for_ptrace( thread
))
494 get_thread_context( thread
, flags
, get_req_data(req
) );
495 resume_thread( thread
);
497 release_object( thread
);
502 /* set the current context of a thread */
503 DECL_HANDLER(set_thread_context
)
505 struct thread
*thread
;
506 int flags
= req
->flags
& ~CONTEXT_i386
; /* get rid of CPU id */
508 if (get_req_data_size(req
) < sizeof(CONTEXT
))
510 set_error( STATUS_INVALID_PARAMETER
);
513 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_CONTEXT
)))
515 if (thread
->context
) /* thread is inside an exception event */
517 copy_context( thread
->context
, get_req_data(req
), flags
);
518 flags
&= CONTEXT_DEBUG_REGISTERS
;
520 if (flags
&& suspend_for_ptrace( thread
))
522 set_thread_context( thread
, flags
, get_req_data(req
) );
523 resume_thread( thread
);
525 release_object( thread
);
529 #endif /* __i386__ */