248 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| /*
 | |
|  *  Copyright (C) 2017  Steven Rostedt, VMware Inc.
 | |
|  */
 | |
| 
 | |
| #include <linux/linkage.h>
 | |
| #include <asm/page_types.h>
 | |
| #include <asm/segment.h>
 | |
| #include <asm/export.h>
 | |
| #include <asm/ftrace.h>
 | |
| #include <asm/nospec-branch.h>
 | |
| 
 | |
| #ifdef CC_USING_FENTRY
 | |
| # define function_hook	__fentry__
 | |
| EXPORT_SYMBOL(__fentry__)
 | |
| #else
 | |
| # define function_hook	mcount
 | |
| EXPORT_SYMBOL(mcount)
 | |
| #endif
 | |
| 
 | |
| #ifdef CONFIG_DYNAMIC_FTRACE
 | |
| 
 | |
| /* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
 | |
| #if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
 | |
| # define USING_FRAME_POINTER
 | |
| #endif
 | |
| 
 | |
| #ifdef USING_FRAME_POINTER
 | |
| # define MCOUNT_FRAME			1	/* using frame = true  */
 | |
| #else
 | |
| # define MCOUNT_FRAME			0	/* using frame = false */
 | |
| #endif
 | |
| 
 | |
| ENTRY(function_hook)
 | |
| 	ret
 | |
| END(function_hook)
 | |
| 
 | |
| ENTRY(ftrace_caller)
 | |
| 
 | |
| #ifdef USING_FRAME_POINTER
 | |
| # ifdef CC_USING_FENTRY
 | |
| 	/*
 | |
| 	 * Frame pointers are of ip followed by bp.
 | |
| 	 * Since fentry is an immediate jump, we are left with
 | |
| 	 * parent-ip, function-ip. We need to add a frame with
 | |
| 	 * parent-ip followed by ebp.
 | |
| 	 */
 | |
| 	pushl	4(%esp)				/* parent ip */
 | |
| 	pushl	%ebp
 | |
| 	movl	%esp, %ebp
 | |
| 	pushl	2*4(%esp)			/* function ip */
 | |
| # endif
 | |
| 	/* For mcount, the function ip is directly above */
 | |
| 	pushl	%ebp
 | |
| 	movl	%esp, %ebp
 | |
| #endif
 | |
| 	pushl	%eax
 | |
| 	pushl	%ecx
 | |
| 	pushl	%edx
 | |
| 	pushl	$0				/* Pass NULL as regs pointer */
 | |
| 
 | |
| #ifdef USING_FRAME_POINTER
 | |
| 	/* Load parent ebp into edx */
 | |
| 	movl	4*4(%esp), %edx
 | |
| #else
 | |
| 	/* There's no frame pointer, load the appropriate stack addr instead */
 | |
| 	lea	4*4(%esp), %edx
 | |
| #endif
 | |
| 
 | |
| 	movl	(MCOUNT_FRAME+4)*4(%esp), %eax	/* load the rip */
 | |
| 	/* Get the parent ip */
 | |
| 	movl	4(%edx), %edx			/* edx has ebp */
 | |
| 
 | |
| 	movl	function_trace_op, %ecx
 | |
| 	subl	$MCOUNT_INSN_SIZE, %eax
 | |
| 
 | |
| .globl ftrace_call
 | |
| ftrace_call:
 | |
| 	call	ftrace_stub
 | |
| 
 | |
| 	addl	$4, %esp			/* skip NULL pointer */
 | |
| 	popl	%edx
 | |
| 	popl	%ecx
 | |
| 	popl	%eax
 | |
| #ifdef USING_FRAME_POINTER
 | |
| 	popl	%ebp
 | |
| # ifdef CC_USING_FENTRY
 | |
| 	addl	$4,%esp				/* skip function ip */
 | |
| 	popl	%ebp				/* this is the orig bp */
 | |
| 	addl	$4, %esp			/* skip parent ip */
 | |
| # endif
 | |
| #endif
 | |
| .Lftrace_ret:
 | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | |
| .globl ftrace_graph_call
 | |
| ftrace_graph_call:
 | |
| 	jmp	ftrace_stub
 | |
| #endif
 | |
| 
 | |
| /* This is weak to keep gas from relaxing the jumps */
 | |
| WEAK(ftrace_stub)
 | |
| 	ret
 | |
| END(ftrace_caller)
 | |
| 
 | |
| ENTRY(ftrace_regs_caller)
 | |
| 	/*
 | |
| 	 * i386 does not save SS and ESP when coming from kernel.
 | |
| 	 * Instead, to get sp, ®s->sp is used (see ptrace.h).
 | |
| 	 * Unfortunately, that means eflags must be at the same location
 | |
| 	 * as the current return ip is. We move the return ip into the
 | |
| 	 * regs->ip location, and move flags into the return ip location.
 | |
| 	 */
 | |
| 	pushl	$__KERNEL_CS
 | |
| 	pushl	4(%esp)				/* Save the return ip */
 | |
| 	pushl	$0				/* Load 0 into orig_ax */
 | |
| 	pushl	%gs
 | |
| 	pushl	%fs
 | |
| 	pushl	%es
 | |
| 	pushl	%ds
 | |
| 	pushl	%eax
 | |
| 
 | |
| 	/* Get flags and place them into the return ip slot */
 | |
| 	pushf
 | |
| 	popl	%eax
 | |
| 	movl	%eax, 8*4(%esp)
 | |
| 
 | |
| 	pushl	%ebp
 | |
| 	pushl	%edi
 | |
| 	pushl	%esi
 | |
| 	pushl	%edx
 | |
| 	pushl	%ecx
 | |
| 	pushl	%ebx
 | |
| 
 | |
| 	movl	12*4(%esp), %eax		/* Load ip (1st parameter) */
 | |
| 	subl	$MCOUNT_INSN_SIZE, %eax		/* Adjust ip */
 | |
| #ifdef CC_USING_FENTRY
 | |
| 	movl	15*4(%esp), %edx		/* Load parent ip (2nd parameter) */
 | |
| #else
 | |
| 	movl	0x4(%ebp), %edx			/* Load parent ip (2nd parameter) */
 | |
| #endif
 | |
| 	movl	function_trace_op, %ecx		/* Save ftrace_pos in 3rd parameter */
 | |
| 	pushl	%esp				/* Save pt_regs as 4th parameter */
 | |
| 
 | |
| GLOBAL(ftrace_regs_call)
 | |
| 	call	ftrace_stub
 | |
| 
 | |
| 	addl	$4, %esp			/* Skip pt_regs */
 | |
| 
 | |
| 	/* restore flags */
 | |
| 	push	14*4(%esp)
 | |
| 	popf
 | |
| 
 | |
| 	/* Move return ip back to its original location */
 | |
| 	movl	12*4(%esp), %eax
 | |
| 	movl	%eax, 14*4(%esp)
 | |
| 
 | |
| 	popl	%ebx
 | |
| 	popl	%ecx
 | |
| 	popl	%edx
 | |
| 	popl	%esi
 | |
| 	popl	%edi
 | |
| 	popl	%ebp
 | |
| 	popl	%eax
 | |
| 	popl	%ds
 | |
| 	popl	%es
 | |
| 	popl	%fs
 | |
| 	popl	%gs
 | |
| 
 | |
| 	/* use lea to not affect flags */
 | |
| 	lea	3*4(%esp), %esp			/* Skip orig_ax, ip and cs */
 | |
| 
 | |
| 	jmp	.Lftrace_ret
 | |
| #else /* ! CONFIG_DYNAMIC_FTRACE */
 | |
| 
 | |
| ENTRY(function_hook)
 | |
| 	cmpl	$__PAGE_OFFSET, %esp
 | |
| 	jb	ftrace_stub			/* Paging not enabled yet? */
 | |
| 
 | |
| 	cmpl	$ftrace_stub, ftrace_trace_function
 | |
| 	jnz	.Ltrace
 | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | |
| 	cmpl	$ftrace_stub, ftrace_graph_return
 | |
| 	jnz	ftrace_graph_caller
 | |
| 
 | |
| 	cmpl	$ftrace_graph_entry_stub, ftrace_graph_entry
 | |
| 	jnz	ftrace_graph_caller
 | |
| #endif
 | |
| .globl ftrace_stub
 | |
| ftrace_stub:
 | |
| 	ret
 | |
| 
 | |
| 	/* taken from glibc */
 | |
| .Ltrace:
 | |
| 	pushl	%eax
 | |
| 	pushl	%ecx
 | |
| 	pushl	%edx
 | |
| 	movl	0xc(%esp), %eax
 | |
| 	movl	0x4(%ebp), %edx
 | |
| 	subl	$MCOUNT_INSN_SIZE, %eax
 | |
| 
 | |
| 	movl	ftrace_trace_function, %ecx
 | |
| 	CALL_NOSPEC %ecx
 | |
| 
 | |
| 	popl	%edx
 | |
| 	popl	%ecx
 | |
| 	popl	%eax
 | |
| 	jmp	ftrace_stub
 | |
| END(function_hook)
 | |
| #endif /* CONFIG_DYNAMIC_FTRACE */
 | |
| 
 | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | |
| ENTRY(ftrace_graph_caller)
 | |
| 	pushl	%eax
 | |
| 	pushl	%ecx
 | |
| 	pushl	%edx
 | |
| 	movl	3*4(%esp), %eax
 | |
| 	/* Even with frame pointers, fentry doesn't have one here */
 | |
| #ifdef CC_USING_FENTRY
 | |
| 	lea	4*4(%esp), %edx
 | |
| 	movl	$0, %ecx
 | |
| #else
 | |
| 	lea	0x4(%ebp), %edx
 | |
| 	movl	(%ebp), %ecx
 | |
| #endif
 | |
| 	subl	$MCOUNT_INSN_SIZE, %eax
 | |
| 	call	prepare_ftrace_return
 | |
| 	popl	%edx
 | |
| 	popl	%ecx
 | |
| 	popl	%eax
 | |
| 	ret
 | |
| END(ftrace_graph_caller)
 | |
| 
 | |
| .globl return_to_handler
 | |
| return_to_handler:
 | |
| 	pushl	%eax
 | |
| 	pushl	%edx
 | |
| #ifdef CC_USING_FENTRY
 | |
| 	movl	$0, %eax
 | |
| #else
 | |
| 	movl	%ebp, %eax
 | |
| #endif
 | |
| 	call	ftrace_return_to_handler
 | |
| 	movl	%eax, %ecx
 | |
| 	popl	%edx
 | |
| 	popl	%eax
 | |
| 	JMP_NOSPEC %ecx
 | |
| #endif
 | 
