dnsapi: DnsExtractRecordsFromMessage_A is not exported.
[wine] / server / context_i386.c
1 /*
2  * i386 register context support
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #ifdef __i386__
24
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
38
39 #include "windef.h"
40
41 #include "file.h"
42 #include "thread.h"
43 #include "request.h"
44
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
52
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
60
61 #ifdef PT_GETDBREGS
62 #define PTRACE_GETDBREGS PT_GETDBREGS
63 #endif
64
65 #ifdef PT_SETDBREGS
66 #define PTRACE_SETDBREGS PT_SETDBREGS
67 #endif
68
69 #ifdef linux
70 #ifdef HAVE_SYS_USER_H
71 # include <sys/user.h>
72 #endif
73
74 /* debug register offset in struct user */
75 #define DR_OFFSET(dr) ((int)((((struct user *)0)->u_debugreg) + (dr)))
76
77 /* retrieve a debug register */
78 static inline int get_debug_reg( int pid, int num, DWORD *data )
79 {
80     int res;
81     errno = 0;
82     res = ptrace( PTRACE_PEEKUSER, pid, DR_OFFSET(num), 0 );
83     if ((res == -1) && errno)
84     {
85         file_set_error();
86         return -1;
87     }
88     *data = res;
89     return 0;
90 }
91
92 /* retrieve the thread x86 debug registers */
93 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
94 {
95     int pid = get_ptrace_pid(thread);
96
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;
107 }
108
109 /* set the thread x86 debug registers */
110 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
111 {
112     int pid = get_ptrace_pid(thread);
113
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;
124 }
125
126 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__)
127 #include <machine/reg.h>
128
129 /* retrieve the thread x86 debug registers */
130 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
131 {
132 #ifdef PTRACE_GETDBREGS
133     int pid = get_ptrace_pid(thread);
134
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;
159 }
160
161 /* set the thread x86 debug registers */
162 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
163 {
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;
191 }
192
193 #else  /* linux || __FreeBSD__ */
194
195 /* retrieve the thread x86 debug registers */
196 static int get_thread_debug_regs( struct thread *thread, CONTEXT *context )
197 {
198     return 0;
199 }
200
201 /* set the thread x86 debug registers */
202 static int set_thread_debug_regs( struct thread *thread, const CONTEXT *context )
203 {
204     return 0;
205 }
206
207 #endif  /* linux || __FreeBSD__ */
208
209
210 /* copy a context structure according to the flags */
211 static void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags )
212 {
213     if (flags & CONTEXT_CONTROL)
214     {
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;
221     }
222     if (flags & CONTEXT_INTEGER)
223     {
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;
230     }
231     if (flags & CONTEXT_SEGMENTS)
232     {
233         to->SegDs = from->SegDs;
234         to->SegEs = from->SegEs;
235         to->SegFs = from->SegFs;
236         to->SegGs = from->SegGs;
237     }
238     if (flags & CONTEXT_FLOATING_POINT)
239     {
240         to->FloatSave = from->FloatSave;
241     }
242     if (flags & CONTEXT_DEBUG_REGISTERS)
243     {
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;
250     }
251     to->ContextFlags |= flags;
252 }
253
254 /* retrieve the current instruction pointer of a context */
255 void *get_context_ip( const CONTEXT *context )
256 {
257     return (void *)context->Eip;
258 }
259
260 /* retrieve the thread context */
261 void get_thread_context( struct thread *thread, CONTEXT *context, unsigned int flags )
262 {
263     context->ContextFlags |= CONTEXT_i386;
264     flags &= ~CONTEXT_i386;  /* get rid of CPU id */
265
266     if (thread->context)  /* thread is inside an exception event or suspended */
267         copy_context( context, thread->context, flags & ~CONTEXT_DEBUG_REGISTERS );
268
269     if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread ))
270     {
271         if (get_thread_debug_regs( thread, context )) context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
272         resume_after_ptrace( thread );
273     }
274 }
275
276 /* set the thread context */
277 void set_thread_context( struct thread *thread, const CONTEXT *context, unsigned int flags )
278 {
279     flags &= ~CONTEXT_i386;  /* get rid of CPU id */
280
281     if ((flags & CONTEXT_DEBUG_REGISTERS) && suspend_for_ptrace( thread ))
282     {
283         if (!set_thread_debug_regs( thread, context )) flags &= ~CONTEXT_DEBUG_REGISTERS;
284         resume_after_ptrace( thread );
285     }
286
287     if (thread->context) copy_context( thread->context, context, flags );
288 }
289
290 #endif  /* __i386__ */