|  | ;/* | 
|  | ; Copyright (C) 2014 Apple Inc. All rights reserved. | 
|  | ; | 
|  | ; Redistribution and use in source and binary forms, with or without | 
|  | ; modification, are permitted provided that the following conditions | 
|  | ; are met: | 
|  | ; 1. Redistributions of source code must retain the above copyright | 
|  | ;    notice, this list of conditions and the following disclaimer. | 
|  | ; 2. Redistributions in binary form must reproduce the above copyright | 
|  | ;    notice, this list of conditions and the following disclaimer in the | 
|  | ;    documentation and/or other materials provided with the distribution. | 
|  | ; | 
|  | ; THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | ; PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | ; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | ; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | ; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | ; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | ; OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | ;*/ | 
|  |  | 
|  | PUBLIC ctiMasmProbeTrampoline | 
|  |  | 
|  | _TEXT   SEGMENT | 
|  |  | 
|  | ; The following constants must match the x86_64 version in MacroAssemblerX86Common.cpp. | 
|  | PTR_SIZE EQU 8 | 
|  |  | 
|  | PROBE_PROBE_FUNCTION_OFFSET EQU (0 * PTR_SIZE) | 
|  | PROBE_ARG_OFFSET EQU (1 * PTR_SIZE) | 
|  | PROBE_INIT_STACK_FUNCTION_OFFSET EQU (2 * PTR_SIZE) | 
|  | PROBE_INIT_STACK_ARG_OFFSET EQU (3 * PTR_SIZE) | 
|  |  | 
|  | PROBE_FIRST_GPR_OFFSET EQU (4 * PTR_SIZE) | 
|  | PROBE_CPU_EAX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (0 * PTR_SIZE)) | 
|  | PROBE_CPU_ECX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (1 * PTR_SIZE)) | 
|  | PROBE_CPU_EDX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (2 * PTR_SIZE)) | 
|  | PROBE_CPU_EBX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (3 * PTR_SIZE)) | 
|  | PROBE_CPU_ESP_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (4 * PTR_SIZE)) | 
|  | PROBE_CPU_EBP_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (5 * PTR_SIZE)) | 
|  | PROBE_CPU_ESI_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (6 * PTR_SIZE)) | 
|  | PROBE_CPU_EDI_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (7 * PTR_SIZE)) | 
|  |  | 
|  | PROBE_CPU_R8_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (8 * PTR_SIZE)) | 
|  | PROBE_CPU_R9_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (9 * PTR_SIZE)) | 
|  | PROBE_CPU_R10_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (10 * PTR_SIZE)) | 
|  | PROBE_CPU_R11_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (11 * PTR_SIZE)) | 
|  | PROBE_CPU_R12_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (12 * PTR_SIZE)) | 
|  | PROBE_CPU_R13_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (13 * PTR_SIZE)) | 
|  | PROBE_CPU_R14_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (14 * PTR_SIZE)) | 
|  | PROBE_CPU_R15_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (15 * PTR_SIZE)) | 
|  | PROBE_FIRST_SPR_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (16 * PTR_SIZE)) | 
|  |  | 
|  | PROBE_CPU_EIP_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (0 * PTR_SIZE)) | 
|  | PROBE_CPU_EFLAGS_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (1 * PTR_SIZE)) | 
|  | PROBE_FIRST_XMM_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (2 * PTR_SIZE)) | 
|  |  | 
|  | XMM_SIZE EQU 8 | 
|  | PROBE_CPU_XMM0_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (0 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM1_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (1 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM2_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (2 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM3_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (3 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM4_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (4 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM5_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (5 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM6_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (6 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM7_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (7 * XMM_SIZE)) | 
|  |  | 
|  | PROBE_CPU_XMM8_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (8 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM9_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (9 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM10_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (10 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM11_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (11 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM12_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (12 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM13_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (13 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM14_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (14 * XMM_SIZE)) | 
|  | PROBE_CPU_XMM15_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (15 * XMM_SIZE)) | 
|  | PROBE_SIZE EQU (PROBE_CPU_XMM15_OFFSET + XMM_SIZE) | 
|  |  | 
|  | PROBE_EXECUTOR_OFFSET EQU PROBE_SIZE ; Stash the executeProbe function pointer at the end of the ProbeContext. | 
|  |  | 
|  | OUT_SIZE EQU (5 * PTR_SIZE) | 
|  |  | 
|  | ctiMasmProbeTrampoline PROC | 
|  | pushfq | 
|  |  | 
|  | ; MacroAssemblerX86Common::probe() has already generated code to store some values. | 
|  | ; Together with the rflags pushed above, the top of stack now looks like this: | 
|  | ;     rsp[0 * ptrSize]: rflags | 
|  | ;     rsp[1 * ptrSize]: return address / saved rip | 
|  | ;     rsp[2 * ptrSize]: saved rbx | 
|  | ;     rsp[3 * ptrSize]: saved rdx | 
|  | ;     rsp[4 * ptrSize]: saved rcx | 
|  | ;     rsp[5 * ptrSize]: saved rax | 
|  | ; | 
|  | ; Incoming registers contain: | 
|  | ;     rcx: Probe::executeProbe | 
|  | ;     rdx: probe function | 
|  | ;     rbx: probe arg | 
|  | ;     rax: scratch (was ctiMasmProbeTrampoline) | 
|  |  | 
|  | mov rax, rsp | 
|  | sub rsp, PROBE_SIZE + OUT_SIZE | 
|  |  | 
|  | ; The X86_64 ABI specifies that the worse case stack alignment requirement is 32 bytes. | 
|  | and rsp, not 01fh | 
|  | ; Since sp points to the ProbeContext, we've ensured that it's protected from interrupts before we initialize it. | 
|  |  | 
|  | mov [PROBE_CPU_EBP_OFFSET + rsp], rbp | 
|  | mov rbp, rsp ; Save the ProbeContext*. | 
|  |  | 
|  | mov [PROBE_EXECUTOR_OFFSET + rbp], rcx | 
|  | mov [PROBE_PROBE_FUNCTION_OFFSET + rbp], rdx | 
|  | mov [PROBE_ARG_OFFSET + rbp], rbx | 
|  | mov [PROBE_CPU_ESI_OFFSET + rbp], rsi | 
|  | mov [PROBE_CPU_EDI_OFFSET + rbp], rdi | 
|  |  | 
|  | mov rcx, [0 * PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_EFLAGS_OFFSET + rbp], rcx | 
|  | mov rcx, [1 *  PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_EIP_OFFSET + rbp], rcx | 
|  | mov rcx, [2 * PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_EBX_OFFSET + rbp], rcx | 
|  | mov rcx, [3 * PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_EDX_OFFSET + rbp], rcx | 
|  | mov rcx, [4 * PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_ECX_OFFSET + rbp], rcx | 
|  | mov rcx, [5 * PTR_SIZE + rax] | 
|  | mov [PROBE_CPU_EAX_OFFSET + rbp], rcx | 
|  |  | 
|  | mov rcx, rax | 
|  | add rcx, 6 * PTR_SIZE | 
|  | mov [PROBE_CPU_ESP_OFFSET + rbp], rcx | 
|  |  | 
|  | mov [PROBE_CPU_R8_OFFSET + rbp], r8 | 
|  | mov [PROBE_CPU_R9_OFFSET + rbp], r9 | 
|  | mov [PROBE_CPU_R10_OFFSET + rbp], r10 | 
|  | mov [PROBE_CPU_R11_OFFSET + rbp], r11 | 
|  | mov [PROBE_CPU_R12_OFFSET + rbp], r12 | 
|  | mov [PROBE_CPU_R13_OFFSET + rbp], r13 | 
|  | mov [PROBE_CPU_R14_OFFSET + rbp], r14 | 
|  | mov [PROBE_CPU_R15_OFFSET + rbp], r15 | 
|  |  | 
|  | movq qword ptr [PROBE_CPU_XMM0_OFFSET + rbp], xmm0 | 
|  | movq qword ptr [PROBE_CPU_XMM1_OFFSET + rbp], xmm1 | 
|  | movq qword ptr [PROBE_CPU_XMM2_OFFSET + rbp], xmm2 | 
|  | movq qword ptr [PROBE_CPU_XMM3_OFFSET + rbp], xmm3 | 
|  | movq qword ptr [PROBE_CPU_XMM4_OFFSET + rbp], xmm4 | 
|  | movq qword ptr [PROBE_CPU_XMM5_OFFSET + rbp], xmm5 | 
|  | movq qword ptr [PROBE_CPU_XMM6_OFFSET + rbp], xmm6 | 
|  | movq qword ptr [PROBE_CPU_XMM7_OFFSET + rbp], xmm7 | 
|  | movq qword ptr [PROBE_CPU_XMM8_OFFSET + rbp], xmm8 | 
|  | movq qword ptr [PROBE_CPU_XMM9_OFFSET + rbp], xmm9 | 
|  | movq qword ptr [PROBE_CPU_XMM10_OFFSET + rbp], xmm10 | 
|  | movq qword ptr [PROBE_CPU_XMM11_OFFSET + rbp], xmm11 | 
|  | movq qword ptr [PROBE_CPU_XMM12_OFFSET + rbp], xmm12 | 
|  | movq qword ptr [PROBE_CPU_XMM13_OFFSET + rbp], xmm13 | 
|  | movq qword ptr [PROBE_CPU_XMM14_OFFSET + rbp], xmm14 | 
|  | movq qword ptr [PROBE_CPU_XMM15_OFFSET + rbp], xmm15 | 
|  |  | 
|  | mov rcx, rbp ; the Probe::State* arg. | 
|  | sub rsp, 32 ; shadow space | 
|  | call qword ptr[PROBE_EXECUTOR_OFFSET + rbp] | 
|  | add rsp, 32 | 
|  |  | 
|  | ; Make sure the ProbeContext is entirely below the result stack pointer so | 
|  | ; that register values are still preserved when we call the initializeStack | 
|  | ; function. | 
|  | mov rcx, PROBE_SIZE + OUT_SIZE | 
|  | mov rax, rbp | 
|  | mov rdx, [PROBE_CPU_ESP_OFFSET + rbp] | 
|  | add rax, rcx | 
|  | cmp rdx, rax | 
|  | jge ctiMasmProbeTrampolineProbeContextIsSafe | 
|  |  | 
|  | ; Allocate a safe place on the stack below the result stack pointer to stash the ProbeContext. | 
|  | sub rdx, rcx | 
|  | and rdx, not 01fh ; Keep the stack pointer 32 bytes aligned. | 
|  | xor rax, rax | 
|  | mov rsp, rdx | 
|  |  | 
|  | mov rcx, PROBE_SIZE | 
|  |  | 
|  | ; Copy the ProbeContext to the safe place. | 
|  | ctiMasmProbeTrampolineCopyLoop: | 
|  | mov rdx, [rbp + rax] | 
|  | mov [rsp + rax], rdx | 
|  | add rax, PTR_SIZE | 
|  | cmp rcx, rax | 
|  | jg ctiMasmProbeTrampolineCopyLoop | 
|  |  | 
|  | mov rbp, rsp | 
|  |  | 
|  | ; Call initializeStackFunction if present. | 
|  | ctiMasmProbeTrampolineProbeContextIsSafe: | 
|  | xor rcx, rcx | 
|  | add rcx, [PROBE_INIT_STACK_FUNCTION_OFFSET + rbp] | 
|  | je ctiMasmProbeTrampolineRestoreRegisters | 
|  |  | 
|  | mov rdx, rcx | 
|  | mov rcx, rbp ; the Probe::State* arg. | 
|  | sub rsp, 32 ; shadow space | 
|  | call rdx | 
|  | add rsp, 32 | 
|  |  | 
|  | ctiMasmProbeTrampolineRestoreRegisters: | 
|  |  | 
|  | ; To enable probes to modify register state, we copy all registers | 
|  | ; out of the ProbeContext before returning. | 
|  |  | 
|  | mov rdx, [PROBE_CPU_EDX_OFFSET + rbp] | 
|  | mov rbx, [PROBE_CPU_EBX_OFFSET + rbp] | 
|  | mov rsi, [PROBE_CPU_ESI_OFFSET + rbp] | 
|  | mov rdi, [PROBE_CPU_EDI_OFFSET + rbp] | 
|  |  | 
|  | mov r8, [PROBE_CPU_R8_OFFSET + rbp] | 
|  | mov r9, [PROBE_CPU_R9_OFFSET + rbp] | 
|  | mov r10, [PROBE_CPU_R10_OFFSET + rbp] | 
|  | mov r11, [PROBE_CPU_R11_OFFSET + rbp] | 
|  | mov r12, [PROBE_CPU_R12_OFFSET + rbp] | 
|  | mov r13, [PROBE_CPU_R13_OFFSET + rbp] | 
|  | mov r14, [PROBE_CPU_R14_OFFSET + rbp] | 
|  | mov r15, [PROBE_CPU_R15_OFFSET + rbp] | 
|  |  | 
|  | movq xmm0, qword ptr[PROBE_CPU_XMM0_OFFSET + rbp] | 
|  | movq xmm1, qword ptr[PROBE_CPU_XMM1_OFFSET + rbp] | 
|  | movq xmm2, qword ptr[PROBE_CPU_XMM2_OFFSET + rbp] | 
|  | movq xmm3, qword ptr[PROBE_CPU_XMM3_OFFSET + rbp] | 
|  | movq xmm4, qword ptr[PROBE_CPU_XMM4_OFFSET + rbp] | 
|  | movq xmm5, qword ptr[PROBE_CPU_XMM5_OFFSET + rbp] | 
|  | movq xmm6, qword ptr[PROBE_CPU_XMM6_OFFSET + rbp] | 
|  | movq xmm7, qword ptr[PROBE_CPU_XMM7_OFFSET + rbp] | 
|  | movq xmm8, qword ptr[PROBE_CPU_XMM8_OFFSET + rbp] | 
|  | movq xmm9, qword ptr[PROBE_CPU_XMM9_OFFSET + rbp] | 
|  | movq xmm10, qword ptr[PROBE_CPU_XMM10_OFFSET + rbp] | 
|  | movq xmm11, qword ptr[PROBE_CPU_XMM11_OFFSET + rbp] | 
|  | movq xmm12, qword ptr[PROBE_CPU_XMM12_OFFSET + rbp] | 
|  | movq xmm13, qword ptr[PROBE_CPU_XMM13_OFFSET + rbp] | 
|  | movq xmm14, qword ptr[PROBE_CPU_XMM14_OFFSET + rbp] | 
|  | movq xmm15, qword ptr[PROBE_CPU_XMM15_OFFSET + rbp] | 
|  |  | 
|  | ; There are 6 more registers left to restore: | 
|  | ;     rax, rcx, rbp, rsp, rip, and rflags. | 
|  |  | 
|  | ; The restoration process at ctiMasmProbeTrampolineEnd below works by popping | 
|  | ; 5 words off the stack into rflags, rax, rcx, rbp, and rip. These 5 words need | 
|  | ; to be pushed on top of the final esp value so that just by popping the 5 words, | 
|  | ; we'll get the esp that the probe wants to set. Let's call this area (for storing | 
|  | ; these 5 words) the restore area. | 
|  | mov rcx, [PROBE_CPU_ESP_OFFSET + rbp] | 
|  | sub rcx, 5 * PTR_SIZE | 
|  |  | 
|  | ; rcx now points to the restore area. | 
|  |  | 
|  | ; Copy remaining restore values from the ProbeContext to the restore area. | 
|  | ; Note: We already ensured above that the ProbeContext is in a safe location before | 
|  | ; calling the initializeStackFunction. The initializeStackFunction is not allowed to | 
|  | ; change the stack pointer again. | 
|  | mov rax, [PROBE_CPU_EFLAGS_OFFSET + rbp] | 
|  | mov [0 * PTR_SIZE + rcx], rax | 
|  | mov rax, [PROBE_CPU_EAX_OFFSET + rbp] | 
|  | mov [1 * PTR_SIZE + rcx], rax | 
|  | mov rax, [PROBE_CPU_ECX_OFFSET + rbp] | 
|  | mov [2 * PTR_SIZE + rcx], rax | 
|  | mov rax, [PROBE_CPU_EBP_OFFSET + rbp] | 
|  | mov [3 * PTR_SIZE + rcx], rax | 
|  | mov rax, [PROBE_CPU_EIP_OFFSET + rbp] | 
|  | mov [4 * PTR_SIZE + rcx], rax | 
|  | mov rsp, rcx | 
|  |  | 
|  | ; Do the remaining restoration by popping off the restore area. | 
|  | popfq | 
|  | pop rax | 
|  | pop rcx | 
|  | pop rbp | 
|  | ret | 
|  | ctiMasmProbeTrampoline ENDP | 
|  |  | 
|  | _TEXT   ENDS | 
|  |  | 
|  | END |