diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp --- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp @@ -76,6 +76,24 @@ Fuzzer::StaticInterruptCallback(); } +// cfa_offset is used to reference the stack pointer before entering the +// trampoline (Stack Pointer - cfa_offset = prev Stack Pointer). Before jumping +// to the trampoline we copy all the registers onto the stack. We need to make +// sure that the new stack has enough space to store all the registers. +// +// The trampoline holds cfi information regarding the registers stored in the +// stack, which is then used by the unwinder to restore them. +#if defined(__x86_64__) +// In x86_64 the crashing function might also be using the red zone (128 bytes +// on top of their rsp). +constexpr size_t cfa_offset = 128 + sizeof(zx_thread_state_general_regs_t); +#elif defined(__aarch64__) +// In arm64 we need to always have the stack pointer aligned to 16 bytes, so we +// make sure that we are keeping that same alignment. +constexpr size_t cfa_offset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16; +#else +#error "Unsupported architecture for fuzzing on Fuchsia" +#endif // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback // without POSIX signal handlers. To achieve this, we use an assembly function // to add the necessary CFI unwinding information and a C function to bridge @@ -140,22 +158,22 @@ OP_NUM(27) \ OP_NUM(28) \ OP_NUM(29) \ - OP_NUM(30) \ OP_REG(sp) -#else -#error "Unsupported architecture for fuzzing on Fuchsia" #endif // Produces a CFI directive for the named or numbered register. +// The value used refers to an assembler immediate operand with the same name +// as the register (see ASM_OPERAND_REG). #define CFI_OFFSET_REG(reg) ".cfi_offset " #reg ", %c[" #reg "]\n" -#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(r##num) +#define CFI_OFFSET_NUM(num) CFI_OFFSET_REG(x##num) -// Produces an assembler input operand for the named or numbered register. +// Produces an assembler immediate operand for the named or numbered register. +// This operand contains the offset of the register relative to the cfa. #define ASM_OPERAND_REG(reg) \ - [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), + [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - cfa_offset), #define ASM_OPERAND_NUM(num) \ - [r##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), + [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - cfa_offset), // Trampoline to bridge from the assembly below to the static C++ crash // callback. @@ -168,7 +186,16 @@ } // Creates the trampoline with the necessary CFI information to unwind through -// to the crashing call stack. The attribute is necessary because the function +// to the crashing call stack: +// * Defining the CFA so that it points to the stack pointer at the point +// of crash. +// * Storing all registers at the point of crash in the stack and refer to them +// via cfi information (relative to the cfa). +// * Setting the return column so the unwinder knows how to continue unwinding. +// * (x86_64) making sure rsp is aligned before calling StaticCrashHandler. +// * Calling StaticCrashHandler that will trigger the unwinder. +// +// The __attribute__((used)) is necessary because the function // is never called; it's just a container around the assembly to allow it to // use operands for compile-time computed constants. __attribute__((used)) @@ -181,16 +208,21 @@ ".cfi_signal_frame\n" #if defined(__x86_64__) ".cfi_return_column rip\n" - ".cfi_def_cfa rsp, 0\n" + ".cfi_def_cfa rsp, %c[cfa_offset]\n" FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) + "mov %%rsp, %%rbp\n" + ".cfi_def_cfa_register rbp\n" + "andq $-16, %%rsp\n" "call %c[StaticCrashHandler]\n" "ud2\n" #elif defined(__aarch64__) ".cfi_return_column 33\n" - ".cfi_def_cfa sp, 0\n" - ".cfi_offset 33, %c[pc]\n" + ".cfi_def_cfa sp, %c[cfa_offset]\n" FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) - "bl %[StaticCrashHandler]\n" + ".cfi_offset 33, %c[pc]\n" + ".cfi_offset 30, %c[lr]\n" + "bl %c[StaticCrashHandler]\n" + "brk 1\n" #else #error "Unsupported architecture for fuzzing on Fuchsia" #endif @@ -202,8 +234,10 @@ : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) #if defined(__aarch64__) ASM_OPERAND_REG(pc) + ASM_OPERAND_REG(lr) #endif - [StaticCrashHandler] "i" (StaticCrashHandler)); + [StaticCrashHandler] "i" (StaticCrashHandler), + [cfa_offset] "i" (cfa_offset)); } void CrashHandler(zx_handle_t *Event) { @@ -269,17 +303,14 @@ // onto the stack and jump into a trampoline with CFI instructions on how // to restore it. #if defined(__x86_64__) - uintptr_t StackPtr = - (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & - -(uintptr_t)16; + uintptr_t StackPtr = GeneralRegisters.rsp - cfa_offset; __unsanitized_memcpy(reinterpret_cast(StackPtr), &GeneralRegisters, sizeof(GeneralRegisters)); GeneralRegisters.rsp = StackPtr; GeneralRegisters.rip = reinterpret_cast(CrashTrampolineAsm); #elif defined(__aarch64__) - uintptr_t StackPtr = - (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; + uintptr_t StackPtr = GeneralRegisters.sp - cfa_offset; __unsanitized_memcpy(reinterpret_cast(StackPtr), &GeneralRegisters, sizeof(GeneralRegisters)); GeneralRegisters.sp = StackPtr;