Release 950522
[wine] / loader / signal.c
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>
9
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
17 #include "wine.h"
18 #include "dos_fs.h"
19 #include "prototypes.h"
20 #include "miscemu.h"
21 #include "win.h"
22
23 #if !defined(BSD4_4) || defined(linux) || defined(__FreeBSD__)
24 char * cstack[4096];
25 #endif
26 struct sigaction segv_act;
27
28 #ifdef linux
29 extern void ___sig_restore();
30 extern void ___masksig_restore();
31
32 /* Similar to the sigaction function in libc, except it leaves alone the
33    restorer field */
34
35 static int
36 wine_sigaction(int sig,struct sigaction * new, struct sigaction * old)
37 {
38         __asm__("int $0x80":"=a" (sig)
39                 :"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old));
40         if (sig>=0)
41                 return 0;
42         errno = -sig;
43         return -1;
44 }
45 #endif
46
47 int do_int(int intnum, struct sigcontext_struct *scp)
48 {
49         switch(intnum)
50         {
51               case 0x10: return do_int10(scp);
52
53               case 0x11:  
54                 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | DOS_GetEquipment();
55                 return 1;
56
57               case 0x12:               
58                 scp->sc_eax = (scp->sc_eax & 0xffff0000L) | 640L; 
59                 return 1;       /* get base mem size */                
60
61               case 0x13: return do_int13(scp);
62               case 0x15: return do_int15(scp);
63               case 0x16: return do_int16(scp);
64               case 0x1a: return do_int1a(scp);
65               case 0x21: return do_int21(scp);
66
67               case 0x22:
68                 scp->sc_eax = 0x1234;
69                 scp->sc_ebx = 0x5678;
70                 scp->sc_ecx = 0x9abc;
71                 scp->sc_edx = 0xdef0;
72                 return 1;
73
74               case 0x25: return do_int25(scp);
75               case 0x26: return do_int26(scp);
76               case 0x2a: return do_int2a(scp);
77               case 0x2f: return do_int2f(scp);
78               case 0x31: return do_int31(scp);
79
80               default:
81                 printf("int%02x: Unimplemented!\n", intnum);
82                 break;
83         }
84         return 0;
85 }
86
87 #ifdef linux
88 static void win_fault(int signal, struct sigcontext_struct context)
89 {
90     struct sigcontext_struct *scp = &context;
91 #else
92 static void win_fault(int signal, int code, struct sigcontext *scp)
93 {
94 #endif
95     unsigned char * instr;
96 #if !(defined (linux) || defined (__NetBSD__))
97         int i, *dump;
98 #endif
99
100         /* First take care of a few preliminaries */
101 #ifdef linux
102     if(signal != SIGSEGV 
103        && signal != SIGILL 
104        && signal != SIGFPE 
105 #ifdef SIGBUS
106        && signal != SIGBUS 
107 #endif
108        && signal != SIGTRAP) 
109     {
110         exit(1);
111     }
112
113     /* And back up over the int3 instruction. */
114     if(signal == SIGTRAP) {
115       scp->sc_eip--;
116       goto oops;
117     }
118 #endif
119 #ifdef __NetBSD__
120 /*         set_es(0x1f); set_ds(0x1f); */
121     if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP) 
122         exit(1);
123 #endif
124 #ifdef __FreeBSD__
125 /*         set_es(0x27); set_ds(0x27); */
126     if(signal != SIGBUS && signal != SIGSEGV && signal != SIGTRAP) 
127         exit(1);
128 #endif
129     if (scp->sc_cs == WINE_CODE_SELECTOR)
130     {
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;
136     }
137
138     /*  Now take a look at the actual instruction where the program
139         bombed */
140     instr = (unsigned char *) PTR_SEG_OFF_TO_LIN(scp->sc_cs, scp->sc_eip);
141
142     switch(*instr)
143     {
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;
149             }
150             scp->sc_eip += 2;  /* Bypass the int instruction */
151             break;
152             
153       case 0xe4: /* inb al,XX */
154             inportb_abs(scp);
155             scp->sc_eip += 2;
156             break;
157
158       case 0xe5: /* in ax,XX */
159             inport_abs(scp);
160             scp->sc_eip += 2;
161             break;
162
163       case 0xe6: /* outb XX,al */
164             outportb_abs(scp);
165             scp->sc_eip += 2;
166             break;
167
168       case 0xe7: /* out XX,ax */
169             outport_abs(scp);
170             scp->sc_eip += 2;
171             break;
172
173       case 0xec: /* inb al,dx */
174             inportb(scp);
175             scp->sc_eip++;
176             break;
177
178       case 0xed: /* in ax,dx */
179             inport(scp);
180             scp->sc_eip++;  
181             break;
182
183       case 0xee: /* outb dx,al */
184             outportb(scp);
185             scp->sc_eip++;
186             break;
187       
188       case 0xef: /* out dx,ax */
189             outport(scp);
190             scp->sc_eip++;
191             break;
192
193       case 0xfa: /* cli, ignored */
194             scp->sc_eip++;
195             break;
196
197       case 0xfb: /* sti, ignored */
198             scp->sc_eip++;
199             break;
200
201       default:
202                 fprintf(stderr, "Unexpected Windows program segfault"
203                         " - opcode = %x\n", *instr);
204                 goto oops;
205     }
206     
207     /* OK, done handling the interrupt */
208
209     return;
210
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++) 
222     {
223         fprintf(stderr," %8.8x", *dump++);
224         if ((i % 8) == 7)
225             fprintf(stderr,"\n");
226     }
227     fprintf(stderr,"\n");
228     exit(1);
229 #endif
230 }
231
232 void init_wine_signals(void)
233 {
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         wine_sigaction(SIGFPE, &segv_act, NULL);
243 #ifdef SIGBUS
244         wine_sigaction(SIGBUS, &segv_act, NULL);
245 #endif
246         wine_sigaction(SIGTRAP, &segv_act, NULL); /* For breakpoints */
247 #endif
248 #if defined(__NetBSD__) || defined(__FreeBSD__)
249         sigset_t sig_mask;
250         struct sigaltstack ss;
251         
252 #if !defined (__FreeBSD__)
253         if ((ss.ss_base = malloc(MINSIGSTKSZ)) == NULL) {
254 #else
255         if ((ss.ss_sp = malloc(MINSIGSTKSZ)) == NULL) {
256 #endif
257                 fprintf(stderr, "Unable to allocate signal stack (%d bytes)\n",
258                         MINSIGSTKSZ);
259                 exit(1);
260         }
261         ss.ss_size = MINSIGSTKSZ;
262         ss.ss_flags = 0;
263         if (sigaltstack(&ss, NULL) < 0) {
264                 perror("sigstack");
265                 exit(1);
266         }
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);
274         }
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);
281         }
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);
288         }
289 #endif
290 }
291
292 #endif /* ifndef WINELIB */