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