problem with user trap handlers in -CURRENT
Michiel Boland
michiel at boland.org
Mon Aug 13 17:50:03 UTC 2007
Hi. First, I would like to point out that I'm not at all an expert on
sparc64, so please excuse me if I express myself a bit awkwardly.
Now the problem.
As you may or may not know, -CURRENT on sparc64 is broken in the sense
that you can no longer ssh into a box that has
UsePrivilegeSeparation yes
in sshd_config.
For more details, see
http://lists.freebsd.org/pipermail/freebsd-current/2007-July/074569.html
and
http://lists.freebsd.org/pipermail/freebsd-current/2007-August/075996.html
At the root of all this lies what I think is a fundamental problem with
the way that alignment traps are handled.
Attached you will find (unless the list software decides to eat it) a
program that demonstrates what I mean. It creates a deliberate unaligned
access trap. The idea is that the trap handler then emulates
the load/store in software. This is done in __unaligned_fixup in
src/lib/libc/sparc64/sys/__sparc_utrap_align.c.
Unfortunately this emulation will not work if the trap is taken in the
delay slot right after a return instruction, and the faulting address is
on the stack of the procedure from which the processor just returned. This
is because the contents of the stack are overwritten with a trap frame, at
which point the emulation code will store an erroneous value.
This is why the attached program outputs
expected 37, got 0
instead of nothing, which it should do.
(Surprise your friends: link traptest statically. It will then print a
different value each time it is run. :)
The assembler code generated by gcc looks like
o2:
save %sp, -208, %sp
add %fp, 2019, %l0
add %l0, %i0, %l0
add %fp, 2027, %o0
call o3, 0
mov %l0, %o1
ldsb [%fp+2027], %g1
cmp %g1, 0
add %fp, 2019, %g1
movne %icc, %l0, %g1
return %i7+8
ldsw [%g1], %o0 <----- trap is taken here
^^^^^
this location will be overwritten by the trap frame
I'm not sure how to work around this. I guess one solution would be to
tell gcc not to generate these kinds of instruction combinations.
But also I am wondering why FreeBSD attempts to emulate unaligned loads
and stores in the first place. If I run traptest on Solaris, it crashes
immediately with SIGBUS. I would have guessed it would do the same on
FreeBSD. So I was a bit surprised that it ran at all.
Is it not easier to just not handle unaligned traps at all and simply let
programs crash? Or did someone already try this in the past, and too many
things broke after that?
Also I would assume that if you enforce that all memory access be aligned,
and hence cut out all the (slow) emulation, you get at least a theoretical
spead increase.
Cheers
Michiel
-------------- next part --------------
#include <stdio.h>
#ifndef MAGIC_NUMBER
#define MAGIC_NUMBER 37
#endif
int o2(int);
int main()
{
int i = o2(1);
if (i != MAGIC_NUMBER) {
fprintf(stderr, "expected %d, got %d\n", MAGIC_NUMBER, i);
return 1;
}
return 0;
}
void o3(char *, char *);
int o2(int offset)
{
int *p;
char c[4];
char tmp[8];
/*
* o3 will store the magic number in *(tmp + offset)
*/
o3(c, tmp + offset);
/*
* o3 will also make c[0] nozero, so we should always
* return *(tmp + offset), that is, the magic number.
* This construction is just a trick to make gcc
* emit the correct assembler statements.
*/
p = c[0] ? (int *) (tmp + offset) : (int *) tmp;
return *p;
}
void o3(char *cp, char *s)
{
int *ip = (int *) s;
*cp = 1;
*ip = MAGIC_NUMBER;
}
More information about the freebsd-sparc64
mailing list