This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: {make,set,swap}context broken on powerpc32
On Wed, Dec 13, 2006 at 01:43:31PM +1100, Paul Mackerras wrote:
> I find it hard to see how that could be happening, because the kernel
> code explicitly preserves r2. In arch/powerpc/kernel/signal_32.c,
> sys_swapcontext calls do_setcontext with `sig' == 0, which calls
> restore_user_regs with the same `sig' argument, which then does this:
>
> /*
> * restore general registers but not including MSR or SOFTE. Also
> * take care of keeping r2 (TLS) intact if not a signal
> */
> if (!sig)
> save_r2 = (unsigned int)regs->gpr[2];
> err = restore_general_regs(regs, sr);
> err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
> if (!sig)
> regs->gpr[2] = (unsigned long) save_r2;
>
> The 64-bit sys_swapcontext (in signal_64.c) similarly avoids modifying
> r13, using a slightly different mechanism.
>
> That's assuming that glibc is in fact using the sys_swapcontext system
> call. If it's using sys_rt_sigreturn instead, then yes that will
> restore r2 from the saved registers.
>
> Could you strace your test program and see whether it is using
> sys_swapcontext or sys_rt_sigreturn?
It uses sys_swapcontext to fill it up (i.e. in getcontext calls)
and apparently sys_rt_sigreturn in setcontext (sorry I haven't noticed that),
will look why:
strace /tmp/e2
execve("/tmp/e2", ["/tmp/e2"], [/* 26 vars */]) = 0
brk(0) = 0x10020000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=135453, ...}) = 0
mmap(NULL, 135453, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7fc0000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\24\0\0\0\1\17H\340"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1793784, ...}) = 0
mmap(0xf470000, 1520028, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf470000
mmap(0xf5d0000, 131072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x160000) = 0xf5d0000
close(3) = 0
mprotect(0xf5d0000, 65536, PROT_READ) = 0
mprotect(0xffe0000, 65536, PROT_READ) = 0
munmap(0xf7fc0000, 135453) = 0
swapcontext(0x1001319c, 0) = 0
swapcontext(0x10010cfc, 0) = 0
rt_sigreturn(0x10010cfc) = 78
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
uc_mcontext.uc_regs pointer the swapcontext call creates is not
aligned though:
p ucp
$1 = {uc_flags = 0, uc_link = 0x0, uc_stack = {ss_sp = 0x0, ss_flags = 0, ss_size = 0}, uc_pad = {0, 0, 0, 0, 0, 0, 0},
uc_mcontext = {regs = 0x10010dbc, uc_regs = 0x10010dbc}, uc_sigmask = {__val = {0 <repeats 32 times>}},
uc_reg_space = ... }
and makecontext realigns it:
$2 = {uc_flags = 0, uc_link = 0x1001319c, uc_stack = {ss_sp = 0x1001119c, ss_flags = 0, ss_size = 8192}, uc_pad = {0, 0, 0, 0, 0, 0, 0},
uc_mcontext = {regs = 0x10010db0, uc_regs = 0x10010db0}, uc_sigmask = {__val = {0 <repeats 32 times>}},
uc_reg_space = ... }
thus loosing content of all registers from getcontext except those which it
explicitly overrode.
Jakub