182112379SRussell King/* 282112379SRussell King * This program is free software; you can redistribute it and/or modify 382112379SRussell King * it under the terms of the GNU General Public License version 2 as 482112379SRussell King * published by the Free Software Foundation. 582112379SRussell King */ 682112379SRussell King 782112379SRussell King#include <asm/assembler.h> 882112379SRussell King#include <asm/ftrace.h> 982112379SRussell King#include <asm/unwind.h> 1082112379SRussell King 1182112379SRussell King#include "entry-header.S" 1282112379SRussell King 1382112379SRussell King/* 1482112379SRussell King * When compiling with -pg, gcc inserts a call to the mcount routine at the 1582112379SRussell King * start of every function. In mcount, apart from the function's address (in 1682112379SRussell King * lr), we need to get hold of the function's caller's address. 1782112379SRussell King * 18d3c61619SStefan Agner * Newer GCCs (4.4+) solve this problem by using a version of mcount with call 19d3c61619SStefan Agner * sites like: 2082112379SRussell King * 2182112379SRussell King * push {lr} 2282112379SRussell King * bl __gnu_mcount_nc 2382112379SRussell King * 2482112379SRussell King * With these compilers, frame pointers are not necessary. 2582112379SRussell King * 2682112379SRussell King * mcount can be thought of as a function called in the middle of a subroutine 2782112379SRussell King * call. As such, it needs to be transparent for both the caller and the 2882112379SRussell King * callee: the original lr needs to be restored when leaving mcount, and no 2982112379SRussell King * registers should be clobbered. (In the __gnu_mcount_nc implementation, we 3082112379SRussell King * clobber the ip register. This is OK because the ARM calling convention 3182112379SRussell King * allows it to be clobbered in subroutines and doesn't use it to hold 3282112379SRussell King * parameters.) 3382112379SRussell King * 34d3c61619SStefan Agner * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}" 35d3c61619SStefan Agner * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c). 3682112379SRussell King */ 3782112379SRussell King 3882112379SRussell King.macro mcount_adjust_addr rd, rn 3982112379SRussell King bic \rd, \rn, #1 @ clear the Thumb bit if present 4082112379SRussell King sub \rd, \rd, #MCOUNT_INSN_SIZE 4182112379SRussell King.endm 4282112379SRussell King 4382112379SRussell King.macro __mcount suffix 4482112379SRussell King mcount_enter 4582112379SRussell King ldr r0, =ftrace_trace_function 4682112379SRussell King ldr r2, [r0] 4782112379SRussell King adr r0, .Lftrace_stub 4882112379SRussell King cmp r0, r2 4982112379SRussell King bne 1f 5082112379SRussell King 5182112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 5282112379SRussell King ldr r1, =ftrace_graph_return 5382112379SRussell King ldr r2, [r1] 5482112379SRussell King cmp r0, r2 5582112379SRussell King bne ftrace_graph_caller\suffix 5682112379SRussell King 5782112379SRussell King ldr r1, =ftrace_graph_entry 5882112379SRussell King ldr r2, [r1] 5982112379SRussell King ldr r0, =ftrace_graph_entry_stub 6082112379SRussell King cmp r0, r2 6182112379SRussell King bne ftrace_graph_caller\suffix 6282112379SRussell King#endif 6382112379SRussell King 6482112379SRussell King mcount_exit 6582112379SRussell King 6682112379SRussell King1: mcount_get_lr r1 @ lr of instrumented func 6782112379SRussell King mcount_adjust_addr r0, lr @ instrumented function 6814327c66SRussell King badr lr, 2f 6982112379SRussell King mov pc, r2 7082112379SRussell King2: mcount_exit 7182112379SRussell King.endm 7282112379SRussell King 73620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 74620176f3SAbel Vesa 75620176f3SAbel Vesa.macro __ftrace_regs_caller 76620176f3SAbel Vesa 77620176f3SAbel Vesa sub sp, sp, #8 @ space for PC and CPSR OLD_R0, 78620176f3SAbel Vesa @ OLD_R0 will overwrite previous LR 79620176f3SAbel Vesa 80620176f3SAbel Vesa add ip, sp, #12 @ move in IP the value of SP as it was 81620176f3SAbel Vesa @ before the push {lr} of the mcount mechanism 82620176f3SAbel Vesa 83620176f3SAbel Vesa str lr, [sp, #0] @ store LR instead of PC 84620176f3SAbel Vesa 85620176f3SAbel Vesa ldr lr, [sp, #8] @ get previous LR 86620176f3SAbel Vesa 87620176f3SAbel Vesa str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR 88620176f3SAbel Vesa 89620176f3SAbel Vesa stmdb sp!, {ip, lr} 90620176f3SAbel Vesa stmdb sp!, {r0-r11, lr} 91620176f3SAbel Vesa 92620176f3SAbel Vesa @ stack content at this point: 93620176f3SAbel Vesa @ 0 4 48 52 56 60 64 68 72 94620176f3SAbel Vesa @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | 95620176f3SAbel Vesa 96620176f3SAbel Vesa mov r3, sp @ struct pt_regs* 97620176f3SAbel Vesa 98620176f3SAbel Vesa ldr r2, =function_trace_op 99620176f3SAbel Vesa ldr r2, [r2] @ pointer to the current 100620176f3SAbel Vesa @ function tracing op 101620176f3SAbel Vesa 102620176f3SAbel Vesa ldr r1, [sp, #S_LR] @ lr of instrumented func 103620176f3SAbel Vesa 104620176f3SAbel Vesa ldr lr, [sp, #S_PC] @ get LR 105620176f3SAbel Vesa 106620176f3SAbel Vesa mcount_adjust_addr r0, lr @ instrumented function 107620176f3SAbel Vesa 108620176f3SAbel Vesa .globl ftrace_regs_call 109620176f3SAbel Vesaftrace_regs_call: 110620176f3SAbel Vesa bl ftrace_stub 111620176f3SAbel Vesa 112620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER 113620176f3SAbel Vesa .globl ftrace_graph_regs_call 114620176f3SAbel Vesaftrace_graph_regs_call: 115620176f3SAbel Vesa mov r0, r0 116620176f3SAbel Vesa#endif 117620176f3SAbel Vesa 118620176f3SAbel Vesa @ pop saved regs 119620176f3SAbel Vesa ldmia sp!, {r0-r12} @ restore r0 through r12 120620176f3SAbel Vesa ldr ip, [sp, #8] @ restore PC 121620176f3SAbel Vesa ldr lr, [sp, #4] @ restore LR 122620176f3SAbel Vesa ldr sp, [sp, #0] @ restore SP 123620176f3SAbel Vesa mov pc, ip @ return 124620176f3SAbel Vesa.endm 125620176f3SAbel Vesa 126620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER 127620176f3SAbel Vesa.macro __ftrace_graph_regs_caller 128620176f3SAbel Vesa 129620176f3SAbel Vesa sub r0, fp, #4 @ lr of instrumented routine (parent) 130620176f3SAbel Vesa 131620176f3SAbel Vesa @ called from __ftrace_regs_caller 132620176f3SAbel Vesa ldr r1, [sp, #S_PC] @ instrumented routine (func) 133620176f3SAbel Vesa mcount_adjust_addr r1, r1 134620176f3SAbel Vesa 135620176f3SAbel Vesa mov r2, fp @ frame pointer 136620176f3SAbel Vesa bl prepare_ftrace_return 137620176f3SAbel Vesa 138620176f3SAbel Vesa @ pop registers saved in ftrace_regs_caller 139620176f3SAbel Vesa ldmia sp!, {r0-r12} @ restore r0 through r12 140620176f3SAbel Vesa ldr ip, [sp, #8] @ restore PC 141620176f3SAbel Vesa ldr lr, [sp, #4] @ restore LR 142620176f3SAbel Vesa ldr sp, [sp, #0] @ restore SP 143620176f3SAbel Vesa mov pc, ip @ return 144620176f3SAbel Vesa 145620176f3SAbel Vesa.endm 146620176f3SAbel Vesa#endif 147620176f3SAbel Vesa#endif 148620176f3SAbel Vesa 14982112379SRussell King.macro __ftrace_caller suffix 15082112379SRussell King mcount_enter 15182112379SRussell King 15282112379SRussell King mcount_get_lr r1 @ lr of instrumented func 15382112379SRussell King mcount_adjust_addr r0, lr @ instrumented function 15482112379SRussell King 155620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 156620176f3SAbel Vesa ldr r2, =function_trace_op 157620176f3SAbel Vesa ldr r2, [r2] @ pointer to the current 158620176f3SAbel Vesa @ function tracing op 159620176f3SAbel Vesa mov r3, #0 @ regs is NULL 160620176f3SAbel Vesa#endif 161620176f3SAbel Vesa 16282112379SRussell King .globl ftrace_call\suffix 16382112379SRussell Kingftrace_call\suffix: 16482112379SRussell King bl ftrace_stub 16582112379SRussell King 16682112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 16782112379SRussell King .globl ftrace_graph_call\suffix 16882112379SRussell Kingftrace_graph_call\suffix: 16982112379SRussell King mov r0, r0 17082112379SRussell King#endif 17182112379SRussell King 17282112379SRussell King mcount_exit 17382112379SRussell King.endm 17482112379SRussell King 17582112379SRussell King.macro __ftrace_graph_caller 17682112379SRussell King sub r0, fp, #4 @ &lr of instrumented routine (&parent) 17782112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 17882112379SRussell King @ called from __ftrace_caller, saved in mcount_enter 17982112379SRussell King ldr r1, [sp, #16] @ instrumented routine (func) 18082112379SRussell King mcount_adjust_addr r1, r1 18182112379SRussell King#else 18282112379SRussell King @ called from __mcount, untouched in lr 18382112379SRussell King mcount_adjust_addr r1, lr @ instrumented routine (func) 18482112379SRussell King#endif 18582112379SRussell King mov r2, fp @ frame pointer 18682112379SRussell King bl prepare_ftrace_return 18782112379SRussell King mcount_exit 18882112379SRussell King.endm 18982112379SRussell King 19082112379SRussell King/* 19182112379SRussell King * __gnu_mcount_nc 19282112379SRussell King */ 19382112379SRussell King 19482112379SRussell King.macro mcount_enter 19582112379SRussell King/* 19682112379SRussell King * This pad compensates for the push {lr} at the call site. Note that we are 19782112379SRussell King * unable to unwind through a function which does not otherwise save its lr. 19882112379SRussell King */ 19982112379SRussell King UNWIND(.pad #4) 20082112379SRussell King stmdb sp!, {r0-r3, lr} 20182112379SRussell King UNWIND(.save {r0-r3, lr}) 20282112379SRussell King.endm 20382112379SRussell King 20482112379SRussell King.macro mcount_get_lr reg 20582112379SRussell King ldr \reg, [sp, #20] 20682112379SRussell King.endm 20782112379SRussell King 20882112379SRussell King.macro mcount_exit 20982112379SRussell King ldmia sp!, {r0-r3, ip, lr} 21082112379SRussell King ret ip 21182112379SRussell King.endm 21282112379SRussell King 21382112379SRussell KingENTRY(__gnu_mcount_nc) 21482112379SRussell KingUNWIND(.fnstart) 21582112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 21682112379SRussell King mov ip, lr 21782112379SRussell King ldmia sp!, {lr} 21882112379SRussell King ret ip 21982112379SRussell King#else 22082112379SRussell King __mcount 22182112379SRussell King#endif 22282112379SRussell KingUNWIND(.fnend) 22382112379SRussell KingENDPROC(__gnu_mcount_nc) 22482112379SRussell King 22582112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 22682112379SRussell KingENTRY(ftrace_caller) 22782112379SRussell KingUNWIND(.fnstart) 22882112379SRussell King __ftrace_caller 22982112379SRussell KingUNWIND(.fnend) 23082112379SRussell KingENDPROC(ftrace_caller) 231620176f3SAbel Vesa 232620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 233620176f3SAbel VesaENTRY(ftrace_regs_caller) 234620176f3SAbel VesaUNWIND(.fnstart) 235620176f3SAbel Vesa __ftrace_regs_caller 236620176f3SAbel VesaUNWIND(.fnend) 237620176f3SAbel VesaENDPROC(ftrace_regs_caller) 238620176f3SAbel Vesa#endif 239620176f3SAbel Vesa 24082112379SRussell King#endif 24182112379SRussell King 24282112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 24382112379SRussell KingENTRY(ftrace_graph_caller) 24482112379SRussell KingUNWIND(.fnstart) 24582112379SRussell King __ftrace_graph_caller 24682112379SRussell KingUNWIND(.fnend) 24782112379SRussell KingENDPROC(ftrace_graph_caller) 248620176f3SAbel Vesa 249620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 250620176f3SAbel VesaENTRY(ftrace_graph_regs_caller) 251620176f3SAbel VesaUNWIND(.fnstart) 252620176f3SAbel Vesa __ftrace_graph_regs_caller 253620176f3SAbel VesaUNWIND(.fnend) 254620176f3SAbel VesaENDPROC(ftrace_graph_regs_caller) 255620176f3SAbel Vesa#endif 25682112379SRussell King#endif 25782112379SRussell King 25882112379SRussell King.purgem mcount_enter 25982112379SRussell King.purgem mcount_get_lr 26082112379SRussell King.purgem mcount_exit 26182112379SRussell King 26282112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 26382112379SRussell King .globl return_to_handler 26482112379SRussell Kingreturn_to_handler: 26582112379SRussell King stmdb sp!, {r0-r3} 26682112379SRussell King mov r0, fp @ frame pointer 26782112379SRussell King bl ftrace_return_to_handler 26882112379SRussell King mov lr, r0 @ r0 has real ret addr 26982112379SRussell King ldmia sp!, {r0-r3} 27082112379SRussell King ret lr 27182112379SRussell King#endif 27282112379SRussell King 27382112379SRussell KingENTRY(ftrace_stub) 27482112379SRussell King.Lftrace_stub: 27582112379SRussell King ret lr 27682112379SRussell KingENDPROC(ftrace_stub) 277