Commit 9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966

Authored by bellard
1 parent 66fb9763

better signal/exception support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
1   -- asynchronous signal interrupt / clear synchronous signal handling
2   -- add eflags restore in emulator
3   -- finish signal handing (fp87 state)
4   -- verify thread support (clone() and various locks)
5 1 - optimize translated cache chaining (DLL PLT-like system)
  2 +- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues)
  3 +- finish signal handing (fp87 state, more siginfo conversions)
  4 +- verify thread support (clone() and various locks)
6 5 - vm86 syscall support
7 6 - overrides/16bit for string ops
8   -- more syscalls (in particular all 64 bit ones)
9 7 - make it self runnable (use same trick as ld.so : include its own relocator and libc)
10 8 - improved 16 bit support
11 9 - fix FPU exceptions (in particular: gen_op_fpush not before mem load)
... ...
cpu-i386.h
... ... @@ -68,7 +68,7 @@
68 68 #define EXCP11_ALGN 18
69 69 #define EXCP12_MCHK 19
70 70  
71   -#define EXCP_SIGNAL 256 /* async signal */
  71 +#define EXCP_INTERRUPT 256 /* async interruption */
72 72  
73 73 enum {
74 74 CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
... ... @@ -170,9 +170,10 @@ typedef struct CPUX86State {
170 170 /* various CPU modes */
171 171 int vm86;
172 172  
173   - /* exception handling */
  173 + /* exception/interrupt handling */
174 174 jmp_buf jmp_env;
175 175 int exception_index;
  176 + int interrupt_request;
176 177 } CPUX86State;
177 178  
178 179 /* all CPU memory access use these macros */
... ... @@ -383,11 +384,19 @@ int cpu_x86_inl(int addr);
383 384  
384 385 CPUX86State *cpu_x86_init(void);
385 386 int cpu_x86_exec(CPUX86State *s);
  387 +void cpu_x86_interrupt(CPUX86State *s);
386 388 void cpu_x86_close(CPUX86State *s);
387 389  
388 390 /* needed to load some predefinied segment registers */
389 391 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
390 392  
  393 +/* you can call these signal handler from you SIGBUS and SIGSEGV
  394 + signal handlers to inform the virtual CPU of exceptions. non zero
  395 + is returned if the signal was handled by the virtual CPU. */
  396 +struct siginfo;
  397 +int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
  398 + void *puc);
  399 +
391 400 /* internal functions */
392 401  
393 402 #define GEN_FLAG_CODE32_SHIFT 0
... ...
exec-i386.c
... ... @@ -21,6 +21,7 @@
21 21  
22 22 //#define DEBUG_EXEC
23 23 #define DEBUG_FLUSH
  24 +//#define DEBUG_SIGNAL
24 25  
25 26 /* main execution loop */
26 27  
... ... @@ -98,7 +99,41 @@ void cpu_unlock(void)
98 99 global_cpu_lock = 0;
99 100 }
100 101  
101   -#ifdef DEBUG_EXEC
  102 +/* exception support */
  103 +/* NOTE: not static to force relocation generation by GCC */
  104 +void raise_exception(int exception_index)
  105 +{
  106 + /* NOTE: the register at this point must be saved by hand because
  107 + longjmp restore them */
  108 +#ifdef reg_EAX
  109 + env->regs[R_EAX] = EAX;
  110 +#endif
  111 +#ifdef reg_ECX
  112 + env->regs[R_ECX] = ECX;
  113 +#endif
  114 +#ifdef reg_EDX
  115 + env->regs[R_EDX] = EDX;
  116 +#endif
  117 +#ifdef reg_EBX
  118 + env->regs[R_EBX] = EBX;
  119 +#endif
  120 +#ifdef reg_ESP
  121 + env->regs[R_ESP] = ESP;
  122 +#endif
  123 +#ifdef reg_EBP
  124 + env->regs[R_EBP] = EBP;
  125 +#endif
  126 +#ifdef reg_ESI
  127 + env->regs[R_ESI] = ESI;
  128 +#endif
  129 +#ifdef reg_EDI
  130 + env->regs[R_EDI] = EDI;
  131 +#endif
  132 + env->exception_index = exception_index;
  133 + longjmp(env->jmp_env, 1);
  134 +}
  135 +
  136 +#if defined(DEBUG_EXEC)
102 137 static const char *cc_op_str[] = {
103 138 "DYNAMIC",
104 139 "EFLAGS",
... ... @@ -132,15 +167,16 @@ static const char *cc_op_str[] = {
132 167 "SARL",
133 168 };
134 169  
135   -static void cpu_x86_dump_state(void)
  170 +static void cpu_x86_dump_state(FILE *f)
136 171 {
137 172 int eflags;
138 173 eflags = cc_table[CC_OP].compute_all();
139 174 eflags |= (DF & DIRECTION_FLAG);
140   - fprintf(logfile,
  175 + fprintf(f,
141 176 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
142 177 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
143   - "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n",
  178 + "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
  179 + "EIP=%08x\n",
144 180 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
145 181 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
146 182 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
... ... @@ -150,10 +186,10 @@ static void cpu_x86_dump_state(void)
150 186 eflags & CC_Z ? 'Z' : '-',
151 187 eflags & CC_A ? 'A' : '-',
152 188 eflags & CC_P ? 'P' : '-',
153   - eflags & CC_C ? 'C' : '-'
154   - );
  189 + eflags & CC_C ? 'C' : '-',
  190 + env->eip);
155 191 #if 1
156   - fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
  192 + fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
157 193 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
158 194 #endif
159 195 }
... ... @@ -185,10 +221,11 @@ static void tb_flush(void)
185 221 }
186 222  
187 223 /* find a translation block in the translation cache. If not found,
188   - allocate a new one */
189   -static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
190   - unsigned long cs_base,
191   - unsigned int flags)
  224 + return NULL and the pointer to the last element of the list in pptb */
  225 +static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
  226 + unsigned long pc,
  227 + unsigned long cs_base,
  228 + unsigned int flags)
192 229 {
193 230 TranslationBlock **ptb, *tb;
194 231 unsigned int h;
... ... @@ -203,16 +240,19 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
203 240 return tb;
204 241 ptb = &tb->hash_next;
205 242 }
  243 + *pptb = ptb;
  244 + return NULL;
  245 +}
  246 +
  247 +/* allocate a new translation block. flush the translation buffer if
  248 + too many translation blocks or too much generated code */
  249 +static inline TranslationBlock *tb_alloc(void)
  250 +{
  251 + TranslationBlock *tb;
206 252 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
207 253 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
208 254 tb_flush();
209 255 tb = &tbs[nb_tbs++];
210   - *ptb = tb;
211   - tb->pc = pc;
212   - tb->cs_base = cs_base;
213   - tb->flags = flags;
214   - tb->tc_ptr = NULL;
215   - tb->hash_next = NULL;
216 256 return tb;
217 257 }
218 258  
... ... @@ -246,7 +286,7 @@ int cpu_x86_exec(CPUX86State *env1)
246 286 #endif
247 287 int code_gen_size, ret;
248 288 void (*gen_func)(void);
249   - TranslationBlock *tb;
  289 + TranslationBlock *tb, **ptb;
250 290 uint8_t *tc_ptr, *cs_base, *pc;
251 291 unsigned int flags;
252 292  
... ... @@ -289,12 +329,21 @@ int cpu_x86_exec(CPUX86State *env1)
289 329 EDI = env->regs[R_EDI];
290 330 #endif
291 331  
  332 + /* put eflags in CPU temporary format */
  333 + T0 = env->eflags;
  334 + op_movl_eflags_T0();
  335 + CC_OP = CC_OP_EFLAGS;
  336 + env->interrupt_request = 0;
  337 +
292 338 /* prepare setjmp context for exception handling */
293 339 if (setjmp(env->jmp_env) == 0) {
294 340 for(;;) {
  341 + if (env->interrupt_request) {
  342 + raise_exception(EXCP_INTERRUPT);
  343 + }
295 344 #ifdef DEBUG_EXEC
296 345 if (loglevel) {
297   - cpu_x86_dump_state();
  346 + cpu_x86_dump_state(logfile);
298 347 }
299 348 #endif
300 349 /* we compute the CPU state. We assume it will not
... ... @@ -307,28 +356,43 @@ int cpu_x86_exec(CPUX86State *env1)
307 356 GEN_FLAG_ADDSEG_SHIFT;
308 357 cs_base = env->seg_cache[R_CS].base;
309 358 pc = cs_base + env->eip;
310   - tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base,
311   - flags);
312   - tc_ptr = tb->tc_ptr;
313   - if (!tb->tc_ptr) {
  359 + tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
  360 + flags);
  361 + if (!tb) {
314 362 /* if no translated code available, then translate it now */
315 363 /* XXX: very inefficient: we lock all the cpus when
316 364 generating code */
317 365 cpu_lock();
318 366 tc_ptr = code_gen_ptr;
319   - cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
320   - &code_gen_size, pc, cs_base, flags);
  367 + ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
  368 + &code_gen_size, pc, cs_base, flags);
  369 + /* if invalid instruction, signal it */
  370 + if (ret != 0) {
  371 + cpu_unlock();
  372 + raise_exception(EXCP06_ILLOP);
  373 + }
  374 + tb = tb_alloc();
  375 + *ptb = tb;
  376 + tb->pc = (unsigned long)pc;
  377 + tb->cs_base = (unsigned long)cs_base;
  378 + tb->flags = flags;
321 379 tb->tc_ptr = tc_ptr;
  380 + tb->hash_next = NULL;
322 381 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
323 382 cpu_unlock();
324 383 }
325 384 /* execute the generated code */
  385 + tc_ptr = tb->tc_ptr;
326 386 gen_func = (void *)tc_ptr;
327 387 gen_func();
328 388 }
329 389 }
330 390 ret = env->exception_index;
331 391  
  392 + /* restore flags in standard format */
  393 + op_movl_T0_eflags();
  394 + env->eflags = T0;
  395 +
332 396 /* restore global registers */
333 397 #ifdef reg_EAX
334 398 EAX = saved_EAX;
... ... @@ -361,6 +425,12 @@ int cpu_x86_exec(CPUX86State *env1)
361 425 return ret;
362 426 }
363 427  
  428 +void cpu_x86_interrupt(CPUX86State *s)
  429 +{
  430 + s->interrupt_request = 1;
  431 +}
  432 +
  433 +
364 434 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
365 435 {
366 436 CPUX86State *saved_env;
... ... @@ -370,3 +440,56 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
370 440 load_seg(seg_reg, selector);
371 441 env = saved_env;
372 442 }
  443 +
  444 +#undef EAX
  445 +#undef ECX
  446 +#undef EDX
  447 +#undef EBX
  448 +#undef ESP
  449 +#undef EBP
  450 +#undef ESI
  451 +#undef EDI
  452 +#undef EIP
  453 +#include <signal.h>
  454 +#include <sys/ucontext.h>
  455 +
  456 +static inline int handle_cpu_signal(unsigned long pc,
  457 + sigset_t *old_set)
  458 +{
  459 +#ifdef DEBUG_SIGNAL
  460 + printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
  461 + pc, *(unsigned long *)old_set);
  462 +#endif
  463 + if (pc >= (unsigned long)code_gen_buffer &&
  464 + pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
  465 + /* the PC is inside the translated code. It means that we have
  466 + a virtual CPU fault */
  467 + /* we restore the process signal mask as the sigreturn should
  468 + do it */
  469 + sigprocmask(SIG_SETMASK, old_set, NULL);
  470 + /* XXX: need to compute virtual pc position by retranslating
  471 + code. The rest of the CPU state should be correct. */
  472 + raise_exception(EXCP0D_GPF);
  473 + /* never comes here */
  474 + return 1;
  475 + } else {
  476 + return 0;
  477 + }
  478 +}
  479 +
  480 +int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
  481 + void *puc)
  482 +{
  483 +#if defined(__i386__)
  484 + struct ucontext *uc = puc;
  485 + unsigned long pc;
  486 + sigset_t *pold_set;
  487 +
  488 + pc = uc->uc_mcontext.gregs[EIP];
  489 + pold_set = &uc->uc_sigmask;
  490 + return handle_cpu_signal(pc, pold_set);
  491 +#else
  492 +#warning No CPU specific signal handler: cannot handle target SIGSEGV events
  493 + return 0;
  494 +#endif
  495 +}
... ...
exec-i386.h
... ... @@ -141,3 +141,7 @@ extern CCTable cc_table[];
141 141 void load_seg(int seg_reg, int selector);
142 142 void cpu_lock(void);
143 143 void cpu_unlock(void);
  144 +void raise_exception(int exception_index);
  145 +
  146 +void OPPROTO op_movl_eflags_T0(void);
  147 +void OPPROTO op_movl_T0_eflags(void);
... ...
linux-user/elfload.c
... ... @@ -261,6 +261,9 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
261 261 /* Create enough stack to hold everything. If we don't use
262 262 * it for args, we'll use it for something else...
263 263 */
  264 + /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
  265 + we allocate a bigger stack. Need a better solution, for example
  266 + by remapping the process stack directly at the right place */
264 267 if(x86_stack_size > MAX_ARG_PAGES*X86_PAGE_SIZE) {
265 268 if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
266 269 PROT_READ | PROT_WRITE,
... ...
linux-user/ioctls.h
1 1 /* emulated ioctl list */
2 2  
3 3 IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
4   - IOCTL(TCGETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
  4 + IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
5 5 IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
6 6 IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
7 7 IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
... ... @@ -199,8 +199,12 @@
199 199 IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
200 200 IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
201 201 IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
  202 +#if 0
  203 + /* we invalidate these defines because they have a same number as
  204 + termios ioctls */
202 205 IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
203 206 IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
  207 +#endif
204 208 IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
205 209 IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
206 210  
... ...
linux-user/main.c
... ... @@ -33,7 +33,10 @@
33 33 FILE *logfile = NULL;
34 34 int loglevel;
35 35  
36   -unsigned long x86_stack_size;
  36 +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
  37 + we allocate a bigger stack. Need a better solution, for example
  38 + by remapping the process stack directly at the right place */
  39 +unsigned long x86_stack_size = 512 * 1024;
37 40 unsigned long stktop;
38 41  
39 42 void gemu_log(const char *fmt, ...)
... ... @@ -102,10 +105,11 @@ uint64_t gdt_table[6];
102 105  
103 106 void cpu_loop(struct CPUX86State *env)
104 107 {
  108 + int err;
  109 + uint8_t *pc;
  110 + target_siginfo_t info;
  111 +
105 112 for(;;) {
106   - int err;
107   - uint8_t *pc;
108   -
109 113 err = cpu_x86_exec(env);
110 114 pc = env->seg_cache[R_CS].base + env->eip;
111 115 switch(err) {
... ... @@ -122,12 +126,42 @@ void cpu_loop(struct CPUX86State *env)
122 126 env->regs[R_EDI],
123 127 env->regs[R_EBP]);
124 128 } else {
125   - goto trap_error;
  129 + /* XXX: more precise info */
  130 + info.si_signo = SIGSEGV;
  131 + info.si_errno = 0;
  132 + info.si_code = 0;
  133 + info._sifields._sigfault._addr = 0;
  134 + queue_signal(info.si_signo, &info);
126 135 }
127 136 break;
  137 + case EXCP00_DIVZ:
  138 + /* division by zero */
  139 + info.si_signo = SIGFPE;
  140 + info.si_errno = 0;
  141 + info.si_code = TARGET_FPE_INTDIV;
  142 + info._sifields._sigfault._addr = env->eip;
  143 + queue_signal(info.si_signo, &info);
  144 + break;
  145 + case EXCP04_INTO:
  146 + case EXCP05_BOUND:
  147 + info.si_signo = SIGSEGV;
  148 + info.si_errno = 0;
  149 + info.si_code = 0;
  150 + info._sifields._sigfault._addr = 0;
  151 + queue_signal(info.si_signo, &info);
  152 + break;
  153 + case EXCP06_ILLOP:
  154 + info.si_signo = SIGILL;
  155 + info.si_errno = 0;
  156 + info.si_code = TARGET_ILL_ILLOPN;
  157 + info._sifields._sigfault._addr = env->eip;
  158 + queue_signal(info.si_signo, &info);
  159 + break;
  160 + case EXCP_INTERRUPT:
  161 + /* just indicate that signals should be handled asap */
  162 + break;
128 163 default:
129   - trap_error:
130   - fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n",
  164 + fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n",
131 165 (long)pc, err);
132 166 abort();
133 167 }
... ... @@ -144,6 +178,9 @@ void usage(void)
144 178 exit(1);
145 179 }
146 180  
  181 +/* XXX: currently only used for async signals (see signal.c) */
  182 +CPUX86State *global_env;
  183 +
147 184 int main(int argc, char **argv)
148 185 {
149 186 const char *filename;
... ... @@ -199,6 +236,7 @@ int main(int argc, char **argv)
199 236 signal_init();
200 237  
201 238 env = cpu_x86_init();
  239 + global_env = env;
202 240  
203 241 /* linux register setup */
204 242 env->regs[R_EAX] = regs->eax;
... ...
linux-user/qemu.h
... ... @@ -3,30 +3,12 @@
3 3  
4 4 #include "thunk.h"
5 5  
6   -#ifdef TARGET_I386
7   -
8   -/* default linux values for the selectors */
9   -#define __USER_CS (0x23)
10   -#define __USER_DS (0x2B)
11   -
12   -struct target_pt_regs {
13   - long ebx;
14   - long ecx;
15   - long edx;
16   - long esi;
17   - long edi;
18   - long ebp;
19   - long eax;
20   - int xds;
21   - int xes;
22   - long orig_eax;
23   - long eip;
24   - int xcs;
25   - long eflags;
26   - long esp;
27   - int xss;
28   -};
  6 +#include <signal.h>
  7 +#include "syscall_defs.h"
29 8  
  9 +#ifdef TARGET_I386
  10 +#include "cpu-i386.h"
  11 +#include "syscall-i386.h"
30 12 #endif
31 13  
32 14 /* This struct is used to hold certain information about the image.
... ... @@ -59,9 +41,10 @@ void syscall_init(void);
59 41 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
60 42 long arg4, long arg5, long arg6);
61 43 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
62   -struct CPUX86State;
63   -void cpu_loop(struct CPUX86State *env);
  44 +extern CPUX86State *global_env;
  45 +void cpu_loop(CPUX86State *env);
64 46 void process_pending_signals(void *cpu_env);
65 47 void signal_init(void);
  48 +int queue_signal(int sig, target_siginfo_t *info);
66 49  
67 50 #endif
... ...
linux-user/signal.c
... ... @@ -27,13 +27,6 @@
27 27  
28 28 #include "gemu.h"
29 29  
30   -#include "syscall_defs.h"
31   -
32   -#ifdef TARGET_I386
33   -#include "cpu-i386.h"
34   -#include "syscall-i386.h"
35   -#endif
36   -
37 30 /* signal handling inspired from em86. */
38 31  
39 32 //#define DEBUG_SIGNAL
... ... @@ -42,7 +35,7 @@
42 35  
43 36 struct sigqueue {
44 37 struct sigqueue *next;
45   - siginfo_t info;
  38 + target_siginfo_t info;
46 39 };
47 40  
48 41 struct emulated_sigaction {
... ... @@ -101,20 +94,66 @@ void target_to_host_old_sigset(sigset_t *sigset,
101 94 *(unsigned long *)sigset = tswapl(*old_sigset);
102 95 }
103 96  
104   -/* XXX: finish it */
105   -void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info)
  97 +/* siginfo conversion */
  98 +
  99 +static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
  100 + const siginfo_t *info)
106 101 {
107   - tinfo->si_signo = tswap32(info->si_signo);
  102 + int sig;
  103 + sig = host_to_target_signal(info->si_signo);
  104 + tinfo->si_signo = sig;
  105 + tinfo->si_errno = 0;
  106 + tinfo->si_code = 0;
  107 + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
  108 + /* should never come here, but who knows. The information for
  109 + the target is irrelevant */
  110 + tinfo->_sifields._sigfault._addr = 0;
  111 + } else if (sig >= TARGET_SIGRTMIN) {
  112 + tinfo->_sifields._rt._pid = info->si_pid;
  113 + tinfo->_sifields._rt._uid = info->si_uid;
  114 + /* XXX: potential problem if 64 bit */
  115 + tinfo->_sifields._rt._sigval.sival_ptr =
  116 + (target_ulong)info->si_value.sival_ptr;
  117 + }
  118 +}
  119 +
  120 +static void tswap_siginfo(target_siginfo_t *tinfo,
  121 + const target_siginfo_t *info)
  122 +{
  123 + int sig;
  124 + sig = info->si_signo;
  125 + tinfo->si_signo = tswap32(sig);
108 126 tinfo->si_errno = tswap32(info->si_errno);
109 127 tinfo->si_code = tswap32(info->si_code);
  128 + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
  129 + tinfo->_sifields._sigfault._addr =
  130 + tswapl(info->_sifields._sigfault._addr);
  131 + } else if (sig >= TARGET_SIGRTMIN) {
  132 + tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
  133 + tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
  134 + tinfo->_sifields._rt._sigval.sival_ptr =
  135 + tswapl(info->_sifields._rt._sigval.sival_ptr);
  136 + }
  137 +}
  138 +
  139 +
  140 +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
  141 +{
  142 + host_to_target_siginfo_noswap(tinfo, info);
  143 + tswap_siginfo(tinfo, tinfo);
110 144 }
111 145  
112   -/* XXX: finish it */
113   -void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo)
  146 +/* XXX: we support only POSIX RT signals are used. */
  147 +/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
  148 +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
114 149 {
115 150 info->si_signo = tswap32(tinfo->si_signo);
116 151 info->si_errno = tswap32(tinfo->si_errno);
117 152 info->si_code = tswap32(tinfo->si_code);
  153 + info->si_pid = tswap32(tinfo->_sifields._rt._pid);
  154 + info->si_uid = tswap32(tinfo->_sifields._rt._uid);
  155 + info->si_value.sival_ptr =
  156 + (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
118 157 }
119 158  
120 159 void signal_init(void)
... ... @@ -122,8 +161,9 @@ void signal_init(void)
122 161 struct sigaction act;
123 162 int i;
124 163  
125   - /* set all host signal handlers */
126   - sigemptyset(&act.sa_mask);
  164 + /* set all host signal handlers. ALL signals are blocked during
  165 + the handlers to serialize them. */
  166 + sigfillset(&act.sa_mask);
127 167 act.sa_flags = SA_SIGINFO;
128 168 act.sa_sigaction = host_signal_handler;
129 169 for(i = 1; i < NSIG; i++) {
... ... @@ -155,56 +195,40 @@ static inline void free_sigqueue(struct sigqueue *q)
155 195 first_free = q;
156 196 }
157 197  
158   -static int queue_signal(struct emulated_sigaction *k, int sig, siginfo_t *info)
159   -{
160   - struct sigqueue *q, **pq;
161   -
162   - pq = &k->first;
163   - if (!k->pending || sig < TARGET_SIGRTMIN) {
164   - /* first signal or non real time signal */
165   - q = &k->info;
166   - } else {
167   - q = alloc_sigqueue();
168   - if (!q)
169   - return -EAGAIN;
170   - while (*pq != NULL)
171   - pq = &(*pq)->next;
172   - }
173   - *pq = q;
174   - q->info = *info;
175   - q->next = NULL;
176   - k->pending = 1;
177   - /* signal that a new signal is pending */
178   - signal_pending = 1;
179   - return 0;
180   -}
181   -
182   -void force_sig(int sig)
  198 +/* abort execution with signal */
  199 +void __attribute((noreturn)) force_sig(int sig)
183 200 {
184 201 int host_sig;
185   - /* abort execution with signal */
186 202 host_sig = target_to_host_signal(sig);
187 203 fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n",
188 204 sig, strsignal(host_sig));
  205 +#if 1
189 206 _exit(-host_sig);
  207 +#else
  208 + {
  209 + struct sigaction act;
  210 + sigemptyset(&act.sa_mask);
  211 + act.sa_flags = SA_SIGINFO;
  212 + act.sa_sigaction = SIG_DFL;
  213 + sigaction(SIGABRT, &act, NULL);
  214 + abort();
  215 + }
  216 +#endif
190 217 }
191 218  
192   -
193   -static void host_signal_handler(int host_signum, siginfo_t *info,
194   - void *puc)
  219 +/* queue a signal so that it will be send to the virtual CPU as soon
  220 + as possible */
  221 +int queue_signal(int sig, target_siginfo_t *info)
195 222 {
196 223 struct emulated_sigaction *k;
197   - int sig;
  224 + struct sigqueue *q, **pq;
198 225 target_ulong handler;
199 226  
200   - /* get target signal number */
201   - sig = host_to_target_signal(host_signum);
202   - if (sig < 1 || sig > TARGET_NSIG)
203   - return;
204   - k = &sigact_table[sig - 1];
205   -#ifdef DEBUG_SIGNAL
206   - fprintf(stderr, "gemu: got signal %d\n", sig);
  227 +#if defined(DEBUG_SIGNAL)
  228 + fprintf(stderr, "queue_sigal: sig=%d\n",
  229 + sig);
207 230 #endif
  231 + k = &sigact_table[sig - 1];
208 232 handler = k->sa._sa_handler;
209 233 if (handler == TARGET_SIG_DFL) {
210 234 /* default handler : ignore some signal. The other are fatal */
... ... @@ -212,13 +236,96 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
212 236 sig != TARGET_SIGURG &&
213 237 sig != TARGET_SIGWINCH) {
214 238 force_sig(sig);
  239 + } else {
  240 + return 0; /* indicate ignored */
215 241 }
216 242 } else if (handler == TARGET_SIG_IGN) {
217 243 /* ignore signal */
  244 + return 0;
218 245 } else if (handler == TARGET_SIG_ERR) {
219 246 force_sig(sig);
220 247 } else {
221   - queue_signal(k, sig, info);
  248 + pq = &k->first;
  249 + if (sig < TARGET_SIGRTMIN) {
  250 + /* if non real time signal, we queue exactly one signal */
  251 + if (!k->pending)
  252 + q = &k->info;
  253 + else
  254 + return 0;
  255 + } else {
  256 + if (!k->pending) {
  257 + /* first signal */
  258 + q = &k->info;
  259 + } else {
  260 + q = alloc_sigqueue();
  261 + if (!q)
  262 + return -EAGAIN;
  263 + while (*pq != NULL)
  264 + pq = &(*pq)->next;
  265 + }
  266 + }
  267 + *pq = q;
  268 + q->info = *info;
  269 + q->next = NULL;
  270 + k->pending = 1;
  271 + /* signal that a new signal is pending */
  272 + signal_pending = 1;
  273 + return 1; /* indicates that the signal was queued */
  274 + }
  275 +}
  276 +
  277 +#if defined(DEBUG_SIGNAL)
  278 +#ifdef __i386__
  279 +static void dump_regs(struct ucontext *uc)
  280 +{
  281 + fprintf(stderr,
  282 + "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
  283 + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
  284 + "EFL=%08x EIP=%08x\n",
  285 + uc->uc_mcontext.gregs[EAX],
  286 + uc->uc_mcontext.gregs[EBX],
  287 + uc->uc_mcontext.gregs[ECX],
  288 + uc->uc_mcontext.gregs[EDX],
  289 + uc->uc_mcontext.gregs[ESI],
  290 + uc->uc_mcontext.gregs[EDI],
  291 + uc->uc_mcontext.gregs[EBP],
  292 + uc->uc_mcontext.gregs[ESP],
  293 + uc->uc_mcontext.gregs[EFL],
  294 + uc->uc_mcontext.gregs[EIP]);
  295 +}
  296 +#else
  297 +static void dump_regs(struct ucontext *uc)
  298 +{
  299 +}
  300 +#endif
  301 +
  302 +#endif
  303 +
  304 +static void host_signal_handler(int host_signum, siginfo_t *info,
  305 + void *puc)
  306 +{
  307 + int sig;
  308 + target_siginfo_t tinfo;
  309 +
  310 + /* the CPU emulator uses some host signals to detect exceptions,
  311 + we we forward to it some signals */
  312 + if (host_signum == SIGSEGV || host_signum == SIGBUS) {
  313 + if (cpu_x86_signal_handler(host_signum, info, puc))
  314 + return;
  315 + }
  316 +
  317 + /* get target signal number */
  318 + sig = host_to_target_signal(host_signum);
  319 + if (sig < 1 || sig > TARGET_NSIG)
  320 + return;
  321 +#if defined(DEBUG_SIGNAL)
  322 + fprintf(stderr, "gemu: got signal %d\n", sig);
  323 + dump_regs(puc);
  324 +#endif
  325 + host_to_target_siginfo_noswap(&tinfo, info);
  326 + if (queue_signal(sig, &tinfo) == 1) {
  327 + /* interrupt the virtual CPU as soon as possible */
  328 + cpu_x86_interrupt(global_env);
222 329 }
223 330 }
224 331  
... ... @@ -388,9 +495,10 @@ struct rt_sigframe
388 495 0;\
389 496 })
390 497  
391   -static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, siginfo_t *info)
  498 +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
  499 + const target_siginfo_t *info)
392 500 {
393   - host_to_target_siginfo(tinfo, info);
  501 + tswap_siginfo(tinfo, info);
394 502 return 0;
395 503 }
396 504  
... ... @@ -531,7 +639,8 @@ give_sigsegv:
531 639 force_sig(TARGET_SIGSEGV /* , current */);
532 640 }
533 641  
534   -static void setup_rt_frame(int sig, struct emulated_sigaction *ka, siginfo_t *info,
  642 +static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
  643 + target_siginfo_t *info,
535 644 target_sigset_t *set, CPUX86State *env)
536 645 {
537 646 struct rt_sigframe *frame;
... ... @@ -734,7 +843,8 @@ void process_pending_signals(void *cpu_env)
734 843 {
735 844 int sig;
736 845 target_ulong handler;
737   - target_sigset_t set;
  846 + sigset_t set, old_set;
  847 + target_sigset_t target_old_set;
738 848 struct emulated_sigaction *k;
739 849 struct sigqueue *q;
740 850  
... ... @@ -774,12 +884,24 @@ void process_pending_signals(void *cpu_env)
774 884 } else if (handler == TARGET_SIG_ERR) {
775 885 force_sig(sig);
776 886 } else {
777   - set = k->sa.sa_mask;
778   - /* send the signal to the CPU */
  887 + /* compute the blocked signals during the handler execution */
  888 + target_to_host_sigset(&set, &k->sa.sa_mask);
  889 + /* SA_NODEFER indicates that the current signal should not be
  890 + blocked during the handler */
  891 + if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
  892 + sigaddset(&set, target_to_host_signal(sig));
  893 +
  894 + /* block signals in the handler using Linux */
  895 + sigprocmask(SIG_BLOCK, &set, &old_set);
  896 + /* save the previous blocked signal state to restore it at the
  897 + end of the signal execution (see do_sigreturn) */
  898 + host_to_target_sigset(&target_old_set, &old_set);
  899 +
  900 + /* prepare the stack frame of the virtual CPU */
779 901 if (k->sa.sa_flags & TARGET_SA_SIGINFO)
780   - setup_rt_frame(sig, k, &q->info, &set, cpu_env);
  902 + setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
781 903 else
782   - setup_frame(sig, k, &set, cpu_env);
  904 + setup_frame(sig, k, &target_old_set, cpu_env);
783 905 if (k->sa.sa_flags & TARGET_SA_RESETHAND)
784 906 k->sa._sa_handler = TARGET_SIG_DFL;
785 907 }
... ...
linux-user/syscall.c
... ... @@ -38,6 +38,7 @@
38 38 #include <sched.h>
39 39 #include <sys/socket.h>
40 40 #include <sys/uio.h>
  41 +#include <sys/poll.h>
41 42 //#include <sys/user.h>
42 43  
43 44 #define termios host_termios
... ... @@ -68,15 +69,8 @@
68 69 #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
69 70 #define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
70 71  
71   -#include "syscall_defs.h"
72   -
73   -#ifdef TARGET_I386
74   -#include "cpu-i386.h"
75   -#include "syscall-i386.h"
76   -#endif
77   -
78   -void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info);
79   -void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo);
  72 +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
  73 +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
80 74 long do_sigreturn(CPUX86State *env);
81 75 long do_rt_sigreturn(CPUX86State *env);
82 76  
... ... @@ -106,6 +100,9 @@ _syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
106 100 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
107 101  
108 102 extern int personality(int);
  103 +extern int flock(int, int);
  104 +extern int setfsuid(int);
  105 +extern int setfsgid(int);
109 106  
110 107 static inline long get_errno(long ret)
111 108 {
... ... @@ -437,7 +434,7 @@ static long do_ioctl(long fd, long cmd, long arg)
437 434 ie++;
438 435 }
439 436 arg_type = ie->arg_type;
440   -#ifdef DEBUG
  437 +#if defined(DEBUG)
441 438 gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
442 439 #endif
443 440 switch(arg_type[0]) {
... ... @@ -1244,9 +1241,30 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1244 1241 ret = get_errno(sethostname((const char *)arg1, arg2));
1245 1242 break;
1246 1243 case TARGET_NR_setrlimit:
1247   - goto unimplemented;
  1244 + {
  1245 + /* XXX: convert resource ? */
  1246 + int resource = arg1;
  1247 + struct target_rlimit *target_rlim = (void *)arg2;
  1248 + struct rlimit rlim;
  1249 + rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
  1250 + rlim.rlim_max = tswapl(target_rlim->rlim_max);
  1251 + ret = get_errno(setrlimit(resource, &rlim));
  1252 + }
  1253 + break;
1248 1254 case TARGET_NR_getrlimit:
1249   - goto unimplemented;
  1255 + {
  1256 + /* XXX: convert resource ? */
  1257 + int resource = arg1;
  1258 + struct target_rlimit *target_rlim = (void *)arg2;
  1259 + struct rlimit rlim;
  1260 +
  1261 + ret = get_errno(getrlimit(resource, &rlim));
  1262 + if (!is_error(ret)) {
  1263 + target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
  1264 + target_rlim->rlim_max = tswapl(rlim.rlim_max);
  1265 + }
  1266 + }
  1267 + break;
1250 1268 case TARGET_NR_getrusage:
1251 1269 goto unimplemented;
1252 1270 case TARGET_NR_gettimeofday:
... ... @@ -1317,6 +1335,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1317 1335 case TARGET_NR_munmap:
1318 1336 ret = get_errno(munmap((void *)arg1, arg2));
1319 1337 break;
  1338 + case TARGET_NR_mprotect:
  1339 + ret = get_errno(mprotect((void *)arg1, arg2, arg3));
  1340 + break;
  1341 + case TARGET_NR_mremap:
  1342 + ret = get_errno((long)mremap((void *)arg1, arg2, arg3, arg4));
  1343 + break;
  1344 + case TARGET_NR_msync:
  1345 + ret = get_errno(msync((void *)arg1, arg2, arg3));
  1346 + break;
  1347 + case TARGET_NR_mlock:
  1348 + ret = get_errno(mlock((void *)arg1, arg2));
  1349 + break;
  1350 + case TARGET_NR_munlock:
  1351 + ret = get_errno(munlock((void *)arg1, arg2));
  1352 + break;
  1353 + case TARGET_NR_mlockall:
  1354 + ret = get_errno(mlockall(arg1));
  1355 + break;
  1356 + case TARGET_NR_munlockall:
  1357 + ret = get_errno(munlockall());
  1358 + break;
1320 1359 case TARGET_NR_truncate:
1321 1360 ret = get_errno(truncate((const char *)arg1, arg2));
1322 1361 break;
... ... @@ -1506,9 +1545,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1506 1545 #endif
1507 1546 case TARGET_NR_adjtimex:
1508 1547 goto unimplemented;
1509   - case TARGET_NR_mprotect:
1510   - ret = get_errno(mprotect((void *)arg1, arg2, arg3));
1511   - break;
1512 1548 case TARGET_NR_create_module:
1513 1549 case TARGET_NR_init_module:
1514 1550 case TARGET_NR_delete_module:
... ... @@ -1532,9 +1568,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1532 1568 case TARGET_NR_afs_syscall:
1533 1569 goto unimplemented;
1534 1570 case TARGET_NR_setfsuid:
1535   - goto unimplemented;
  1571 + ret = get_errno(setfsuid(arg1));
  1572 + break;
1536 1573 case TARGET_NR_setfsgid:
1537   - goto unimplemented;
  1574 + ret = get_errno(setfsgid(arg1));
  1575 + break;
1538 1576 case TARGET_NR__llseek:
1539 1577 {
1540 1578 int64_t res;
... ... @@ -1596,10 +1634,31 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1596 1634 ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
1597 1635 (void *)arg5);
1598 1636 break;
  1637 + case TARGET_NR_poll:
  1638 + {
  1639 + struct target_pollfd *target_pfd = (void *)arg1;
  1640 + unsigned int nfds = arg2;
  1641 + int timeout = arg3;
  1642 + struct pollfd *pfd;
  1643 + int i;
  1644 +
  1645 + pfd = alloca(sizeof(struct pollfd) * nfds);
  1646 + for(i = 0; i < nfds; i++) {
  1647 + pfd->fd = tswap32(target_pfd->fd);
  1648 + pfd->events = tswap16(target_pfd->events);
  1649 + }
  1650 + ret = get_errno(poll(pfd, nfds, timeout));
  1651 + if (!is_error(ret)) {
  1652 + for(i = 0; i < nfds; i++) {
  1653 + target_pfd->revents = tswap16(pfd->revents);
  1654 + }
  1655 + }
  1656 + }
  1657 + break;
1599 1658 case TARGET_NR_flock:
1600   - goto unimplemented;
1601   - case TARGET_NR_msync:
1602   - ret = get_errno(msync((void *)arg1, arg2, arg3));
  1659 + /* NOTE: the flock constant seems to be the same for every
  1660 + Linux platform */
  1661 + ret = get_errno(flock(arg1, arg2));
1603 1662 break;
1604 1663 case TARGET_NR_readv:
1605 1664 {
... ... @@ -1638,18 +1697,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1638 1697 goto unimplemented;
1639 1698 case TARGET_NR__sysctl:
1640 1699 goto unimplemented;
1641   - case TARGET_NR_mlock:
1642   - ret = get_errno(mlock((void *)arg1, arg2));
1643   - break;
1644   - case TARGET_NR_munlock:
1645   - ret = get_errno(munlock((void *)arg1, arg2));
1646   - break;
1647   - case TARGET_NR_mlockall:
1648   - ret = get_errno(mlockall(arg1));
1649   - break;
1650   - case TARGET_NR_munlockall:
1651   - ret = get_errno(munlockall());
1652   - break;
1653 1700 case TARGET_NR_sched_setparam:
1654 1701 goto unimplemented;
1655 1702 case TARGET_NR_sched_getparam:
... ... @@ -1681,12 +1728,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1681 1728 }
1682 1729 break;
1683 1730  
1684   - case TARGET_NR_mremap:
1685 1731 case TARGET_NR_setresuid:
1686 1732 case TARGET_NR_getresuid:
1687 1733 case TARGET_NR_vm86:
1688 1734 case TARGET_NR_query_module:
1689   - case TARGET_NR_poll:
1690 1735 case TARGET_NR_nfsservctl:
1691 1736 case TARGET_NR_setresgid:
1692 1737 case TARGET_NR_getresgid:
... ... @@ -1800,7 +1845,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
1800 1845 goto unimplemented;
1801 1846 default:
1802 1847 unimplemented:
1803   - gemu_log("Unsupported syscall: %d\n", num);
  1848 + gemu_log("gemu: Unsupported syscall: %d\n", num);
1804 1849 ret = -ENOSYS;
1805 1850 break;
1806 1851 }
... ...
linux-user/syscall_defs.h
... ... @@ -150,6 +150,17 @@ struct target_sigaction;
150 150 int do_sigaction(int sig, const struct target_sigaction *act,
151 151 struct target_sigaction *oact);
152 152  
  153 +struct target_rlimit {
  154 + target_ulong rlim_cur;
  155 + target_ulong rlim_max;
  156 +};
  157 +
  158 +struct target_pollfd {
  159 + int fd; /* file descriptor */
  160 + short events; /* requested events */
  161 + short revents; /* returned events */
  162 +};
  163 +
153 164 /* Networking ioctls */
154 165 #define TARGET_SIOCADDRT 0x890B /* add routing table entry */
155 166 #define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
... ...
op-i386.c
... ... @@ -119,40 +119,6 @@ static inline int lshift(int x, int n)
119 119 return x >> (-n);
120 120 }
121 121  
122   -/* exception support */
123   -/* NOTE: not static to force relocation generation by GCC */
124   -void raise_exception(int exception_index)
125   -{
126   - /* NOTE: the register at this point must be saved by hand because
127   - longjmp restore them */
128   -#ifdef reg_EAX
129   - env->regs[R_EAX] = EAX;
130   -#endif
131   -#ifdef reg_ECX
132   - env->regs[R_ECX] = ECX;
133   -#endif
134   -#ifdef reg_EDX
135   - env->regs[R_EDX] = EDX;
136   -#endif
137   -#ifdef reg_EBX
138   - env->regs[R_EBX] = EBX;
139   -#endif
140   -#ifdef reg_ESP
141   - env->regs[R_ESP] = ESP;
142   -#endif
143   -#ifdef reg_EBP
144   - env->regs[R_EBP] = EBP;
145   -#endif
146   -#ifdef reg_ESI
147   - env->regs[R_ESI] = ESI;
148   -#endif
149   -#ifdef reg_EDI
150   - env->regs[R_EDI] = EDI;
151   -#endif
152   - env->exception_index = exception_index;
153   - longjmp(env->jmp_env, 1);
154   -}
155   -
156 122 /* we define the various pieces of code used by the JIT */
157 123  
158 124 #define REG EAX
... ... @@ -391,13 +357,15 @@ void OPPROTO op_imull_T0_T1(void)
391 357 }
392 358  
393 359 /* division, flags are undefined */
394   -/* XXX: add exceptions for overflow & div by zero */
  360 +/* XXX: add exceptions for overflow */
395 361 void OPPROTO op_divb_AL_T0(void)
396 362 {
397 363 unsigned int num, den, q, r;
398 364  
399 365 num = (EAX & 0xffff);
400 366 den = (T0 & 0xff);
  367 + if (den == 0)
  368 + raise_exception(EXCP00_DIVZ);
401 369 q = (num / den) & 0xff;
402 370 r = (num % den) & 0xff;
403 371 EAX = (EAX & 0xffff0000) | (r << 8) | q;
... ... @@ -409,6 +377,8 @@ void OPPROTO op_idivb_AL_T0(void)
409 377  
410 378 num = (int16_t)EAX;
411 379 den = (int8_t)T0;
  380 + if (den == 0)
  381 + raise_exception(EXCP00_DIVZ);
412 382 q = (num / den) & 0xff;
413 383 r = (num % den) & 0xff;
414 384 EAX = (EAX & 0xffff0000) | (r << 8) | q;
... ... @@ -420,6 +390,8 @@ void OPPROTO op_divw_AX_T0(void)
420 390  
421 391 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
422 392 den = (T0 & 0xffff);
  393 + if (den == 0)
  394 + raise_exception(EXCP00_DIVZ);
423 395 q = (num / den) & 0xffff;
424 396 r = (num % den) & 0xffff;
425 397 EAX = (EAX & 0xffff0000) | q;
... ... @@ -432,6 +404,8 @@ void OPPROTO op_idivw_AX_T0(void)
432 404  
433 405 num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
434 406 den = (int16_t)T0;
  407 + if (den == 0)
  408 + raise_exception(EXCP00_DIVZ);
435 409 q = (num / den) & 0xffff;
436 410 r = (num % den) & 0xffff;
437 411 EAX = (EAX & 0xffff0000) | q;
... ... @@ -445,6 +419,8 @@ void OPPROTO op_divl_EAX_T0(void)
445 419  
446 420 num = EAX | ((uint64_t)EDX << 32);
447 421 den = T0;
  422 + if (den == 0)
  423 + raise_exception(EXCP00_DIVZ);
448 424 q = (num / den);
449 425 r = (num % den);
450 426 EAX = q;
... ... @@ -458,6 +434,8 @@ void OPPROTO op_idivl_EAX_T0(void)
458 434  
459 435 num = EAX | ((uint64_t)EDX << 32);
460 436 den = T0;
  437 + if (den == 0)
  438 + raise_exception(EXCP00_DIVZ);
461 439 q = (num / den);
462 440 r = (num % den);
463 441 EAX = q;
... ...
syscall-i386.h
... ... @@ -359,7 +359,7 @@ struct target_sigaction {
359 359  
360 360 typedef union target_sigval {
361 361 int sival_int;
362   - void *sival_ptr;
  362 + target_ulong sival_ptr;
363 363 } target_sigval_t;
364 364  
365 365 #define TARGET_SI_MAX_SIZE 128
... ... @@ -389,7 +389,7 @@ typedef struct target_siginfo {
389 389 struct {
390 390 pid_t _pid; /* sender's pid */
391 391 uid_t _uid; /* sender's uid */
392   - sigval_t _sigval;
  392 + target_sigval_t _sigval;
393 393 } _rt;
394 394  
395 395 /* SIGCHLD */
... ... @@ -403,7 +403,7 @@ typedef struct target_siginfo {
403 403  
404 404 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
405 405 struct {
406   - void *_addr; /* faulting insn/memory ref. */
  406 + target_ulong _addr; /* faulting insn/memory ref. */
407 407 } _sigfault;
408 408  
409 409 /* SIGPOLL */
... ... @@ -414,6 +414,46 @@ typedef struct target_siginfo {
414 414 } _sifields;
415 415 } target_siginfo_t;
416 416  
  417 +/*
  418 + * SIGILL si_codes
  419 + */
  420 +#define TARGET_ILL_ILLOPN (2) /* illegal operand */
  421 +
  422 +/*
  423 + * SIGFPE si_codes
  424 + */
  425 +#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
  426 +#define TARGET_FPE_INTOVF (2) /* integer overflow */
  427 +#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
  428 +#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
  429 +#define TARGET_FPE_FLTUND (5) /* floating point underflow */
  430 +#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
  431 +#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
  432 +#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
  433 +#define TARGET_NSIGFPE 8
  434 +
  435 +/* default linux values for the selectors */
  436 +#define __USER_CS (0x23)
  437 +#define __USER_DS (0x2B)
  438 +
  439 +struct target_pt_regs {
  440 + long ebx;
  441 + long ecx;
  442 + long edx;
  443 + long esi;
  444 + long edi;
  445 + long ebp;
  446 + long eax;
  447 + int xds;
  448 + int xes;
  449 + long orig_eax;
  450 + long eip;
  451 + int xcs;
  452 + long eflags;
  453 + long esp;
  454 + int xss;
  455 +};
  456 +
417 457 /* ioctls */
418 458  
419 459 /*
... ...
tests/testsig.c
  1 +#define _GNU_SOURCE
1 2 #include <stdlib.h>
2 3 #include <stdio.h>
  4 +#include <string.h>
3 5 #include <signal.h>
4 6 #include <unistd.h>
  7 +#include <setjmp.h>
  8 +#include <sys/ucontext.h>
  9 +
  10 +jmp_buf jmp_env;
5 11  
6 12 void alarm_handler(int sig)
7 13 {
... ... @@ -9,15 +15,82 @@ void alarm_handler(int sig)
9 15 alarm(1);
10 16 }
11 17  
  18 +void dump_regs(struct ucontext *uc)
  19 +{
  20 + printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
  21 + "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
  22 + "EFL=%08x EIP=%08x\n",
  23 + uc->uc_mcontext.gregs[EAX],
  24 + uc->uc_mcontext.gregs[EBX],
  25 + uc->uc_mcontext.gregs[ECX],
  26 + uc->uc_mcontext.gregs[EDX],
  27 + uc->uc_mcontext.gregs[ESI],
  28 + uc->uc_mcontext.gregs[EDI],
  29 + uc->uc_mcontext.gregs[EBP],
  30 + uc->uc_mcontext.gregs[ESP],
  31 + uc->uc_mcontext.gregs[EFL],
  32 + uc->uc_mcontext.gregs[EIP]);
  33 +}
  34 +
  35 +void sig_handler(int sig, siginfo_t *info, void *puc)
  36 +{
  37 + struct ucontext *uc = puc;
  38 +
  39 + printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n",
  40 + strsignal(info->si_signo),
  41 + info->si_signo, info->si_errno, info->si_code,
  42 + (unsigned long)info->si_addr);
  43 + dump_regs(uc);
  44 + longjmp(jmp_env, 1);
  45 +}
  46 +
  47 +int v1;
  48 +
12 49 int main(int argc, char **argv)
13 50 {
14 51 struct sigaction act;
  52 + int i;
  53 +
  54 + /* test division by zero reporting */
  55 + if (setjmp(jmp_env) == 0) {
  56 + act.sa_sigaction = sig_handler;
  57 + sigemptyset(&act.sa_mask);
  58 + act.sa_flags = SA_SIGINFO | SA_ONESHOT;
  59 + sigaction(SIGFPE, &act, NULL);
  60 +
  61 + /* now divide by zero */
  62 + v1 = 0;
  63 + v1 = 2 / v1;
  64 + }
  65 +
  66 + /* test illegal instruction reporting */
  67 + if (setjmp(jmp_env) == 0) {
  68 + act.sa_sigaction = sig_handler;
  69 + sigemptyset(&act.sa_mask);
  70 + act.sa_flags = SA_SIGINFO | SA_ONESHOT;
  71 + sigaction(SIGILL, &act, NULL);
  72 +
  73 + /* now execute an invalid instruction */
  74 + asm volatile("ud2");
  75 + }
  76 +
  77 + /* test SEGV reporting */
  78 + if (setjmp(jmp_env) == 0) {
  79 + act.sa_sigaction = sig_handler;
  80 + sigemptyset(&act.sa_mask);
  81 + act.sa_flags = SA_SIGINFO | SA_ONESHOT;
  82 + sigaction(SIGSEGV, &act, NULL);
  83 +
  84 + /* now store in an invalid address */
  85 + *(char *)0x1234 = 1;
  86 + }
  87 +
15 88 act.sa_handler = alarm_handler;
16 89 sigemptyset(&act.sa_mask);
17 90 act.sa_flags = 0;
18 91 sigaction(SIGALRM, &act, NULL);
19 92 alarm(1);
20   - for(;;) {
  93 + for(i = 0;i < 2; i++) {
21 94 sleep(1);
22 95 }
23 96 return 0;
... ...
translate-i386.c
... ... @@ -22,6 +22,7 @@
22 22 #include <stdio.h>
23 23 #include <string.h>
24 24 #include <inttypes.h>
  25 +#include <signal.h>
25 26 #include <assert.h>
26 27  
27 28 #define DEBUG_DISAS
... ... @@ -3487,7 +3488,8 @@ static void dump_ops(const uint16_t *opc_buf)
3487 3488 static uint16_t gen_opc_buf[OPC_BUF_SIZE];
3488 3489 static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
3489 3490  
3490   -/* return the next pc */
  3491 +/* return non zero if the very first instruction is invalid so that
  3492 + the virtual CPU can trigger an exception. */
3491 3493 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3492 3494 int *gen_code_size_ptr,
3493 3495 uint8_t *pc_start, uint8_t *cs_base, int flags)
... ... @@ -3519,9 +3521,13 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
3519 3521 do {
3520 3522 ret = disas_insn(dc, pc_ptr);
3521 3523 if (ret == -1) {
3522   - fprintf(stderr, "unknown instruction at PC=0x%08lx B=%02x %02x %02x",
3523   - (long)pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]);
3524   - abort();
  3524 + /* we trigger an illegal instruction operation only if it
  3525 + is the first instruction. Otherwise, we simply stop
  3526 + generating the code just before it */
  3527 + if (pc_ptr == pc_start)
  3528 + return -1;
  3529 + else
  3530 + break;
3525 3531 }
3526 3532 pc_ptr = (void *)ret;
3527 3533 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end);
... ... @@ -3640,8 +3646,7 @@ CPUX86State *cpu_x86_init(void)
3640 3646 env->fptags[i] = 1;
3641 3647 env->fpuc = 0x37f;
3642 3648 /* flags setup */
3643   - env->cc_op = CC_OP_EFLAGS;
3644   - env->df = 1;
  3649 + env->eflags = 0;
3645 3650  
3646 3651 /* init various static tables */
3647 3652 if (!inited) {
... ...