[RFC]: try two MD_FALLBACK_FRAME_STATE_FOR macro for darwin PPC

Geoff Keating geoffk@geoffk.org
Fri Feb 20 22:10:00 GMT 2004


Andreas Tobler <toa@pop.agri.ch> writes:

> Dale Johannesen wrote:
> 
> > Saved regs are described in rs6000.h of course.
> > Floats are F14-F31 and I think you may need CR also, some of its
> > subregs are caller-saved.
> > And then there's Altivec, V20-V31 and VRSAVE.  They don't exist on
> > all machines though!
> 
> Ok here a next try, some more saves.
> 
> I managed to pass the cleanup-[8-11].c with some modifications too.
> 
> The modifications I had to do are on the tests itself.
> 
> #ifndef SA_ONESHOT
> #define SA_ONESHOT SA_RESETHAND
> #endif
> 
> Because darwin does not know SA_ONESHOT.
> 
> And the signal handler itself has to be loaded with a SIGBUS since
> this is emitted when a EXC_BAD_ACCESS happens on darwin.
> 
> The macro itself does only work with 32 bit CPU's, not with G5, as
> Andrew pointed out. I think a 64bit macro should be possible after I
> completed this one?
> 
> I have to do some further test if the regs are saved correctly,
> especially the altivec ones. For now in my test apps they don't get
> saved. Either I don't need them or my mechanics to check whether to
> save or not does not work.
> 
> Any further comments?

OK, so perhaps I should explain how this whole thing should work.

You're writing a macro that hooks into the exception-throwing code.
Its job is to take the system's signal return code, which (at least on
Panther) doesn't have any exception table information, and basically
emulate that information.

So, what happens when you throw a signal on Panther?  Well, because
this is Mach, it doesn't work quite like on, say, Linux.  What really
happens when a signal is thrown is that a routine called sigtramp() is
called, which you can find in sys/sigtramp.c in Libc (which should be
available somewhere in Apple's open source repository, you want
Libc-320 for the version used on Panther); its job is to call the
user's signal handler, and then call the sigreturn system call.

In principle, this code looks like:

  sa_handler(sig);
  sigreturn(uctx);

which would be only a handful of instructions.  In practise, however,
the code is *much* more complicated than this.  One big complication
with the current code is that it has to restore 64-bit registers, but
must not break existing code that believes that the signal context
holds 32-bit registers and which might have changed those registers
expecting them to be changed in the caller.  Another complication is
that there's two ways of installing signal handlers, and the
user-level signal handlers take slightly different parameter lists
depending on how you install them, depending on the setting of the
SA_SIGINFO flag.

So, the macro needs to:

1. Determine that you actually are in sigtramp().
2. Determine where the user context is.
3. Restore the registers from the user context.

(3) you have, although I think it might help if you wrote an assembler
test program that sets up all registers with known values, then causes
a signal, then changes the value of every variable in the signal
handler, then throws an exception, then checks that all the registers
have been restored.  I'm suspicious of the CR-restoring code, in particular.

(2) you're doing by assuming that sigtramp() has a stack frame of a
particular size, and that the kernel always puts the signal context
right above sigtramp()'s stack frame.  This will work, but it's a
fragile assumption: it relies on the particular assembly code in
sigtramp(), and on the kernel version.  In addition, it turns out that
on 64-bit CPUs there are two different styles of context, both of
which exist at the same time, and you want to pick the one that would
have been restored.  This complicates things somewhat.  As an initial
pass, I suggest doing what you do now, which is restore the 32-bit
context, but find it by looking at where sigtramp puts it: in r29.
(FYI, the 64-bit context immediately follows the 32-bit context.)
That will remove the kernel dependency, which is important since the
kernel changes more often than libSystem and is more expensive to check.

[I found out that it was r29 by running 'otool -vt' on
/usr/lib/libSystem.dylib, and noticing the instruction

900251bc        or      r4,r29,r29

which is passing the address of the context to the sigreturn system call.]

For (1), the only thing you can really do is look at the entire
machine code sequence from the point at which the user's signal
handler would return, right up to the point where the sigreturn system
call happens, which is this instruction:

900251e8        b       0x900fb6c4

You especially want to check the 900251bc instruction, which involves
checking a much longer sequence than your patch does.  I suggest, to
avoid copying a large sequence of libSystem.dylib into the compiler
and possibly having copyright troubles, that you use a checksum of the
sequence.  You also need to allow for the two possible locations that
the user's signal handler is called from, so you need to allow for a
return location:

90025140        mtspr   ctr,r12
90025144        bctrl
>>>>>>>>>> here,
90025148        b       0x90025158
9002514c        or      r5,r7,r7
90025150        mtspr   ctr,r12
90025154        bctrl
>>>>>>>>>> or here.
90025158        cmpwi   cr4,r30,0x32

I think your code does do that, although with a misleading comment

+	/* If the signal handler did not skip the faulting instruction	\
+	   we will do.  */						\

-- 
- Geoffrey Keating <geoffk@geoffk.org>



More information about the Gcc-patches mailing list