From: Mark W. <ma...@so...> - 2025-03-30 18:25:36
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=41441379baa63b5471385361d08c8df317705b69 commit 41441379baa63b5471385361d08c8df317705b69 Author: Mark Wielaard <ma...@kl...> Date: Sun Mar 30 17:38:21 2025 +0200 Handle top __syscall_cancel frames when getting stack traces Since glibc 2.41 there are extra frames inserted before doing a syscall to support proper thread cancellation. This breaks various suppressions and regtests involving checking syscall arguments. Solve this by removing those extra frames from the top of the call stack when we are processing a linux system call. https://bugs.kde.org/show_bug.cgi?id=502126 Diff: --- NEWS | 1 + coregrind/m_stacktrace.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 40b9539596..7145157f21 100644 --- a/NEWS +++ b/NEWS @@ -70,6 +70,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 501846 Add x86 Linux shm wrappers 501850 FreeBSD syscall arguments 7 and 8 incorrect. 501893 Missing suppression for __wcscat_avx2 (strcat-strlen-avx2.h.S:68)? +502126 glibc 2.41 extra syscall_cancel frames To see details of a given bug, visit https://bugs.kde.org/show_bug.cgi?id=XXXXXX diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index cbeaab9db1..21c0f47942 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -9,6 +9,8 @@ Copyright (C) 2000-2017 Julian Seward js...@ac... + Copyright (C) 2025 Mark J. Wielaard + ma...@kl... This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -1693,10 +1695,59 @@ UInt VG_(get_StackTrace_with_deltas)( tid, stack_highest_byte, startRegs.r_pc, startRegs.r_sp); - return VG_(get_StackTrace_wrk)(tid, ips, n_ips, + Int found = VG_(get_StackTrace_wrk)(tid, ips, n_ips, sps, fps, &startRegs, stack_highest_byte); + +#if defined(VGO_linux) + /* glibc might insert some extra frames before doing a syscall to support + thread cancellation. This breaks various suppressions and regtests + involving checking syscall arguments. So when processing a syscall just + remove those extra frames from the top of the call stack. */ + if (VG_(is_in_syscall)(tid)) { + Int i; + Int start = 0; + DiEpoch ep = VG_(current_DiEpoch)(); + for (i = 0; i < found; i++) { + /* This could be made a little more efficient by doing the lookups + for the symbols at glibc load time and check the address falls + inside the function symbol address range here. But given this + is only called during syscall processing, this is probably fine + for now. */ + const HChar *buf; + if (VG_(get_fnname_raw)(ep, ips[i], &buf)) { // raw, don't demangle + if (VG_STREQ("__syscall_cancel_arch", buf) || + VG_STREQ("__internal_syscall_cancel", buf) || +#if defined(VGP_x86_linux) || defined(VGP_arm_linux) + VG_STREQ("__libc_do_syscall", buf) || +#endif +#if defined(VGP_x86_linux) + VG_STREQ("_dl_sysinfo_int80", buf) || +#endif + VG_STREQ("__syscall_cancel", buf)) { + start++; + continue; // Maybe the next one is special too? + } else { + break; // Not special, only skip top stack names. + } + } else { + break; // No name, not special, don't skip. + } + } + + if (start > 0) { + for (i = 0; i < (found - start); i++) { + ips[i] = ips[i + start]; + if (sps) sps[i] = sps[i + start]; + if (fps) fps[i] = fps[i + start]; + } + return found - start; + } + } +#endif + + return found; } UInt VG_(get_StackTrace) ( ThreadId tid, |