136 lines · plain
1// This is assembly code that needs to be run2// through the preprocessor, for simplicity of3// preprocessing it's named .c to start with.4//5// clang-format off6 7 8#define DW_CFA_register 0x99#define ehframe_x0 010#define ehframe_x20 2011#define ehframe_x22 2212#define ehframe_x23 2313#define ehframe_pc 3214 15#if defined(__APPLE__)16#define TO_BE_INTERRUPTED _to_be_interrupted17#define TRAP _trap18#define BREAK_TO_DEBUGGER _break_to_debugger19#else20#define TO_BE_INTERRUPTED to_be_interrupted21#define TRAP trap22#define BREAK_TO_DEBUGGER break_to_debugger23#endif24 25 .text26//--------------------------------------27// to_be_interrupted() a frameless function that does a non-ABI28// function call to trap(), simulating an async signal/interrup/exception/fault.29// Before it branches to trap(), put the return address in x23.30// trap() knows to branch back to $x23 when it has finished.31//--------------------------------------32 .globl TO_BE_INTERRUPTED33#if defined(__APPLE__)34 .p2align 235#endif36TO_BE_INTERRUPTED:37 .cfi_startproc38 39 // This is a garbage entry to ensure that eh_frame is emitted.40 // If there's no eh_frame, lldb can use the assembly emulation scan,41 // which always includes a rule for $lr, and we won't replicate the42 // bug we're testing for.43 .cfi_escape DW_CFA_register, ehframe_x22, ehframe_x2344 mov x24, x045 add x24, x24, #146 47#if defined(__APPLE__)48 adrp x23, L_.return@PAGE // put return address in x2349 add x23, x23, L_.return@PAGEOFF50#else51 adrp x23, .L.return52 add x23, x23, :lo12:.L.return53#endif54 55 b TRAP // branch to trap handler, fake async interrupt56 57#if defined(__APPLE__)58L_.return:59#else60.L.return:61#endif62 mov x0, x2463 ret64 .cfi_endproc65 66 67 68//--------------------------------------69// trap() trap handler function, sets up stack frame70// with special unwind rule for the pc value of the71// "interrupted" stack frame (it's in x23), then calls72// break_to_debugger().73//--------------------------------------74 .globl TRAP75#if defined(__APPLE__)76 .p2align 277#endif78TRAP:79 .cfi_startproc80 .cfi_signal_frame81 82 // The pc value when we were interrupted is in x2383 .cfi_escape DW_CFA_register, ehframe_pc, ehframe_x2384 85 // For fun, mark x0 as unmodified so the caller can86 // retrieve the value if it wants.87 .cfi_same_value ehframe_x088 89 // Mark x20 as undefined. This is a callee-preserved90 // (non-volatile) register by the SysV AArch64 ABI, but91 // it'll be fun to see lldb not passing a value past this92 // point on the stack.93 .cfi_undefined ehframe_x2094 95 // standard prologue save of fp & lr so we can call 96 // break_to_debugger()97 sub sp, sp, #3298 stp x29, x30, [sp, #16]99 add x29, sp, #16100 .cfi_def_cfa w29, 16101 .cfi_offset w30, -8102 .cfi_offset w29, -16103 104 bl BREAK_TO_DEBUGGER105 106 ldp x29, x30, [sp, #16]107 .cfi_same_value x29108 .cfi_same_value x30109 .cfi_def_cfa sp, 32110 add sp, sp, #32111 .cfi_same_value sp112 .cfi_def_cfa sp, 0113 114 // jump back to $x23 to resume execution of to_be_interrupted115 br x23116 .cfi_endproc117 118//--------------------------------------119// break_to_debugger() executes a BRK instruction120//--------------------------------------121 .globl BREAK_TO_DEBUGGER122#if defined(__APPLE__)123 .p2align 2124#endif125BREAK_TO_DEBUGGER:126 .cfi_startproc127 128 // For fun, mark x0 as unmodified so the caller can129 // retrieve the value if it wants.130 .cfi_same_value ehframe_x0131 132 brk #0xf000 // __builtin_debugtrap aarch64 instruction133 134 ret135 .cfi_endproc136