Release 950122
[wine/multimedia.git] / loader / signal.c
blob285571bea9b2811b8202d6bfd3f4c50fbecb44fc
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
17 #include "wine.h"
18 #include "dos_fs.h"
19 #include "segmem.h"
20 #include "prototypes.h"
21 #include "miscemu.h"
22 #include "win.h"
24 #if !defined(BSD4_4) || defined(linux) || defined(__FreeBSD__)
25 char * cstack[4096];
26 #endif
27 struct sigaction segv_act;
29 #ifdef linux
30 extern void ___sig_restore();
31 extern void ___masksig_restore();
33 /* Similar to the sigaction function in libc, except it leaves alone the
34 restorer field */
36 static int
37 wine_sigaction(int sig,struct sigaction * new, struct sigaction * old)
39 __asm__("int $0x80":"=a" (sig)
40 :"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old));
41 if (sig>=0)
42 return 0;
43 errno = -sig;
44 return -1;
46 #endif
48 int do_int(int intnum, struct sigcontext_struct *scp)
50 switch(intnum)
52 case 0x10: return do_int10(scp);
54 case 0x11:
55 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | DOS_GetEquipment();
56 return 1;
58 case 0x12:
59 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | 640L;
60 return 1; /* get base mem size */
62 case 0x13: return do_int13(scp);
63 case 0x15: return do_int15(scp);
64 case 0x16: return do_int16(scp);
65 case 0x1a: return do_int1a(scp);
66 case 0x21: return do_int21(scp);
68 case 0x22:
69 scp->sc_eax = 0x1234;
70 scp->sc_ebx = 0x5678;
71 scp->sc_ecx = 0x9abc;
72 scp->sc_edx = 0xdef0;
73 return 1;
75 case 0x25: return do_int25(scp);
76 case 0x26: return do_int26(scp);
77 case 0x2a: return do_int2a(scp);
78 case 0x2f: return do_int2f(scp);
79 case 0x31: return do_int31(scp);
81 return 0;
84 #ifdef linux
85 static void win_fault(int signal, struct sigcontext_struct context)
87 struct sigcontext_struct *scp = &context;
88 #else
89 static void win_fault(int signal, int code, struct sigcontext *scp)
91 #endif
92 unsigned char * instr;
93 #if !(defined (linux) || defined (__NetBSD__))
94 int i, *dump;
95 #endif
97 /* First take care of a few preliminaries */
98 #ifdef linux
99 if(signal != SIGSEGV
100 && signal != SIGILL
101 #ifdef SIGBUS
102 && signal != SIGBUS
103 #endif
104 && signal != SIGTRAP)
106 exit(1);
109 /* And back up over the int3 instruction. */
110 if(signal == SIGTRAP) {
111 scp->sc_eip--;
112 goto oops;
115 if((scp->sc_cs & 7) != 7)
117 #endif
118 #if defined(__NetBSD__) || defined(__FreeBSD__)
119 /* set_es(0x27); set_ds(0x27); */
120 if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP)
121 exit(1);
122 if(scp->sc_cs == 0x1f)
124 #endif
125 fprintf(stderr,
126 "Segmentation fault in Wine program (%x:%lx)."
127 " Please debug\n",
128 scp->sc_cs, scp->sc_eip);
129 goto oops;
132 /* Now take a look at the actual instruction where the program
133 bombed */
134 instr = (unsigned char *) SAFEMAKEPTR(scp->sc_cs, scp->sc_eip);
136 switch(*instr)
138 case 0xcd: /* int <XX> */
139 instr++;
140 if (!do_int(*instr, scp)) {
141 fprintf(stderr,"Unexpected Windows interrupt %x\n", *instr);
142 goto oops;
144 scp->sc_eip += 2; /* Bypass the int instruction */
145 break;
147 case 0xe4: /* inb al,XX */
148 inportb_abs(scp);
149 scp->sc_eip += 2;
150 break;
152 case 0xe5: /* in ax,XX */
153 inport_abs(scp);
154 scp->sc_eip += 2;
155 break;
157 case 0xe6: /* outb XX,al */
158 outportb_abs(scp);
159 scp->sc_eip += 2;
160 break;
162 case 0xe7: /* out XX,ax */
163 outport_abs(scp);
164 scp->sc_eip += 2;
165 break;
167 case 0xec: /* inb al,dx */
168 inportb(scp);
169 scp->sc_eip++;
170 break;
172 case 0xed: /* in ax,dx */
173 inport(scp);
174 scp->sc_eip++;
175 break;
177 case 0xee: /* outb dx,al */
178 outportb(scp);
179 scp->sc_eip++;
180 break;
182 case 0xef: /* out dx,ax */
183 outport(scp);
184 scp->sc_eip++;
185 break;
187 case 0xfa: /* cli, ignored */
188 scp->sc_eip++;
189 break;
191 case 0xfb: /* sti, ignored */
192 scp->sc_eip++;
193 break;
195 default:
196 fprintf(stderr, "Unexpected Windows program segfault"
197 " - opcode = %x\n", *instr);
198 goto oops;
201 /* OK, done handling the interrupt */
203 return;
205 oops:
206 XUngrabPointer(display, CurrentTime);
207 XUngrabServer(display);
208 XFlush(display);
209 fprintf(stderr,"In win_fault %x:%lx\n", scp->sc_cs, scp->sc_eip);
210 #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__)
211 wine_debug(signal, (int *)scp); /* Enter our debugger */
212 #else
213 fprintf(stderr,"Stack: %x:%x\n", scp->sc_ss, scp->sc_esp);
214 dump = (int*) scp;
215 for(i=0; i<22; i++)
217 fprintf(stderr," %8.8x", *dump++);
218 if ((i % 8) == 7)
219 fprintf(stderr,"\n");
221 fprintf(stderr,"\n");
222 exit(1);
223 #endif
226 void init_wine_signals(void)
228 #ifdef linux
229 segv_act.sa_handler = (__sighandler_t) win_fault;
230 /* Point to the top of the stack, minus 4 just in case, and make
231 it aligned */
232 segv_act.sa_restorer =
233 (void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
234 wine_sigaction(SIGSEGV, &segv_act, NULL);
235 wine_sigaction(SIGILL, &segv_act, NULL);
236 #ifdef SIGBUS
237 wine_sigaction(SIGBUS, &segv_act, NULL);
238 #endif
239 wine_sigaction(SIGTRAP, &segv_act, NULL); /* For breakpoints */
240 #endif
241 #if defined(__NetBSD__) || defined(__FreeBSD__)
242 sigset_t sig_mask;
243 #if defined(BSD4_4) && !defined (__FreeBSD__)
244 struct sigaltstack ss;
246 if ((ss.ss_base = malloc(MINSIGSTKSZ)) == NULL) {
247 fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n",
248 MINSIGSTKSZ);
249 exit(1);
251 ss.ss_size = MINSIGSTKSZ;
252 ss.ss_flags = 0;
253 if (sigaltstack(&ss, NULL) < 0) {
254 perror("sigstack");
255 exit(1);
257 #else
258 struct sigstack ss;
260 ss.ss_sp = (char *) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
261 ss.ss_onstack = 0;
262 if (sigstack(&ss, NULL) < 0) {
263 perror("sigstack");
264 exit(1);
266 #endif
267 sigemptyset(&sig_mask);
268 segv_act.sa_handler = (void (*)) win_fault;
269 segv_act.sa_flags = SA_ONSTACK;
270 segv_act.sa_mask = sig_mask;
271 if (sigaction(SIGBUS, &segv_act, NULL) < 0) {
272 perror("sigaction: SIGBUS");
273 exit(1);
275 segv_act.sa_handler = (void (*)) win_fault;
276 segv_act.sa_flags = SA_ONSTACK;
277 segv_act.sa_mask = sig_mask;
278 if (sigaction(SIGSEGV, &segv_act, NULL) < 0) {
279 perror("sigaction: SIGSEGV");
280 exit(1);
282 segv_act.sa_handler = (void (*)) win_fault; /* For breakpoints */
283 segv_act.sa_flags = SA_ONSTACK;
284 segv_act.sa_mask = sig_mask;
285 if (sigaction(SIGTRAP, &segv_act, NULL) < 0) {
286 perror("sigaction: SIGTRAP");
287 exit(1);
289 #endif
292 static sigjmp_buf segv_jmpbuf;
294 static void
295 segv_handler()
297 siglongjmp(segv_jmpbuf, 1);
301 test_memory( char *p, int write )
303 int ret = FALSE;
304 struct sigaction new_act;
305 struct sigaction old_act;
307 memset(&new_act, 0, sizeof new_act);
308 new_act.sa_handler = segv_handler;
309 if (sigsetjmp( segv_jmpbuf, 1 ) == 0) {
310 char c = 100;
311 if (sigaction(SIGSEGV, &new_act, &old_act) < 0)
312 perror("sigaction");
313 c = *p;
314 if (write)
315 *p = c;
316 ret = TRUE;
318 #ifdef linux
319 wine_sigaction(SIGSEGV, &old_act, NULL);
320 #else
321 sigaction(SIGSEGV, &old_act, NULL);
322 #endif
323 return ret;
326 #endif /* ifndef WINELIB */