libsanitizer: arm/ucontext: fix VFP save/restore to use uc_regspace area
The ARM {get,set}context implementations were imported from glibc in
2013 (commit a8dc90eaa, uClibc patch series "libc: add
{get,set,swap,make}context to ARM", see
https://lists.uclibc.org/pipermail/uclibc/2013-January/047400.html).
At that time glibc's own getcontext.S / setcontext.S also lacked the
`add r0, r4, #UCONTEXT_REGSPACE` (resp. `add r0, r0, #UCONTEXT_REGSPACE`)
instruction. glibc later added it -- current master has it, see
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/arm/getcontext.S
https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/arm/setcontext.S
-- but uClibc-ng never picked up the fix.
Without that instruction:
* in __getcontext, r0 is clobbered by the preceding `bl sigprocmask`
call (so r0 == sigprocmask's return value, typically 0). The next
instruction `stc p11, cr8, [r0], #64` then writes 64 bytes of VFP
state to address 0 - SIGSEGV.
* in __setcontext, r0 still points at the start of `ucontext_t`
(i.e. uc_flags), so `ldc p11, cr8, [r0], #64` loads 64 bytes of
garbage (uc_flags + uc_link + uc_stack + start of uc_mcontext) into
d8-d15, then the next 4 bytes are interpreted as fpscr - leaving
the FPU in an undefined state on every setcontext().
The bug is invisible on soft-float builds: the VFP and iWMMXt save
blocks are gated by compile-time `__VFP_FP__` / `__IWMMXT__` defines,
so on a soft-float toolchain (no VFP, no iWMMXt) the entire block
compiles out and r0 is simply unused after sigprocmask. The bug only
surfaces once VFP or iWMMXt is enabled.
This is reproducible on cortex-a5 (and any other VFP target) with
gcc.dg/asan/c-c++-common/asan/swapcontext-test-1.c from the GCC
testsuite, which crashes inside /lib/libc.so.0 with
AddressSanitizer: SEGV on unknown address 0x00000000
The signal is caused by a WRITE memory access.
#0 0xb67a25c0 (/lib/libc.so.0+0x115c0)
where 0x115c0 lands exactly on the `stc p11, cr8, [r0], #64` in
__getcontext.
Fix: restore the missing `add r0, r4, #UCONTEXT_REGSPACE` /
`add r0, r0, #UCONTEXT_REGSPACE` instruction in both files so that r0
points at uc_regspace[] (the dedicated VFP/iWMMXt save area at the end
of ucontext_t, see <sys/ucontext.h>: `unsigned long uc_regspace[128]
__attribute__((__aligned__(8)));`).
This matches what glibc does today and is the minimum invasive fix.
The HWCAP runtime-detection that current glibc adds on top is not
strictly necessary here because uClibc-ng's ucontext code is already
gated by compile-time `__VFP_FP__` / `__IWMMXT__` defines.
Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>