Release 0.3.0
[wine/multimedia.git] / loader / signal.c
blob39f4080b6bf95b353e653f3a20e71f33866539fc
1 #include <signal.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <time.h>
6 #include <syscall.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <linux/sched.h>
10 #include <asm/system.h>
12 extern void ___sig_restore();
13 extern void ___masksig_restore();
15 /* Similar to the sigaction function in libc, except it leaves alone the
16 restorer field */
18 static int
19 wine_sigaction(int sig,struct sigaction * new, struct sigaction * old)
21 __asm__("int $0x80":"=a" (sig)
22 :"0" (SYS_sigaction),"b" (sig),"c" (new),"d" (old));
23 if (sig>=0)
24 return 0;
25 errno = -sig;
26 return -1;
29 char * cstack[4096];
30 struct sigaction segv_act;
32 struct sigcontext_struct {
33 unsigned short gs, __gsh;
34 unsigned short fs, __fsh;
35 unsigned short es, __esh;
36 unsigned short ds, __dsh;
37 unsigned long edi;
38 unsigned long esi;
39 unsigned long ebp;
40 unsigned long esp;
41 unsigned long ebx;
42 unsigned long edx;
43 unsigned long ecx;
44 unsigned long eax;
45 unsigned long trapno;
46 unsigned long err;
47 unsigned long eip;
48 unsigned short cs, __csh;
49 unsigned long eflags;
50 unsigned long esp_at_signal;
51 unsigned short ss, __ssh;
52 unsigned long i387;
53 unsigned long oldmask;
54 unsigned long cr2;
57 static void
58 GetTimeDate(int time_flag, struct sigcontext_struct * context)
60 struct tm *now;
61 time_t ltime;
63 ltime = time(NULL);
64 now = localtime(&ltime);
65 if (time_flag)
67 context->ecx = (now->tm_hour << 8) | now->tm_min;
68 context->edx = now->tm_sec << 8;
70 else
72 context->ecx = now->tm_year + 1900;
73 context->edx = ((now->tm_mon + 1) << 8) | now->tm_mday;
74 context->eax &= 0xff00;
75 context->eax |= now->tm_wday;
79 /* We handle all int21 calls here. There is some duplicate code from
80 misc/dos.c that I am unsure how to deal with, since the locations
81 that we store the registers are all different */
83 static int
84 do_int21(struct sigcontext_struct * context){
85 fprintf(stderr,"Doing int21 %x ", (context->eax >> 8) & 0xff);
86 switch((context->eax >> 8) & 0xff){
87 case 0x30:
88 context->eax = 0x0303; /* Hey folks, this is DOS V3.3! */
89 context->ebx = 0;
90 context->ecx = 0;
91 break;
93 /* Ignore any attempt to set a segment vector */
94 case 0x25:
95 return 1;
97 case 0x35: /* Return a NULL segment selector - this will bomb
98 if anyone ever tries to use it */
99 context->es = 0;
100 context->ebx = 0;
101 break;
103 case 0x2a:
104 GetTimeDate(0, context);
105 /* Function does not return */
107 case 0x2c:
108 GetTimeDate(1, context);
109 /* Function does not return */
111 case 0x4c:
112 exit(context->eax & 0xff);
115 default:
116 fprintf(stderr,"Unable to handle int 0x21 %x\n", context->eax);
117 return 1;
119 return 1;
122 static int
123 do_int1A(struct sigcontext_struct * context){
124 time_t ltime;
125 int ticks;
127 switch((context->eax >> 8) & 0xff){
128 case 0:
129 ltime = time(NULL);
130 ticks = (int) (ltime * HZ);
131 context->ecx = ticks >> 16;
132 context->edx = ticks & 0x0000FFFF;
133 context->eax = 0; /* No midnight rollover */
134 break;
136 default:
137 fprintf(stderr,"Unable to handle int 0x1A %x\n", context->eax);
138 return 1;
140 return 1;
143 static void win_segfault(int signal, struct sigcontext_struct context){
144 unsigned char * instr;
145 unsigned char intno;
146 unsigned int * dump;
147 int i;
149 /* First take care of a few preliminaries */
150 if(signal != SIGSEGV) exit(1);
151 if((context.cs & 7) != 7){
152 fprintf(stderr,
153 "Segmentation fault in Wine program (%x:%x)."
154 " Please debug\n",
155 context.cs, context.eip);
156 goto oops;
159 /* Now take a look at the actual instruction where the program
160 bombed */
161 instr = (char *) ((context.cs << 16) | (context.eip & 0xffff));
163 if(*instr != 0xcd) {
164 fprintf(stderr,
165 "Unexpected Windows program segfault"
166 " - opcode = %x\n", *instr);
167 #if 0
168 return;
169 #else
170 goto oops;
171 #endif
174 instr++;
175 intno = *instr;
176 switch(intno){
177 case 0x21:
178 if(!do_int21(&context)) goto oops;
179 break;
180 case 0x1A:
181 if(!do_int1A(&context)) goto oops;
182 break;
183 default:
184 fprintf(stderr,"Unexpected Windows interrupt %x\n", intno);
185 goto oops;
188 /* OK, done handling the interrupt */
190 context.eip += 2; /* Bypass the int instruction */
191 return;
193 oops:
194 fprintf(stderr,"In win_segfault %x:%x\n", context.cs, context.eip);
195 fprintf(stderr,"Stack: %x:%x\n", context.ss, context.esp_at_signal);
196 dump = (int*) &context;
197 for(i=0; i<22; i++)
199 fprintf(stderr," %8.8x", *dump++);
200 if ((i % 8) == 7)
201 fprintf(stderr,"\n");
203 fprintf(stderr,"\n");
204 exit(1);
208 init_wine_signals(){
209 segv_act.sa_handler = (__sighandler_t) win_segfault;
210 /* Point to the top of the stack, minus 4 just in case, and make
211 it aligned */
212 segv_act.sa_restorer =
213 (void (*)()) (((unsigned int)(cstack + sizeof(cstack) - 4)) & ~3);
214 wine_sigaction(SIGSEGV, &segv_act, NULL);