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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
62 #define PTRACE_GETDBREGS PT_GETDBREGS
66 #define PTRACE_SETDBREGS PT_SETDBREGS
70 #ifdef HAVE_SYS_USER_H
71 # include <sys/user.h>
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 )
82 res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
83 if ((res == -1) && errno)
92 /* retrieve the thread x86 debug registers */
93 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
95 int pid = get_ptrace_pid(thread);
97 if (get_debug_reg( pid, 0, &context->Dr0 ) == -1) goto error;
98 if (get_debug_reg( pid, 1, &context->Dr1 ) == -1) goto error;
99 if (get_debug_reg( pid, 2, &context->Dr2 ) == -1) goto error;
100 if (get_debug_reg( pid, 3, &context->Dr3 ) == -1) goto error;
101 if (get_debug_reg( pid, 6, &context->Dr6 ) == -1) goto error;
102 if (get_debug_reg( pid, 7, &context->Dr7 ) == -1) goto error;
109 /* set the thread x86 debug registers */
110 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
112 int pid = get_ptrace_pid(thread);
114 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(0), context->Dr0 ) == -1) goto error;
115 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(1), context->Dr1 ) == -1) goto error;
116 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(2), context->Dr2 ) == -1) goto error;
117 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(3), context->Dr3 ) == -1) goto error;
118 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(6), context->Dr6 ) == -1) goto error;
119 if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->Dr7 ) == -1) goto error;
126 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__)
127 #include <machine/reg.h>
129 /* retrieve the thread x86 debug registers */
130 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
132 #ifdef PTRACE_GETDBREGS
133 int pid = get_ptrace_pid(thread);
136 if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
139 /* needed for FreeBSD, the structure fields have changed under 5.x */
140 context->Dr0 = DBREG_DRX((&dbregs), 0);
141 context->Dr1 = DBREG_DRX((&dbregs), 1);
142 context->Dr2 = DBREG_DRX((&dbregs), 2);
143 context->Dr3 = DBREG_DRX((&dbregs), 3);
144 context->Dr6 = DBREG_DRX((&dbregs), 6);
145 context->Dr7 = DBREG_DRX((&dbregs), 7);
147 context->Dr0 = dbregs.dr0;
148 context->Dr1 = dbregs.dr1;
149 context->Dr2 = dbregs.dr2;
150 context->Dr3 = dbregs.dr3;
151 context->Dr6 = dbregs.dr6;
152 context->Dr7 = dbregs.dr7;
161 /* set the thread x86 debug registers */
162 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
164 #ifdef PTRACE_SETDBREGS
165 int pid = get_ptrace_pid(thread);
168 /* needed for FreeBSD, the structure fields have changed under 5.x */
169 DBREG_DRX((&dbregs), 0) = context->Dr0;
170 DBREG_DRX((&dbregs), 1) = context->Dr1;
171 DBREG_DRX((&dbregs), 2) = context->Dr2;
172 DBREG_DRX((&dbregs), 3) = context->Dr3;
173 DBREG_DRX((&dbregs), 4) = 0;
174 DBREG_DRX((&dbregs), 5) = 0;
175 DBREG_DRX((&dbregs), 6) = context->Dr6;
176 DBREG_DRX((&dbregs), 7) = context->Dr7;
178 dbregs.dr0 = context->Dr0;
179 dbregs.dr1 = context->Dr1;
180 dbregs.dr2 = context->Dr2;
181 dbregs.dr3 = context->Dr3;
184 dbregs.dr6 = context->Dr6;
185 dbregs.dr7 = context->Dr7;
187 if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) != -1) return 1;
193 #else /* linux || __FreeBSD__ */
195 /* retrieve the thread x86 debug registers */
196 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
201 /* set the thread x86 debug registers */
202 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
207 #endif /* linux || __FreeBSD__ */
210 /* copy a context structure according to the flags */
211 static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
213 if (flags & CONTEXT_CONTROL)
218 to->SegCs = from->SegCs;
219 to->SegSs = from->SegSs;
220 to->EFlags = from->EFlags;
222 if (flags & CONTEXT_INTEGER)
231 if (flags & CONTEXT_SEGMENTS)
233 to->SegDs = from->SegDs;
234 to->SegEs = from->SegEs;
235 to->SegFs = from->SegFs;
236 to->SegGs = from->SegGs;
238 if (flags & CONTEXT_FLOATING_POINT)
240 to->FloatSave = from->FloatSave;
242 if (flags & CONTEXT_DEBUG_REGISTERS)
251 to->ContextFlags |= flags;
254 /* retrieve the current instruction pointer of a context */
255 void *get_context_ip( const CONTEXT *context )
257 return (void *)context->Eip;
260 /* retrieve the thread context */
261 void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
263 context->ContextFlags |= CONTEXT_i386;
264 flags &= ~CONTEXT_i386; /* get rid of CPU id */
266 if (thread->context) /* thread is inside an exception event or suspended */
267 copy_context( context, thread->context, flags & ~CONTEXT_DEBUG_REGISTERS );
269 if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread ))
271 if (get_thread_debug_regs( thread, context )) context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
272 resume_after_ptrace( thread );
276 /* set the thread context */
277 void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
279 flags &= ~CONTEXT_i386; /* get rid of CPU id */
281 if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread ))
283 if (!set_thread_debug_regs( thread, context )) flags &= ~CONTEXT_DEBUG_REGISTERS;
284 resume_after_ptrace( thread );
287 if (thread->context) copy_context( thread->context, context, flags );
290 #endif /* __i386__ */