Commit 9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966
1 parent
66fb9763
better signal/exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@42 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
15 changed files
with
642 additions
and
206 deletions
TODO
| 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) { | ... | ... |