msxml: Allow the element implementation to be aggregatable.
[wine/hacks.git] / server / context_i386.c
blob35c30ae8d49bd277b025ecdb4a4d6ad6cfee730d
1 /*
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
21 #include "config.h"
23 #ifdef __i386__
25 #include <assert.h>
26 #include <errno.h>
27 #ifdef HAVE_SYS_REG_H
28 #include <sys/reg.h>
29 #endif
30 #include <stdarg.h>
31 #include <unistd.h>
32 #ifdef HAVE_SYS_PTRACE_H
33 # include <sys/ptrace.h>
34 #endif
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
39 #include "windef.h"
41 #include "file.h"
42 #include "thread.h"
43 #include "request.h"
45 #ifndef PTRACE_PEEKUSER
46 # ifdef PTRACE_PEEKUSR /* libc5 uses USR not USER */
47 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
48 # else
49 # define PTRACE_PEEKUSER PT_READ_U
50 # endif
51 #endif
53 #ifndef PTRACE_POKEUSER
54 # ifdef PTRACE_POKEUSR /* libc5 uses USR not USER */
55 # define PTRACE_POKEUSER PTRACE_POKEUSR
56 # else
57 # define PTRACE_POKEUSER PT_WRITE_U
58 # endif
59 #endif
61 #ifdef PT_GETDBREGS
62 #define PTRACE_GETDBREGS PT_GETDBREGS
63 #endif
65 #ifdef PT_SETDBREGS
66 #define PTRACE_SETDBREGS PT_SETDBREGS
67 #endif
69 #ifdef linux
70 #ifdef HAVE_SYS_USER_H
71 # include <sys/user.h>
72 #endif
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;
81 errno = 0;
82 res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
83 if ((res == -1) && errno)
85 file_set_error();
86 return -1;
88 *data = res;
89 return 0;
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;
103 return 1;
104 error:
105 file_set_error();
106 return 0;
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;
120 return 1;
121 error:
122 file_set_error();
123 return 0;
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);
135 struct dbreg dbregs;
136 if (ptrace( PTRACE_GETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1)
137 goto error;
138 #ifdef DBREG_DRX
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);
146 #else
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;
153 #endif
154 return 1;
155 error:
156 file_set_error();
157 #endif
158 return 0;
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);
166 struct dbreg dbregs;
167 #ifdef DBREG_DRX
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;
177 #else
178 dbregs.dr0 = context->Dr0;
179 dbregs.dr1 = context->Dr1;
180 dbregs.dr2 = context->Dr2;
181 dbregs.dr3 = context->Dr3;
182 dbregs.dr4 = 0;
183 dbregs.dr5 = 0;
184 dbregs.dr6 = context->Dr6;
185 dbregs.dr7 = context->Dr7;
186 #endif
187 if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) != -1) return 1;
188 file_set_error();
189 #endif
190 return 0;
193 #else /* linux || __FreeBSD__ */
195 /* retrieve the thread x86 debug registers */
196 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
198 return 0;
201 /* set the thread x86 debug registers */
202 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
204 return 0;
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)
215 to->Ebp = from->Ebp;
216 to->Eip = from->Eip;
217 to->Esp = from->Esp;
218 to->SegCs = from->SegCs;
219 to->SegSs = from->SegSs;
220 to->EFlags = from->EFlags;
222 if (flags & CONTEXT_INTEGER)
224 to->Eax = from->Eax;
225 to->Ebx = from->Ebx;
226 to->Ecx = from->Ecx;
227 to->Edx = from->Edx;
228 to->Esi = from->Esi;
229 to->Edi = from->Edi;
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)
244 to->Dr0 = from->Dr0;
245 to->Dr1 = from->Dr1;
246 to->Dr2 = from->Dr2;
247 to->Dr3 = from->Dr3;
248 to->Dr6 = from->Dr6;
249 to->Dr7 = from->Dr7;
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__ */