// REQUIRES: asserts // // RUN: %clang %cflags -march=armv8.3-a %s -o %t.exe // RUN: llvm-bolt-binary-analysis --scanners=pacret -no-threads \ // RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck %s // RUN: llvm-bolt-binary-analysis --scanners=pauth -no-threads \ // RUN: -debug-only bolt-pauth-scanner %t.exe 2>&1 | FileCheck -check-prefixes=CHECK,PAUTH %s // Check the debug output generated by PAuth gadget scanner to make sure the // that output is kept meaningful and to provide an overview of what happens // inside the scanner. .globl simple .type simple,@function simple: paciasp stp x29, x30, [sp, #-0x10]! b 1f 1: autiza x0 blr x0 ldp x29, x30, [sp], #0x10 autiasp ret .size simple, .-simple // CHECK-LABEL:Analyzing function simple, AllocatorId = 1 // CHECK-NEXT: Binary Function "simple" { // CHECK-NEXT: Number : 1 // CHECK-NEXT: State : CFG constructed // ... // CHECK: BB Layout : [[BB0:[0-9a-zA-Z.]+]], [[BB1:[0-9a-zA-Z.]+]] // CHECK-NEXT: } // CHECK-NEXT: [[BB0]] (3 instructions, align : 1) // CHECK-NEXT: Entry Point // CHECK-NEXT: 00000000: paciasp // CHECK-NEXT: 00000004: stp x29, x30, [sp, #-0x10]! // CHECK-NEXT: 00000008: b [[BB1]] // CHECK-NEXT: Successors: [[BB1]] // CHECK-EMPTY: // CHECK-NEXT: [[BB1]] (5 instructions, align : 1) // CHECK-NEXT: Predecessors: [[BB0]] // CHECK-NEXT: 0000000c: autiza x0 // CHECK-NEXT: 00000010: blr x0 // CHECK-NEXT: 00000014: ldp x29, x30, [sp], #0x10 // CHECK-NEXT: 00000018: autiasp // CHECK-NEXT: 0000001c: ret // CHECK-EMPTY: // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "simple" // CHECK-EMPTY: // CHECK-NEXT: Running src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #25, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( stp x29, x30, [sp, #-0x10]!, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( b [[BB1]], src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: DataflowSrcSafetyAnalysis::Confluence( // CHECK-NEXT: State 1: src-state // CHECK-NEXT: State 2: src-state) // CHECK-NEXT: merged state: src-state // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: DataflowSrcSafetyAnalysis::Confluence( // CHECK-NEXT: State 1: src-state // CHECK-NEXT: State 2: src-state) // CHECK-NEXT: merged state: src-state // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( autiza x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( blr x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ldp x29, x30, [sp], #0x10, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( hint #29, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After src register safety analysis: // CHECK-NEXT: Binary Function "simple" { // CHECK-NEXT: Number : 1 // CHECK-NEXT: State : CFG constructed // ... // CHECK: BB Layout : [[BB0]], [[BB1]] // CHECK-NEXT: } // CHECK-NEXT: [[BB0]] (3 instructions, align : 1) // CHECK-NEXT: Entry Point // CHECK-NEXT: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000004: stp x29, x30, [sp, #-0x10]! # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000008: b [[BB1]] # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: Successors: [[BB1]] // CHECK-EMPTY: // CHECK-NEXT: [[BB1]] (5 instructions, align : 1) // CHECK-NEXT: Predecessors: [[BB0]] // CHECK-NEXT: 0000000c: autiza x0 # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000010: blr x0 # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000014: ldp x29, x30, [sp], #0x10 # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000018: autiasp # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: 0000001c: ret # DataflowSrcSafetyAnalysis: src-state // CHECK-EMPTY: // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "simple" // CHECK-EMPTY: // PAUTH-NEXT: Found sign inst: 00000000: paciasp # DataflowSrcSafetyAnalysis: src-state // PAUTH-NEXT: Signed reg: LR // PAUTH-NEXT: TrustedRegs: LR W30 W30_HI{{[ \t]*$}} // PAUTH-NEXT: Found call inst: 00000000: blr x0 # DataflowSrcSafetyAnalysis: src-state // PAUTH-NEXT: Call destination reg: X0 // PAUTH-NEXT: SafeToDerefRegs: W0 X0 W0_HI{{[ \t]*$}} // CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: RetReg: LR // CHECK-NEXT: SafeToDerefRegs: LR W30 W30_HI{{[ \t]*$}} .globl clobber .type clobber,@function clobber: mov w30, #0 ret .size clobber, .-clobber // CHECK-LABEL:Analyzing function clobber, AllocatorId = 1 // ... // CHECK: Running src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After src register safety analysis: // CHECK-NEXT: Binary Function "clobber" { // ... // CHECK: End of Function "clobber" // The above output was printed after first run of analysis // CHECK-EMPTY: // CHECK-NEXT: Found RET inst: 00000000: ret # DataflowSrcSafetyAnalysis: src-state // CHECK-NEXT: RetReg: LR // CHECK-NEXT: SafeToDerefRegs: W30_HI{{[ \t]*$}} // CHECK-EMPTY: // CHECK-NEXT: Running detailed src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( mov w30, #0x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After detailed src register safety analysis: // CHECK-NEXT: Binary Function "clobber" { // ... // CHECK: End of Function "clobber" // The analysis was re-computed with register tracking, as an issue was found in this function. // Iterating over the reports and attaching clobbering info: // CHECK-EMPTY: // CHECK-NEXT: Attaching clobbering info to: 00000000: ret # DataflowSrcSafetyAnalysis: src-state .globl nocfg .type nocfg,@function nocfg: adr x0, 1f br x0 1: ret .size nocfg, .-nocfg // CHECK-LABEL:Analyzing function nocfg, AllocatorId = 1 // CHECK-NEXT: Binary Function "nocfg" { // CHECK-NEXT: Number : 3 // CHECK-NEXT: State : disassembled // ... // CHECK: IsSimple : 0 // CHECK-NEXT: IsMultiEntry: 1 // CHECK-NEXT: IsSplit : 0 // CHECK-NEXT: BB Count : 0 // CHECK-NEXT: Secondary Entry Points : __ENTRY_nocfg@0x[[ENTRY_ADDR:[0-9a-f]+]] // CHECK-NEXT: } // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] // CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 // CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point): // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000008: ret # Offset: 8 // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "nocfg" // CHECK-EMPTY: // CHECK-NEXT: Running src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8 // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After src register safety analysis: // CHECK-NEXT: Binary Function "nocfg" { // CHECK-NEXT: Number : 3 // CHECK-NEXT: State : disassembled // ... // CHECK: Secondary Entry Points : __ENTRY_nocfg@0x[[ENTRY_ADDR]] // CHECK-NEXT: } // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point): // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "nocfg" // CHECK-EMPTY: // PAUTH-NEXT: Found call inst: 00000000: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state // PAUTH-NEXT: Call destination reg: X0 // PAUTH-NEXT: SafeToDerefRegs: LR W0 W30 X0 W0_HI W30_HI{{[ \t]*$}} // CHECK-NEXT: Found RET inst: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: RetReg: LR // CHECK-NEXT: SafeToDerefRegs:{{[ \t]*$}} // CHECK-EMPTY: // CHECK-NEXT: Running detailed src register safety analysis... // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]], src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( br x0, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: Due to label, resetting the state before: 00000000: ret # Offset: 8 // CHECK-NEXT: SrcSafetyAnalysis::ComputeNext( ret x30, src-state) // CHECK-NEXT: .. result: (src-state) // CHECK-NEXT: After detailed src register safety analysis: // CHECK-NEXT: Binary Function "nocfg" { // CHECK-NEXT: Number : 3 // ... // CHECK: Secondary Entry Points : __ENTRY_nocfg@0x[[ENTRY_ADDR]] // CHECK-NEXT: } // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000000: adr x0, __ENTRY_nocfg@0x[[ENTRY_ADDR]] # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: 00000004: br x0 # UNKNOWN CONTROL FLOW # Offset: 4 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: __ENTRY_nocfg@0x[[ENTRY_ADDR]] (Entry Point): // CHECK-NEXT: .{{[A-Za-z0-9]+}}: // CHECK-NEXT: 00000008: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "nocfg" // CHECK-EMPTY: // CHECK-NEXT: Attaching clobbering info to: 00000000: ret # Offset: 8 # CFGUnawareSrcSafetyAnalysis: src-state .globl auth_oracle .type auth_oracle,@function auth_oracle: autia x0, x1 ret .size auth_oracle, .-auth_oracle // CHECK-LABEL:Analyzing function auth_oracle, AllocatorId = 1 // CHECK-NEXT: Binary Function "auth_oracle" { // CHECK-NEXT: Number : 4 // CHECK-NEXT: State : CFG constructed // ... // CHECK: BB Layout : [[BB0:[0-9a-zA-Z.]+]] // CHECK-NEXT: } // CHECK-NEXT: [[BB0]] (2 instructions, align : 1) // CHECK-NEXT: Entry Point // CHECK-NEXT: 00000000: autia x0, x1 // CHECK-NEXT: 00000004: ret // CHECK-EMPTY: // CHECK-NEXT: DWARF CFI Instructions: // CHECK-NEXT: // CHECK-NEXT: End of Function "auth_oracle" // CHECK-EMPTY: // CHECK-NEXT: Running src register safety analysis... // ... // CHECK: After src register safety analysis: // CHECK-NEXT: Binary Function "auth_oracle" { // ... // CHECK: End of Function "auth_oracle" // ... // PAUTH: Running dst register safety analysis... // PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) // PAUTH-NEXT: .. result: (dst-state) // PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) // PAUTH-NEXT: .. result: (dst-state) // PAUTH-NEXT: After dst register safety analysis: // PAUTH-NEXT: Binary Function "auth_oracle" { // PAUTH-NEXT: Number : 4 // PAUTH-NEXT: State : CFG constructed // ... // PAUTH: BB Layout : [[BB0]] // PAUTH-NEXT: } // PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) // PAUTH-NEXT: Entry Point // PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state // PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state // PAUTH-EMPTY: // PAUTH-NEXT: DWARF CFI Instructions: // PAUTH-NEXT: // PAUTH-NEXT: End of Function "auth_oracle" // PAUTH-EMPTY: // PAUTH-NEXT: Found auth inst: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state // PAUTH-NEXT: Authenticated reg: X0 // PAUTH-NEXT: safe output registers: LR W30 W30_HI{{[ \t]*$}} // PAUTH-EMPTY: // PAUTH-NEXT: Running detailed dst register safety analysis... // PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( ret x30, dst-state) // PAUTH-NEXT: .. result: (dst-state) // PAUTH-NEXT: DstSafetyAnalysis::ComputeNext( autia x0, x1, dst-state) // PAUTH-NEXT: .. result: (dst-state) // PAUTH-NEXT: After detailed dst register safety analysis: // PAUTH-NEXT: Binary Function "auth_oracle" { // PAUTH-NEXT: Number : 4 // PAUTH-NEXT: State : CFG constructed // ... // PAUTH: BB Layout : [[BB0]] // PAUTH-NEXT: } // PAUTH-NEXT: [[BB0]] (2 instructions, align : 1) // PAUTH-NEXT: Entry Point // PAUTH-NEXT: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state // PAUTH-NEXT: 00000004: ret # DataflowDstSafetyAnalysis: dst-state // PAUTH-EMPTY: // PAUTH-NEXT: DWARF CFI Instructions: // PAUTH-NEXT: // PAUTH-NEXT: End of Function "auth_oracle" // PAUTH-EMPTY: // PAUTH-NEXT: Attaching leakage info to: 00000000: autia x0, x1 # DataflowDstSafetyAnalysis: dst-state // Gadget scanner should not crash on CFI instructions, including when debug-printing them. // Note that the particular debug output is not checked, but BOLT should be // compiled with assertions enabled to support -debug-only argument. .globl cfi_inst_df .type cfi_inst_df,@function cfi_inst_df: .cfi_startproc sub sp, sp, #16 .cfi_def_cfa_offset 16 add sp, sp, #16 .cfi_def_cfa_offset 0 ret .size cfi_inst_df, .-cfi_inst_df .cfi_endproc .globl cfi_inst_nocfg .type cfi_inst_nocfg,@function cfi_inst_nocfg: .cfi_startproc sub sp, sp, #16 .cfi_def_cfa_offset 16 adr x0, 1f br x0 1: add sp, sp, #16 .cfi_def_cfa_offset 0 ret .size cfi_inst_nocfg, .-cfi_inst_nocfg .cfi_endproc // CHECK-LABEL:Analyzing function main, AllocatorId = 1 .globl main .type main,@function main: ret .size main, .-main