Release 950606
[wine/multimedia.git] / loader / signal.c
blob6ac04ad5031b4fa848fca46c12cd9ce5b22c8cc7
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 "prototypes.h"
20 #include "miscemu.h"
21 #include "registers.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 *context)
50 switch(intnum)
52 case 0x10: return do_int10(context);
54 case 0x11:
55 AX = DOS_GetEquipment();
56 return 1;
58 case 0x12:
59 AX = 640;
60 return 1; /* get base mem size */
62 case 0x13: return do_int13(context);
63 case 0x15: return do_int15(context);
64 case 0x16: return do_int16(context);
65 case 0x1a: return do_int1a(context);
66 case 0x21: return do_int21(context);
68 case 0x22:
69 AX = 0x1234;
70 BX = 0x5678;
71 CX = 0x9abc;
72 DX = 0xdef0;
73 return 1;
75 case 0x25: return do_int25(context);
76 case 0x26: return do_int26(context);
77 case 0x2a: return do_int2a(context);
78 case 0x2f: return do_int2f(context);
79 case 0x31: return do_int31(context);
80 case 0x5c: return do_int5c(context);
82 default:
83 fprintf(stderr,"int%02x: Unimplemented!\n", intnum);
84 break;
86 return 0;
89 #ifdef linux
90 static void win_fault(int signal, struct sigcontext_struct context_struct)
92 struct sigcontext_struct *context = &context_struct;
93 #else
94 static void win_fault(int signal, int code, struct sigcontext *context)
96 #endif
97 unsigned char * instr;
98 WORD *stack;
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 && signal != SIGFPE
108 #ifdef SIGBUS
109 && signal != SIGBUS
110 #endif
111 && signal != SIGTRAP)
113 exit(1);
116 /* And back up over the int3 instruction. */
117 if(signal == SIGTRAP) {
118 EIP--;
119 goto oops;
121 #endif
122 #ifdef __NetBSD__
123 /* set_es(0x1f); set_ds(0x1f); */
124 if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP)
125 exit(1);
126 #endif
127 #ifdef __FreeBSD__
128 /* set_es(0x27); set_ds(0x27); */
129 if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP)
130 exit(1);
131 #endif
132 if (CS == WINE_CODE_SELECTOR)
134 fprintf(stderr,
135 "Segmentation fault in Wine program (%x:%lx)."
136 " Please debug\n", CS, EIP );
137 goto oops;
140 /* Now take a look at the actual instruction where the program
141 bombed */
142 instr = (unsigned char *) PTR_SEG_OFF_TO_LIN( CS, EIP );
144 switch(*instr)
146 case 0xcd: /* int <XX> */
147 instr++;
148 if (!do_int(*instr, context)) {
149 fprintf(stderr,"Unexpected Windows interrupt %x\n", *instr);
150 goto oops;
152 EIP += 2; /* Bypass the int instruction */
153 break;
155 case 0xcf: /* iret */
156 stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS, SP );
157 EIP = *stack++;
158 CS = *stack++;
159 EFL = *stack;
160 SP += 6; /* Pop the return address and flags */
161 break;
163 case 0xe4: /* inb al,XX */
164 inportb_abs(context);
165 EIP += 2;
166 break;
168 case 0xe5: /* in ax,XX */
169 inport_abs(context);
170 EIP += 2;
171 break;
173 case 0xe6: /* outb XX,al */
174 outportb_abs(context);
175 EIP += 2;
176 break;
178 case 0xe7: /* out XX,ax */
179 outport_abs(context);
180 EIP += 2;
181 break;
183 case 0xec: /* inb al,dx */
184 inportb(context);
185 EIP++;
186 break;
188 case 0xed: /* in ax,dx */
189 inport(context);
190 EIP++;
191 break;
193 case 0xee: /* outb dx,al */
194 outportb(context);
195 EIP++;
196 break;
198 case 0xef: /* out dx,ax */
199 outport(context);
200 EIP++;
201 break;
203 case 0xfa: /* cli, ignored */
204 EIP++;
205 break;
207 case 0xfb: /* sti, ignored */
208 EIP++;
209 break;
211 default:
212 fprintf(stderr, "Unexpected Windows program segfault"
213 " - opcode = %x\n", *instr);
214 goto oops;
217 /* OK, done handling the interrupt */
219 return;
221 oops:
222 XUngrabPointer(display, CurrentTime);
223 XUngrabServer(display);
224 XFlush(display);
225 fprintf(stderr,"In win_fault %x:%lx\n", CS, EIP );
226 #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__)
227 wine_debug(signal, (int *)context); /* Enter our debugger */
228 #else
229 fprintf(stderr,"Stack: %x:%x\n", SS, ESP );
230 dump = (int*) context;
231 for(i=0; i<22; i++)
233 fprintf(stderr," %8.8x", *dump++);
234 if ((i % 8) == 7)
235 fprintf(stderr,"\n");
237 fprintf(stderr,"\n");
238 exit(1);
239 #endif
242 void init_wine_signals(void)
244 #ifdef linux
245 segv_act.sa_handler = (__sighandler_t) win_fault;
246 /* Point to the top of the stack, minus 4 just in case, and make
247 it aligned */
248 segv_act.sa_restorer =
249 (void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
250 wine_sigaction(SIGSEGV, &segv_act, NULL);
251 wine_sigaction(SIGILL, &segv_act, NULL);
252 wine_sigaction(SIGFPE, &segv_act, NULL);
253 #ifdef SIGBUS
254 wine_sigaction(SIGBUS, &segv_act, NULL);
255 #endif
256 wine_sigaction(SIGTRAP, &segv_act, NULL); /* For breakpoints */
257 #endif
258 #if defined(__NetBSD__) || defined(__FreeBSD__)
259 sigset_t sig_mask;
260 struct sigaltstack ss;
262 #if !defined (__FreeBSD__)
263 if ((ss.ss_base = malloc(MINSIGSTKSZ)) == NULL) {
264 #else
265 if ((ss.ss_sp = malloc(MINSIGSTKSZ)) == NULL) {
266 #endif
267 fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n",
268 MINSIGSTKSZ);
269 exit(1);
271 ss.ss_size = MINSIGSTKSZ;
272 ss.ss_flags = 0;
273 if (sigaltstack(&ss, NULL) < 0) {
274 perror("sigstack");
275 exit(1);
277 sigemptyset(&sig_mask);
278 segv_act.sa_handler = (void (*)) win_fault;
279 segv_act.sa_flags = SA_ONSTACK;
280 segv_act.sa_mask = sig_mask;
281 if (sigaction(SIGBUS, &segv_act, NULL) < 0) {
282 perror("sigaction: SIGBUS");
283 exit(1);
285 segv_act.sa_handler = (void (*)) win_fault;
286 segv_act.sa_flags = SA_ONSTACK;
287 segv_act.sa_mask = sig_mask;
288 if (sigaction(SIGSEGV, &segv_act, NULL) < 0) {
289 perror("sigaction: SIGSEGV");
290 exit(1);
292 segv_act.sa_handler = (void (*)) win_fault; /* For breakpoints */
293 segv_act.sa_flags = SA_ONSTACK;
294 segv_act.sa_mask = sig_mask;
295 if (sigaction(SIGTRAP, &segv_act, NULL) < 0) {
296 perror("sigaction: SIGTRAP");
297 exit(1);
299 #endif
302 #endif /* ifndef WINELIB */