summary refs log tree commit diff stats
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-23 16:49:39 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-23 16:49:39 +0000
commit9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966 (patch)
tree718d0257eb2e9cac1196bd8ca83dfd11c15fd475 /linux-user/main.c
parent66fb9763af9cd743158957e8c9c2559d922b1c22 (diff)
downloadfocaccia-qemu-9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966.tar.gz
focaccia-qemu-9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966.zip
better signal/exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c52
1 files changed, 45 insertions, 7 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index bcaa4be161..fba23a0132 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,7 +33,10 @@
 FILE *logfile = NULL;
 int loglevel;
 
-unsigned long x86_stack_size;
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+   we allocate a bigger stack. Need a better solution, for example
+   by remapping the process stack directly at the right place */
+unsigned long x86_stack_size = 512 * 1024;
 unsigned long stktop;
 
 void gemu_log(const char *fmt, ...)
@@ -102,10 +105,11 @@ uint64_t gdt_table[6];
 
 void cpu_loop(struct CPUX86State *env)
 {
+    int err;
+    uint8_t *pc;
+    target_siginfo_t info;
+    
     for(;;) {
-        int err;
-        uint8_t *pc;
-        
         err = cpu_x86_exec(env);
         pc = env->seg_cache[R_CS].base + env->eip;
         switch(err) {
@@ -122,12 +126,42 @@ void cpu_loop(struct CPUX86State *env)
                                               env->regs[R_EDI],
                                               env->regs[R_EBP]);
             } else {
-                goto trap_error;
+                /* XXX: more precise info */
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = 0;
+                info._sifields._sigfault._addr = 0;
+                queue_signal(info.si_signo, &info);
             }
             break;
+        case EXCP00_DIVZ:
+            /* division by zero */
+            info.si_signo = SIGFPE;
+            info.si_errno = 0;
+            info.si_code = TARGET_FPE_INTDIV;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP04_INTO:
+        case EXCP05_BOUND:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = 0;
+            info._sifields._sigfault._addr = 0;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP06_ILLOP:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->eip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
         default:
-        trap_error:
-            fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n", 
+            fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", 
                     (long)pc, err);
             abort();
         }
@@ -144,6 +178,9 @@ void usage(void)
     exit(1);
 }
 
+/* XXX: currently only used for async signals (see signal.c) */
+CPUX86State *global_env;
+
 int main(int argc, char **argv)
 {
     const char *filename;
@@ -199,6 +236,7 @@ int main(int argc, char **argv)
     signal_init();
 
     env = cpu_x86_init();
+    global_env = env;
 
     /* linux register setup */
     env->regs[R_EAX] = regs->eax;