This adds a specific unwind plan for AArch64 Linux sigreturn frames. Previously we assumed that the fp would be valid here but it is not. https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S On Ubuntu Bionic it happened to point to an old frame info which meant you got what looked like a correct backtrace. On Focal, the info is completely invalid. (probably due to some code shuffling in libc) This adds an UnwindPlan that knows that the sp in a sigreturn frame points to an rt_sigframe from which we can offset to get saved sp and pc values to backtrace correctly. Based on LibUnwind's change: https://reviews.llvm.org/D90898 A new test is added that sets all compares the frames from the initial signal catch to the handler break. Ensuring that the stack/frame pointer, function name and register values match. (this test is AArch64 Linux specific because it's the only one with a specific unwind plan for this situation) Fixes https://bugs.llvm.org/show_bug.cgi?id=52165 Reviewed By: omjavaid, labath Differential Revision: https://reviews.llvm.org/D112069
65 lines
2.4 KiB
C
65 lines
2.4 KiB
C
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
void handler(int sig) {
|
|
// The kernel only changes a few registers so set them all to something other
|
|
// than the values in sigill() so that we can't fall back to real registers
|
|
// and still pass the test.
|
|
#define SETREG(N) "mov x" N ", #" N "+1\n\t"
|
|
asm volatile(
|
|
/* clang-format off */
|
|
/* x0 is used for a parameter */
|
|
SETREG("1") SETREG("2") SETREG("3")
|
|
SETREG("4") SETREG("5") SETREG("6") SETREG("7")
|
|
SETREG("8") SETREG("9") SETREG("10") SETREG("11")
|
|
SETREG("12") SETREG("13") SETREG("14") SETREG("15")
|
|
SETREG("16") SETREG("17") SETREG("18") SETREG("19")
|
|
SETREG("20") SETREG("21") SETREG("22") SETREG("23")
|
|
SETREG("24") SETREG("25") SETREG("26") SETREG("27")
|
|
SETREG("28") // fp/x29 needed for unwiding
|
|
SETREG("30") // 31 is xzr/sp
|
|
/* clang-format on */
|
|
::
|
|
: /* skipped x0 */ "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8",
|
|
"x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18",
|
|
"x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27",
|
|
"x28",
|
|
/* skipped fp/x29 */ "x30");
|
|
printf("Set a breakpoint here.\n");
|
|
exit(0);
|
|
}
|
|
|
|
static void sigill() {
|
|
// Set all general registers to known values to check
|
|
// that the signal unwind plan sets their locations correctly.
|
|
#define SETREG(N) "mov x" N ", #" N "\n\t"
|
|
asm volatile(
|
|
/* clang-format off */
|
|
SETREG("0") SETREG("1") SETREG("2") SETREG("3")
|
|
SETREG("4") SETREG("5") SETREG("6") SETREG("7")
|
|
SETREG("8") SETREG("9") SETREG("10") SETREG("11")
|
|
SETREG("12") SETREG("13") SETREG("14") SETREG("15")
|
|
SETREG("16") SETREG("17") SETREG("18") SETREG("19")
|
|
SETREG("20") SETREG("21") SETREG("22") SETREG("23")
|
|
SETREG("24") SETREG("25") SETREG("26") SETREG("27")
|
|
SETREG("28") SETREG("29") SETREG("30") /* 31 is xzr/sp */
|
|
/* clang-format on */
|
|
".inst 0x00000000\n\t" // udf #0 (old binutils don't support udf)
|
|
::
|
|
: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10",
|
|
"x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19",
|
|
"x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28",
|
|
"x29", "x30");
|
|
}
|
|
|
|
int main() {
|
|
if (signal(SIGILL, handler) == SIG_ERR) {
|
|
perror("signal");
|
|
return 1;
|
|
}
|
|
|
|
sigill();
|
|
return 2;
|
|
}
|