Release 950109
[wine/multimedia.git] / loader / signal.c
blob51fa4306cb1402aa8d2a8223f53629bf35c14779
1 #ifndef WINELIB
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <signal.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <time.h>
8 #include <setjmp.h>
10 #if defined(__NetBSD__) || defined(__FreeBSD__)
11 #include <sys/syscall.h>
12 #include <sys/param.h>
13 #else
14 #include <syscall.h>
15 #endif
16 #ifdef linux
17 #define inline __inline__ /* So we can compile with -ansi */
18 #include <linux/sched.h>
19 #include <asm/system.h>
20 #undef inline
21 #endif
23 #include "wine.h"
24 #include "dos_fs.h"
25 #include "segmem.h"
26 #include "prototypes.h"
27 #include "miscemu.h"
28 #include "win.h"
30 #if !defined(BSD4_4) || defined(linux) || defined(__FreeBSD__)
31 char * cstack[4096];
32 #endif
33 struct sigaction segv_act;
35 #ifdef linux
36 extern void ___sig_restore();
37 extern void ___masksig_restore();
39 /* Similar to the sigaction function in libc, except it leaves alone the
40 restorer field */
42 static int
43 wine_sigaction(int sig,struct sigaction * new, struct sigaction * old)
45 __asm__("int $0x80":"=a" (sig)
46 :"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old));
47 if (sig>=0)
48 return 0;
49 errno = -sig;
50 return -1;
52 #endif
54 int do_int(int intnum, struct sigcontext_struct *scp)
56 switch(intnum)
58 case 0x10: return do_int10(scp);
60 case 0x11:
61 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | DOS_GetEquipment();
62 return 1;
64 case 0x12:
65 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | 640L;
66 return 1; /* get base mem size */
68 case 0x13: return do_int13(scp);
69 case 0x15: return do_int15(scp);
70 case 0x16: return do_int16(scp);
71 case 0x1a: return do_int1a(scp);
72 case 0x21: return do_int21(scp);
74 case 0x22:
75 scp->sc_eax = 0x1234;
76 scp->sc_ebx = 0x5678;
77 scp->sc_ecx = 0x9abc;
78 scp->sc_edx = 0xdef0;
79 return 1;
81 case 0x25: return do_int25(scp);
82 case 0x26: return do_int26(scp);
83 case 0x2a: return do_int2a(scp);
84 case 0x2f: return do_int2f(scp);
85 case 0x31: return do_int31(scp);
87 return 0;
90 #ifdef linux
91 static void win_fault(int signal, struct sigcontext_struct context)
93 struct sigcontext_struct *scp = &context;
94 #else
95 static void win_fault(int signal, int code, struct sigcontext *scp)
97 #endif
98 unsigned char * instr;
99 #if !(defined (linux) || defined (__NetBSD__))
100 int i, *dump;
101 #endif
103 /* First take care of a few preliminaries */
104 #ifdef linux
105 if(signal != SIGSEGV
106 && signal != SIGILL
107 #ifdef SIGBUS
108 && signal != SIGBUS
109 #endif
110 && signal != SIGTRAP)
112 exit(1);
115 /* And back up over the int3 instruction. */
116 if(signal == SIGTRAP) {
117 scp->sc_eip--;
118 goto oops;
121 if((scp->sc_cs & 7) != 7)
123 #endif
124 #if defined(__NetBSD__) || defined(__FreeBSD__)
125 /* set_es(0x27); set_ds(0x27); */
126 if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP)
127 exit(1);
128 if(scp->sc_cs == 0x1f)
130 #endif
131 fprintf(stderr,
132 "Segmentation fault in Wine program (%x:%lx)."
133 " Please debug\n",
134 scp->sc_cs, scp->sc_eip);
135 goto oops;
138 /* Now take a look at the actual instruction where the program
139 bombed */
140 instr = (unsigned char *) SAFEMAKEPTR(scp->sc_cs, scp->sc_eip);
142 switch(*instr)
144 case 0xcd: /* int <XX> */
145 instr++;
146 if (!do_int(*instr, scp)) {
147 fprintf(stderr,"Unexpected Windows interrupt %x\n", *instr);
148 goto oops;
150 scp->sc_eip += 2; /* Bypass the int instruction */
151 break;
153 case 0xe4: /* inb al,XX */
154 inportb_abs(scp);
155 scp->sc_eip += 2;
156 break;
158 case 0xe5: /* in ax,XX */
159 inport_abs(scp);
160 scp->sc_eip += 2;
161 break;
163 case 0xe6: /* outb XX,al */
164 outportb_abs(scp);
165 scp->sc_eip += 2;
166 break;
168 case 0xe7: /* out XX,ax */
169 outport_abs(scp);
170 scp->sc_eip += 2;
171 break;
173 case 0xec: /* inb al,dx */
174 inportb(scp);
175 scp->sc_eip++;
176 break;
178 case 0xed: /* in ax,dx */
179 inport(scp);
180 scp->sc_eip++;
181 break;
183 case 0xee: /* outb dx,al */
184 outportb(scp);
185 scp->sc_eip++;
186 break;
188 case 0xef: /* out dx,ax */
189 outport(scp);
190 scp->sc_eip++;
191 break;
193 case 0xfa: /* cli, ignored */
194 scp->sc_eip++;
195 break;
197 case 0xfb: /* sti, ignored */
198 scp->sc_eip++;
199 break;
201 default:
202 fprintf(stderr, "Unexpected Windows program segfault"
203 " - opcode = %x\n", *instr);
204 goto oops;
207 /* OK, done handling the interrupt */
209 return;
211 oops:
212 XUngrabPointer(display, CurrentTime);
213 XUngrabServer(display);
214 XFlush(display);
215 fprintf(stderr,"In win_fault %x:%lx\n", scp->sc_cs, scp->sc_eip);
216 #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__)
217 wine_debug(signal, (int *)scp); /* Enter our debugger */
218 #else
219 fprintf(stderr,"Stack: %x:%x\n", scp->sc_ss, scp->sc_esp);
220 dump = (int*) scp;
221 for(i=0; i<22; i++)
223 fprintf(stderr," %8.8x", *dump++);
224 if ((i % 8) == 7)
225 fprintf(stderr,"\n");
227 fprintf(stderr,"\n");
228 exit(1);
229 #endif
232 void init_wine_signals(void)
234 #ifdef linux
235 segv_act.sa_handler = (__sighandler_t) win_fault;
236 /* Point to the top of the stack, minus 4 just in case, and make
237 it aligned */
238 segv_act.sa_restorer =
239 (void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
240 wine_sigaction(SIGSEGV, &segv_act, NULL);
241 wine_sigaction(SIGILL, &segv_act, NULL);
242 #ifdef SIGBUS
243 wine_sigaction(SIGBUS, &segv_act, NULL);
244 #endif
245 wine_sigaction(SIGTRAP, &segv_act, NULL); /* For breakpoints */
246 #endif
247 #if defined(__NetBSD__) || defined(__FreeBSD__)
248 sigset_t sig_mask;
249 #if defined(BSD4_4) && !defined (__FreeBSD__)
250 struct sigaltstack ss;
252 if ((ss.ss_base = malloc(MINSIGSTKSZ)) == NULL) {
253 fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n",
254 MINSIGSTKSZ);
255 exit(1);
257 ss.ss_size = MINSIGSTKSZ;
258 ss.ss_flags = 0;
259 if (sigaltstack(&ss, NULL) < 0) {
260 perror("sigstack");
261 exit(1);
263 #else
264 struct sigstack ss;
266 ss.ss_sp = (char *) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
267 ss.ss_onstack = 0;
268 if (sigstack(&ss, NULL) < 0) {
269 perror("sigstack");
270 exit(1);
272 #endif
273 sigemptyset(&sig_mask);
274 segv_act.sa_handler = (void (*)) win_fault;
275 segv_act.sa_flags = SA_ONSTACK;
276 segv_act.sa_mask = sig_mask;
277 if (sigaction(SIGBUS, &segv_act, NULL) < 0) {
278 perror("sigaction: SIGBUS");
279 exit(1);
281 segv_act.sa_handler = (void (*)) win_fault;
282 segv_act.sa_flags = SA_ONSTACK;
283 segv_act.sa_mask = sig_mask;
284 if (sigaction(SIGSEGV, &segv_act, NULL) < 0) {
285 perror("sigaction: SIGSEGV");
286 exit(1);
288 segv_act.sa_handler = (void (*)) win_fault; /* For breakpoints */
289 segv_act.sa_flags = SA_ONSTACK;
290 segv_act.sa_mask = sig_mask;
291 if (sigaction(SIGTRAP, &segv_act, NULL) < 0) {
292 perror("sigaction: SIGTRAP");
293 exit(1);
295 #endif
298 static sigjmp_buf segv_jmpbuf;
300 static void
301 segv_handler()
303 siglongjmp(segv_jmpbuf, 1);
307 test_memory( char *p, int write )
309 int ret = FALSE;
310 struct sigaction new_act;
311 struct sigaction old_act;
313 memset(&new_act, 0, sizeof new_act);
314 new_act.sa_handler = segv_handler;
315 if (sigsetjmp( segv_jmpbuf, 1 ) == 0) {
316 char c = 100;
317 if (sigaction(SIGSEGV, &new_act, &old_act) < 0)
318 perror("sigaction");
319 c = *p;
320 if (write)
321 *p = c;
322 ret = TRUE;
324 #ifdef linux
325 wine_sigaction(SIGSEGV, &old_act, NULL);
326 #else
327 sigaction(SIGSEGV, &old_act, NULL);
328 #endif
329 return ret;
332 #endif /* ifndef WINELIB */