Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Sep 1999 14:18:21 +0200 (MET DST)
From:      Ulrich Weigand <weigand@informatik.uni-erlangen.de>
To:        nox@jelal.kn-bremen.de, wine-devel@winehq.com, luoqi@watermarkgroup.com
Cc:        freebsd-emulation@FreeBSD.ORG
Subject:   Re:  wine signal handlers lose %fs on FreeBSD
Message-ID:  <199909021218.OAA21251@faui11.informatik.uni-erlangen.de>

next in thread | raw e-mail | index | archive | help

Luoqi Chen <luoqi@watermarkgroup.com> wrote:

> > Here's a strange one:  Sometimes apparently wine's signal handlers receive
> > %fs messed up (zeroed actually) and therefore crash/hang on FreeBSD
> > (3.2-stable, wine current-cvs).  Patch this and watch for
> > `warn:seh:EXC_SaveContext teb=0xsomewhere teb_sel=something, fs=0, gs=foo'
> > messages, teb_sel is what fs really should have been (and what is loaded
> > back there after the message, so the program actually continues too.)

Well, this problem would seem to be caused by Wine.  The problem is
that while any Wine signal handler is running, %fs needs to be loaded
with the value %fs had in the code that was interrupted by the signal
*if that code is 32-bit*.  If *16-bit* code was interrupted, however,
%fs needs to be loaded with the value had at the time the switch from
32-bit to 16-bit took place (this value was saved at the time) ...

The reason for this is that Wine, like 32-bit Windows, uses the %fs
register to identify the current thread.  On 16-bit Windows, however,
%fs has no special meaning and is freely used by apps ...

To achieve this, Wine calls a macro HANDLER_INIT() at the start of
every signal handler which is supposed to set %fs correctly. This is
defined as follows:

#ifdef FS_sig
#include "syslevel.h"
#define HANDLER_INIT() \
    do { int fs = IS_SELECTOR_SYSTEM(CS_sig(HANDLER_CONTEXT)) ?       \
                  FS_sig(HANDLER_CONTEXT) : SYSLEVEL_Win16CurrentTeb; \
         if (!fs) fs = SYSLEVEL_EmergencyTeb;                         \
         SET_FS(fs);                           } while (0)
#else
#define HANDLER_INIT() /* nothing */
#endif

The problem is that the second case (which is active only if FS_sig
is undefined, meaning that the sigcontext structure doesn't contain
the %fs value, like on FreeBSD) is clearly wrong.  Try changing this to

#define HANDLER_INIT() \
    do { int fs; GET_FS(fs); fs &= 0xffff;                      \
         if (!IS_SELECTOR_SYSTEM(CS_sig(HANDLER_CONTEXT)))      \
             fs = SYSLEVEL_Win16CurrentTeb;                     \
         if (!fs) fs = SYSLEVEL_EmergencyTeb;                   \
         SET_FS(fs);                          } while (0)       \


> The kernel sets %fs to 0 during a context switch if it triggers a fault
> (protection fault or segment not present) and signals SIGBUS. Most likely
> the EXC_segv in your previous email is this signal. Unfortunately there
> is no easy way to know which %fs value is causing the fault (probably you
> could add a kernel printf, in file sys/i386/i386/trap.c, search for
> cpu_switch_load_fs).

This is probably not a problem for Wine.  If I understand it correctly,
this should trigger only if a 16-bit app running under Wine loads %fs
with a selector that becomes invalid while still loaded (and on next
context switch to that thread, the fault happens).  In this case the
app is broken anyway and the only thing Wine will want to do in the handler
is to run the built-in debugger; for this the EmergencyTeb is enough ...


> I took a brief look at the exception code, it probably would not work
> under 4.0-current because the kernel uses %fs and signal handlers are
> called with a default %fs value (the same as the default %ds). You might
> need to restore %fs from the value in sigcontext at beginning of your
> signal handlers (yes, fs in sigcontext is set for 4.0-current. Regarding
> this, we could change the kernel, both -current and -stable, so that fs/gs
> are always saved in sigcontext when the signal is delivered, and restored
> during the signal trampoline, hence a consistent interface to application
> authors). Alternatively, we could change the kernel to call signal handlers
> with the original fs.

Well, Wine can work with both ways, as long as there is way to find
out what method the OS uses!  What should we use as a check?

Bye,
Ulrich


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-emulation" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199909021218.OAA21251>