2 * i386 register context support
4 * Copyright (C) 1999 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #ifdef HAVE_SYS_PTRACE_H
33 # include <sys/ptrace.h>
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
45 #ifndef PTRACE_PEEKUSER
46 # ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
47 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
49 # define PTRACE_PEEKUSER PT_READ_U
53 #ifndef PTRACE_POKEUSER
54 # ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
55 # define PTRACE_POKEUSER PTRACE_POKEUSR
57 # define PTRACE_POKEUSER PT_WRITE_U
61 #ifndef PTRACE_GETREGS
62 #define PTRACE_GETREGS PT_GETREGS
64 #ifndef PTRACE_GETFPREGS
65 #define PTRACE_GETFPREGS PT_GETFPREGS
67 #ifndef PTRACE_SETREGS
68 #define PTRACE_SETREGS PT_SETREGS
70 #ifndef PTRACE_SETFPREGS
71 #define PTRACE_SETFPREGS PT_SETFPREGS
75 #define PTRACE_GETDBREGS PT_GETDBREGS
79 #define PTRACE_SETDBREGS PT_SETDBREGS
83 #ifdef HAVE_SYS_USER_H
84 # include <sys/user.h>
87 /* user_regs definitions from asm/user.h */
88 struct kernel_user_regs_struct
90 long ebx, ecx, edx, esi, edi, ebp, eax;
91 unsigned short ds, __ds, es, __es;
92 unsigned short fs, __fs, gs, __gs;
94 unsigned short cs, __cs;
96 unsigned short ss, __ss;
99 /* debug register offset in struct user */
100 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
102 /* retrieve a debug register */
103 static inline int get_debug_reg( int pid, int num, DWORD *data )
107 res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
108 if ((res == -1) && errno)
117 /* retrieve a thread context */
118 static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
120 int pid = get_ptrace_pid(thread);
121 if (flags & CONTEXT_FULL)
123 struct kernel_user_regs_struct regs;
124 if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
125 if (flags & CONTEXT_INTEGER)
127 context->Eax = regs.eax;
128 context->Ebx = regs.ebx;
129 context->Ecx = regs.ecx;
130 context->Edx = regs.edx;
131 context->Esi = regs.esi;
132 context->Edi = regs.edi;
134 if (flags & CONTEXT_CONTROL)
136 context->Ebp = regs.ebp;
137 context->Esp = regs.esp;
138 context->Eip = regs.eip;
139 context->SegCs = regs.cs;
140 context->SegSs = regs.ss;
141 context->EFlags = regs.eflags;
143 if (flags & CONTEXT_SEGMENTS)
145 context->SegDs = regs.ds;
146 context->SegEs = regs.es;
147 context->SegFs = regs.fs;
148 context->SegGs = regs.gs;
150 context->ContextFlags |= flags & CONTEXT_FULL;
152 if (flags & CONTEXT_DEBUG_REGISTERS)
154 if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
155 if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
156 if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
157 if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
158 if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
159 if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
160 context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
162 if (flags & CONTEXT_FLOATING_POINT)
164 /* we can use context->FloatSave directly as it is using the */
165 /* correct structure (the same as fsave/frstor) */
166 if (ptrace( PTRACE_GETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
167 context->FloatSave.Cr0NpxState = 0; /* FIXME */
168 context->ContextFlags |= CONTEXT_FLOATING_POINT;
176 /* set a thread context */
177 static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
179 int pid = get_ptrace_pid(thread);
180 if (flags & CONTEXT_FULL)
182 struct kernel_user_regs_struct regs;
184 /* need to preserve some registers (at a minimum orig_eax must always be preserved) */
185 if (ptrace( PTRACE_GETREGS, pid, 0, ®s ) == -1) goto error;
187 if (flags & CONTEXT_INTEGER)
189 regs.eax = context->Eax;
190 regs.ebx = context->Ebx;
191 regs.ecx = context->Ecx;
192 regs.edx = context->Edx;
193 regs.esi = context->Esi;
194 regs.edi = context->Edi;
196 if (flags & CONTEXT_CONTROL)
198 regs.ebp = context->Ebp;
199 regs.esp = context->Esp;
200 regs.eip = context->Eip;
201 regs.cs = context->SegCs;
202 regs.ss = context->SegSs;
203 regs.eflags = context->EFlags;
205 if (flags & CONTEXT_SEGMENTS)
207 regs.ds = context->SegDs;
208 regs.es = context->SegEs;
209 regs.fs = context->SegFs;
210 regs.gs = context->SegGs;
212 if (ptrace( PTRACE_SETREGS, pid, 0, ®s ) == -1) goto error;
214 if (flags & CONTEXT_DEBUG_REGISTERS)
216 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
217 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
218 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
219 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
220 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
221 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
223 if (flags & CONTEXT_FLOATING_POINT)
225 /* we can use context->FloatSave directly as it is using the */
226 /* correct structure (the same as fsave/frstor) */
227 if (ptrace( PTRACE_SETFPREGS, pid, 0, &context->FloatSave ) == -1) goto error;
234 #elif defined(__sun) || defined(__sun__)
236 /* retrieve a thread context */
237 static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
239 int pid = get_ptrace_pid(thread);
240 if (flags & CONTEXT_FULL)
243 if (ptrace( PTRACE_GETREGS, pid, (int) ®s, 0 ) == -1) goto error;
244 if (flags & CONTEXT_INTEGER)
246 context->Eax = regs.r_eax;
247 context->Ebx = regs.r_ebx;
248 context->Ecx = regs.r_ecx;
249 context->Edx = regs.r_edx;
250 context->Esi = regs.r_esi;
251 context->Edi = regs.r_edi;
253 if (flags & CONTEXT_CONTROL)
255 context->Ebp = regs.r_ebp;
256 context->Esp = regs.r_esp;
257 context->Eip = regs.r_eip;
258 context->SegCs = regs.r_cs & 0xffff;
259 context->SegSs = regs.r_ss & 0xffff;
260 context->EFlags = regs.r_efl;
262 if (flags & CONTEXT_SEGMENTS)
264 context->SegDs = regs.r_ds & 0xffff;
265 context->SegEs = regs.r_es & 0xffff;
266 context->SegFs = regs.r_fs & 0xffff;
267 context->SegGs = regs.r_gs & 0xffff;
269 context->ContextFlags |= flags & CONTEXT_FULL;
271 if (flags & CONTEXT_DEBUG_REGISTERS)
273 /* FIXME: How is this done on Solaris? */
275 if (flags & CONTEXT_FLOATING_POINT)
277 /* we can use context->FloatSave directly as it is using the */
278 /* correct structure (the same as fsave/frstor) */
279 if (ptrace( PTRACE_GETFPREGS, pid, (int) &context->FloatSave, 0 ) == -1) goto error;
280 context->FloatSave.Cr0NpxState = 0; /* FIXME */
281 context->ContextFlags |= CONTEXT_FLOATING_POINT;
289 /* set a thread context */
290 static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
292 int pid = get_ptrace_pid(thread);
293 if (flags & CONTEXT_FULL)
296 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
298 /* need to preserve some registers */
299 if (ptrace( PTRACE_GETREGS, pid, (int) ®s, 0 ) == -1) goto error;
301 if (flags & CONTEXT_INTEGER)
303 regs.r_eax = context->Eax;
304 regs.r_ebx = context->Ebx;
305 regs.r_ecx = context->Ecx;
306 regs.r_edx = context->Edx;
307 regs.r_esi = context->Esi;
308 regs.r_edi = context->Edi;
310 if (flags & CONTEXT_CONTROL)
312 regs.r_ebp = context->Ebp;
313 regs.r_esp = context->Esp;
314 regs.r_eip = context->Eip;
315 regs.r_cs = context->SegCs;
316 regs.r_ss = context->SegSs;
317 regs.r_efl = context->EFlags;
319 if (flags & CONTEXT_SEGMENTS)
321 regs.r_ds = context->SegDs;
322 regs.r_es = context->SegEs;
323 regs.r_fs = context->SegFs;
324 regs.r_gs = context->SegGs;
326 if (ptrace( PTRACE_SETREGS, pid, (int) ®s, 0 ) == -1) goto error;
328 if (flags & CONTEXT_DEBUG_REGISTERS)
330 /* FIXME: How is this done on Solaris? */
332 if (flags & CONTEXT_FLOATING_POINT)
334 /* we can use context->FloatSave directly as it is using the */
335 /* correct structure (the same as fsave/frstor) */
336 if (ptrace( PTRACE_SETFPREGS, pid, (int) &context->FloatSave, 0 ) == -1) goto error;
343 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__)
344 #include <machine/reg.h>
346 /* retrieve a thread context */
347 static void get_thread_context_ptrace( struct thread *thread, unsigned int flags, CONTEXT *context )
349 int pid = get_ptrace_pid(thread);
350 if (flags & CONTEXT_FULL)
353 if (ptrace( PTRACE_GETREGS, pid, (caddr_t) ®s, 0 ) == -1) goto error;
354 if (flags & CONTEXT_INTEGER)
356 context->Eax = regs.r_eax;
357 context->Ebx = regs.r_ebx;
358 context->Ecx = regs.r_ecx;
359 context->Edx = regs.r_edx;
360 context->Esi = regs.r_esi;
361 context->Edi = regs.r_edi;
363 if (flags & CONTEXT_CONTROL)
365 context->Ebp = regs.r_ebp;
366 context->Esp = regs.r_esp;
367 context->Eip = regs.r_eip;
368 context->SegCs = regs.r_cs & 0xffff;
369 context->SegSs = regs.r_ss & 0xffff;
370 context->EFlags = regs.r_eflags;
372 if (flags & CONTEXT_SEGMENTS)
374 context->SegDs = regs.r_ds & 0xffff;
375 context->SegEs = regs.r_es & 0xffff;
376 context->SegFs = regs.r_fs & 0xffff;
377 context->SegGs = regs.r_gs & 0xffff;
379 context->ContextFlags |= flags & CONTEXT_FULL;
381 if (flags & CONTEXT_DEBUG_REGISTERS)
383 #ifdef PTRACE_GETDBREGS
385 if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
388 /* needed for FreeBSD, the structure fields have changed under 5.x */
389 context->Dr0 = DBREG_DRX((&dbregs), 0);
390 context->Dr1 = DBREG_DRX((&dbregs), 1);
391 context->Dr2 = DBREG_DRX((&dbregs), 2);
392 context->Dr3 = DBREG_DRX((&dbregs), 3);
393 context->Dr6 = DBREG_DRX((&dbregs), 6);
394 context->Dr7 = DBREG_DRX((&dbregs), 7);
396 context->Dr0 = dbregs.dr0;
397 context->Dr1 = dbregs.dr1;
398 context->Dr2 = dbregs.dr2;
399 context->Dr3 = dbregs.dr3;
400 context->Dr6 = dbregs.dr6;
401 context->Dr7 = dbregs.dr7;
403 context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
406 if (flags & CONTEXT_FLOATING_POINT)
408 /* we can use context->FloatSave directly as it is using the */
409 /* correct structure (the same as fsave/frstor) */
410 if (ptrace( PTRACE_GETFPREGS, pid, (caddr_t) &context->FloatSave, 0 ) == -1) goto error;
411 context->FloatSave.Cr0NpxState = 0; /* FIXME */
412 context->ContextFlags |= CONTEXT_FLOATING_POINT;
420 /* set a thread context */
421 static void set_thread_context_ptrace( struct thread *thread, unsigned int flags, const CONTEXT *context )
423 int pid = get_ptrace_pid(thread);
424 if (flags & CONTEXT_FULL)
427 if (((flags | CONTEXT_i386) & CONTEXT_FULL) != CONTEXT_FULL)
429 /* need to preserve some registers */
430 if (ptrace( PTRACE_GETREGS, pid, (caddr_t) ®s, 0 ) == -1) goto error;
432 if (flags & CONTEXT_INTEGER)
434 regs.r_eax = context->Eax;
435 regs.r_ebx = context->Ebx;
436 regs.r_ecx = context->Ecx;
437 regs.r_edx = context->Edx;
438 regs.r_esi = context->Esi;
439 regs.r_edi = context->Edi;
441 if (flags & CONTEXT_CONTROL)
443 regs.r_ebp = context->Ebp;
444 regs.r_esp = context->Esp;
445 regs.r_eip = context->Eip;
446 regs.r_cs = context->SegCs;
447 regs.r_ss = context->SegSs;
448 regs.r_eflags = context->EFlags;
450 if (flags & CONTEXT_SEGMENTS)
452 regs.r_ds = context->SegDs;
453 regs.r_es = context->SegEs;
454 regs.r_fs = context->SegFs;
455 regs.r_gs = context->SegGs;
457 if (ptrace( PTRACE_SETREGS, pid, (caddr_t) ®s, 0 ) == -1) goto error;
459 if (flags & CONTEXT_DEBUG_REGISTERS)
461 #ifdef PTRACE_SETDBREGS
464 /* needed for FreeBSD, the structure fields have changed under 5.x */
465 DBREG_DRX((&dbregs), 0) = context->Dr0;
466 DBREG_DRX((&dbregs), 1) = context->Dr1;
467 DBREG_DRX((&dbregs), 2) = context->Dr2;
468 DBREG_DRX((&dbregs), 3) = context->Dr3;
469 DBREG_DRX((&dbregs), 4) = 0;
470 DBREG_DRX((&dbregs), 5) = 0;
471 DBREG_DRX((&dbregs), 6) = context->Dr6;
472 DBREG_DRX((&dbregs), 7) = context->Dr7;
474 dbregs.dr0 = context->Dr0;
475 dbregs.dr1 = context->Dr1;
476 dbregs.dr2 = context->Dr2;
477 dbregs.dr3 = context->Dr3;
480 dbregs.dr6 = context->Dr6;
481 dbregs.dr7 = context->Dr7;
483 if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
487 if (flags & CONTEXT_FLOATING_POINT)
489 /* we can use context->FloatSave directly as it is using the */
490 /* correct structure (the same as fsave/frstor) */
491 if (ptrace( PTRACE_SETFPREGS, pid, (caddr_t) &context->FloatSave, 0 ) == -1) goto error;
498 #else /* linux || __sun__ || __FreeBSD__ */
499 #error You must implement get/set_thread_context_ptrace for your platform
500 #endif /* linux || __sun__ || __FreeBSD__ */
503 /* copy a context structure according to the flags */
504 static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
506 if (flags & CONTEXT_CONTROL)
511 to->SegCs = from->SegCs;
512 to->SegSs = from->SegSs;
513 to->EFlags = from->EFlags;
515 if (flags & CONTEXT_INTEGER)
524 if (flags & CONTEXT_SEGMENTS)
526 to->SegDs = from->SegDs;
527 to->SegEs = from->SegEs;
528 to->SegFs = from->SegFs;
529 to->SegGs = from->SegGs;
531 if (flags & CONTEXT_FLOATING_POINT)
533 to->FloatSave = from->FloatSave;
535 /* we don't bother copying the debug registers, since they */
536 /* always need to be accessed by ptrace anyway */
537 to->ContextFlags |= flags & ~CONTEXT_DEBUG_REGISTERS;
540 /* retrieve the current instruction pointer of a thread */
541 void *get_thread_ip( struct thread *thread )
545 if (suspend_for_ptrace( thread ))
547 get_thread_context_ptrace( thread, CONTEXT_CONTROL, &context );
548 resume_after_ptrace( thread );
550 return (void *)context.Eip;
553 /* determine if we should continue the thread in single-step mode */
554 int get_thread_single_step( struct thread *thread )
557 if (thread->context) return 0; /* don't single-step inside exception event */
558 get_thread_context_ptrace( thread, CONTEXT_CONTROL, &context );
559 return (context.EFlags & 0x100) != 0;
562 /* send a signal to a specific thread */
563 int tkill( int tgid, int pid, int sig )
568 __asm__( "pushl %%ebx\n\t"
573 : "0" (270) /*SYS_tgkill*/, "r" (tgid), "c" (pid), "d" (sig) );
575 __asm__( "pushl %%ebx\n\t"
580 : "0" (238) /*SYS_tkill*/, "r" (pid), "c" (sig) );
581 if (ret >= 0) return ret;
590 /* retrieve the thread context */
591 void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
593 context->ContextFlags |= CONTEXT_i386;
594 flags &= ~CONTEXT_i386; /* get rid of CPU id */
596 if (thread->context) /* thread is inside an exception event or suspended */
598 copy_context( context, thread->context, flags );
599 flags &= CONTEXT_DEBUG_REGISTERS;
602 if (flags && suspend_for_ptrace( thread ))
604 get_thread_context_ptrace( thread, flags, context );
605 resume_after_ptrace( thread );
609 /* set the thread context */
610 void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
612 flags &= ~CONTEXT_i386; /* get rid of CPU id */
614 if (thread->context) /* thread is inside an exception event or suspended */
615 copy_context( thread->context, context, flags );
617 flags &= CONTEXT_DEBUG_REGISTERS; /* the other registers are handled on the client side */
619 if (flags && suspend_for_ptrace( thread ))
621 set_thread_context_ptrace( thread, flags, context );
622 resume_after_ptrace( thread );
626 #endif /* __i386__ */