i386-linux-user returns -1 in sigcontext->trapno
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
QEMU |
Expired
|
Undecided
|
Unassigned |
Bug Description
QEMU development version, git commit 74208cd252c5da9
Certain 16-bit windows programs crash WINE under QEMU linux-user with:
0084:err:
wine: Unhandled illegal instruction at address 00006D65 (thread 0084), starting debugger...
They run correctly on native i386.
Upon further inspection,it becomes clear these programs are failing at addresses where they are making DOS calls (int 21h ie CD 21 for instance).
It is also clear that WINE is expecting an exception/signal at this point, to patch in the actual int21h handling code inside WINE.
However, wine uses sigcontext output extensively to do its structured exception handling. sigcontext->trapno being set to -1 seems to confuse it, causing it to treat the exception as an actual unhandled error.
I do not know if exception_index is being left at -1 due to the case of privileged instructions being executed in 16-bit ldts not being handled specifically, or if there is some other illegal instruction case causing this.
I have identified the core issue:
Synchronous exceptions/traps in linux-user/ i386/cpu_ loop.c are handled as a return value from cpu_exec(). exception( )
cpu_exec() resets exception_index to -1 in cpu_handle_
This means that queue_signal() (called from gen_signal() in the cpu loop) does not store the actual CPU trap value anywhere.
If we abuse env->exception_nr to store the trapnr, and retrieve it from there in setup_sigcontext() in linux-user/ i386/signal. c instead of using exception_index (which will be set to -1 for all synchronous excptions).
The main issue is if this breaks asynchronous signals, and under what conditions exception_nr should be set to -1.