summaryrefslogtreecommitdiff
path: root/tools/perf/scripts/python/stackcollapse.py
diff options
context:
space:
mode:
authorRamin Moussavi <ramin.moussavi@yacoub.de>2026-08-21 17:18:07 +0200
committerMichal Simek <michal.simek@amd.com>2026-09-01 13:50:37 +0200
commitda6829138a39fa3b9ec318ca54ff89af9d94d350 (patch)
tree2ab65efa4cd368071387c84976a760acdd0f6148 /tools/perf/scripts/python/stackcollapse.py
parentc5947d28c20955de897eeb98430f96db0494f7d7 (diff)
microblaze: don't clobber r3/r4 restored by rt_sigreturn
ret_from_trap begins by storing the system call return values r3 and r4 back into the saved user pt_regs. That is right for an ordinary system call, but sys_rt_sigreturn() returns through the same path and has to be transparent: restore_sigcontext() has just filled pt_regs from the signal frame, and every register must reach userspace exactly as saved. The two stores overwrite the restored r3/r4 with whatever the C function left in those registers. Only r4 is actually lost, and that follows from how sigreturn is written everywhere rather than from chance. Architectures have sys_rt_sigreturn() return the restored return-value register precisely so that this writeback stores the restored value -- arm returns regs->ARM_r0, riscv and csky regs->a0, arc regs->r0 -- and microblaze does the same through *rval_p = regs->r3 in restore_sigcontext(). But the entry macros treat r3 and r4 as a pair, so ret_from_trap writes back two registers while a C function has only one return value; nothing carries the restored r4. Commit 791d0a169b91 ("microblaze: Fix sys_rt_sigreturn_wrapper") introduced this in v2.6.37. The old wrapper saved r3/r4 before the call and reloaded them from pt_regs afterwards; switching brlid to brid removed the only point where they were reloaded, and the stores have been overwriting them ever since. Fix it the way the sibling paths already behave: ret_from_irq and ret_from_exc restore the full register set and do not perform these stores at all. Label the instruction after the stores ret_from_trap_no_rval and enter there, biasing r15 by -8 so that the ABI return "rtsd r15, 8" lands on it; naming the entry rather than computing ret_from_trap + 8 keeps it correct if the number of stores ever changes. Restoring the old save/reload would work too, but costs four memory accesses and a branch to undo damage that is better not done. Any value the compiler keeps in r4 across a signal is lost. The tightest windows are the lwx/swx compare-and-swap retry loops gcc emits for atomics: in uClibc-ng's libc.so alone, 50 of 364 such loops hold the address in r4. This is not specific to one libc -- musl passes the address as "r"(p), and glibc has no microblaze atomic-machine.h and so uses gcc's __atomic builtins, which expand the same way. Triggering it needs threads plus a signal storm, which is why it survived 15 years. Reproduced on qemu-system-microblazeel (petalogix-s3adsp1800) by running the uClibc-ng NPTL test tst-eintr1 40 times against an unchanged userspace: on v7.2 built with gcc 16.2.0, 23 of 40 iterations died with SIGSEGV without this patch and 0 of 40 with it; on v7.0 built with gcc 12.5.0 the same comparison gave 6 of 40 against 0 of 40. The register dump of a failing iteration shows the signature: a zero r4 and a fault at address 0, while r3 came back intact. Fixes: 791d0a169b91 ("microblaze: Fix sys_rt_sigreturn_wrapper") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-5 Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de> Tested-by: Waldemar Brodkorb <wbx@openadk.org> Link: https://patch.msgid.link/20260821151809.1233057-4-ramin.moussavi@yacoub.de Signed-off-by: Michal Simek <michal.simek@amd.com>
Diffstat (limited to 'tools/perf/scripts/python/stackcollapse.py')
0 files changed, 0 insertions, 0 deletions