2019-06-04 11:11:33 +03:00
/* SPDX-License-Identifier: GPL-2.0-only */
2014-10-28 16:26:48 +03:00
# include < a s m / a s s e m b l e r . h >
# include < a s m / f t r a c e . h >
# include < a s m / u n w i n d . h >
# include " e n t r y - h e a d e r . S "
/ *
* When c o m p i l i n g w i t h - p g , g c c i n s e r t s a c a l l t o t h e m c o u n t r o u t i n e a t t h e
* start o f e v e r y f u n c t i o n . I n m c o u n t , a p a r t f r o m t h e f u n c t i o n ' s a d d r e s s ( i n
* lr) , w e n e e d t o g e t h o l d o f t h e f u n c t i o n ' s c a l l e r ' s a d d r e s s .
*
2018-09-11 06:31:49 +03:00
* Newer G C C s ( 4 . 4 + ) s o l v e t h i s p r o b l e m b y u s i n g a v e r s i o n o f m c o u n t w i t h c a l l
* sites l i k e :
2014-10-28 16:26:48 +03:00
*
* push { l r }
* bl _ _ g n u _ m c o u n t _ n c
*
* With t h e s e c o m p i l e r s , f r a m e p o i n t e r s a r e n o t n e c e s s a r y .
*
* mcount c a n b e t h o u g h t o f a s a f u n c t i o n c a l l e d i n t h e m i d d l e o f a s u b r o u t i n e
* call. A s s u c h , i t n e e d s t o b e t r a n s p a r e n t f o r b o t h t h e c a l l e r a n d t h e
* callee : the o r i g i n a l l r n e e d s t o b e r e s t o r e d w h e n l e a v i n g m c o u n t , a n d n o
* registers s h o u l d b e c l o b b e r e d . ( I n t h e _ _ g n u _ m c o u n t _ n c i m p l e m e n t a t i o n , w e
* clobber t h e i p r e g i s t e r . T h i s i s O K b e c a u s e t h e A R M c a l l i n g c o n v e n t i o n
* allows i t t o b e c l o b b e r e d i n s u b r o u t i n e s a n d d o e s n ' t u s e i t t o h o l d
* parameters. )
*
2018-09-11 06:31:49 +03:00
* When u s i n g d y n a m i c f t r a c e , w e p a t c h o u t t h e m c o u n t c a l l b y a " p o p { l r } "
* instead o f t h e _ _ g n u _ m c o u n t _ n c c a l l ( s e e a r c h / a r m / k e r n e l / f t r a c e . c ) .
2014-10-28 16:26:48 +03:00
* /
.macro mcount_adjust_addr rd, r n
bic \ r d , \ r n , #1 @ clear the Thumb bit if present
sub \ r d , \ r d , #M C O U N T _ I N S N _ S I Z E
.endm
.macro __mcount suffix
mcount_ e n t e r
ldr r0 , =ftrace_trace_function
ldr r2 , [ r0 ]
adr r0 , . L f t r a c e _ s t u b
cmp r0 , r2
bne 1 f
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
ldr r1 , =ftrace_graph_return
ldr r2 , [ r1 ]
cmp r0 , r2
bne f t r a c e _ g r a p h _ c a l l e r \ s u f f i x
ldr r1 , =ftrace_graph_entry
ldr r2 , [ r1 ]
ldr r0 , =ftrace_graph_entry_stub
cmp r0 , r2
bne f t r a c e _ g r a p h _ c a l l e r \ s u f f i x
# endif
mcount_ e x i t
1 : mcount_ g e t _ l r r1 @ lr of instrumented func
mcount_ a d j u s t _ a d d r r0 , l r @ instrumented function
2015-04-21 16:17:25 +03:00
badr l r , 2 f
2014-10-28 16:26:48 +03:00
mov p c , r2
2 : mcount_ e x i t
.endm
2017-05-26 23:49:47 +03:00
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E _ W I T H _ R E G S
.macro __ftrace_regs_caller
sub s p , s p , #8 @ space for PC and CPSR OLD_R0,
@ OLD_R0 will overwrite previous LR
add i p , s p , #12 @ move in IP the value of SP as it was
@ before the push {lr} of the mcount mechanism
str l r , [ s p , #0 ] @ store LR instead of PC
ldr l r , [ s p , #8 ] @ get previous LR
str r0 , [ s p , #8 ] @ write r0 as OLD_R0 over previous LR
stmdb s p ! , { i p , l r }
stmdb s p ! , { r0 - r11 , l r }
@ stack content at this point:
@ 0 4 48 52 56 60 64 68 72
@ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
mov r3 , s p @ struct pt_regs*
ldr r2 , =function_trace_op
ldr r2 , [ r2 ] @ pointer to the current
@ function tracing op
ldr r1 , [ s p , #S _ L R ] @ l r o f i n s t r u m e n t e d f u n c
ldr l r , [ s p , #S _ P C ] @ g e t L R
mcount_ a d j u s t _ a d d r r0 , l r @ instrumented function
.globl ftrace_regs_call
ftrace_regs_call :
bl f t r a c e _ s t u b
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
.globl ftrace_graph_regs_call
ftrace_graph_regs_call :
mov r0 , r0
# endif
@ pop saved regs
ldmia s p ! , { r0 - r12 } @ restore r0 through r12
ldr i p , [ s p , #8 ] @ restore PC
ldr l r , [ s p , #4 ] @ restore LR
ldr s p , [ s p , #0 ] @ restore SP
mov p c , i p @ return
.endm
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
.macro __ftrace_graph_regs_caller
sub r0 , f p , #4 @ lr of instrumented routine (parent)
@ called from __ftrace_regs_caller
ldr r1 , [ s p , #S _ P C ] @ i n s t r u m e n t e d r o u t i n e ( f u n c )
mcount_ a d j u s t _ a d d r r1 , r1
mov r2 , f p @ frame pointer
bl p r e p a r e _ f t r a c e _ r e t u r n
@ pop registers saved in ftrace_regs_caller
ldmia s p ! , { r0 - r12 } @ restore r0 through r12
ldr i p , [ s p , #8 ] @ restore PC
ldr l r , [ s p , #4 ] @ restore LR
ldr s p , [ s p , #0 ] @ restore SP
mov p c , i p @ return
.endm
# endif
# endif
2014-10-28 16:26:48 +03:00
.macro __ftrace_caller suffix
mcount_ e n t e r
mcount_ g e t _ l r r1 @ lr of instrumented func
mcount_ a d j u s t _ a d d r r0 , l r @ instrumented function
2017-05-26 23:49:47 +03:00
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E _ W I T H _ R E G S
ldr r2 , =function_trace_op
ldr r2 , [ r2 ] @ pointer to the current
@ function tracing op
mov r3 , #0 @ regs is NULL
# endif
2014-10-28 16:26:48 +03:00
.globl ftrace_ c a l l \ s u f f i x
ftrace_ c a l l \ s u f f i x :
bl f t r a c e _ s t u b
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
.globl ftrace_ g r a p h _ c a l l \ s u f f i x
ftrace_ g r a p h _ c a l l \ s u f f i x :
mov r0 , r0
# endif
mcount_ e x i t
.endm
.macro __ftrace_graph_caller
sub r0 , f p , #4 @ &lr of instrumented routine (&parent)
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E
@ called from __ftrace_caller, saved in mcount_enter
ldr r1 , [ s p , #16 ] @ instrumented routine (func)
mcount_ a d j u s t _ a d d r r1 , r1
# else
@ called from __mcount, untouched in lr
mcount_ a d j u s t _ a d d r r1 , l r @ instrumented routine (func)
# endif
mov r2 , f p @ frame pointer
bl p r e p a r e _ f t r a c e _ r e t u r n
mcount_ e x i t
.endm
/ *
* _ _ gnu_ m c o u n t _ n c
* /
.macro mcount_enter
/ *
* This p a d c o m p e n s a t e s f o r t h e p u s h { l r } a t t h e c a l l s i t e . N o t e t h a t w e a r e
* unable t o u n w i n d t h r o u g h a f u n c t i o n w h i c h d o e s n o t o t h e r w i s e s a v e i t s l r .
* /
UNWIND( . p a d #4 )
stmdb s p ! , { r0 - r3 , l r }
UNWIND( . s a v e { r0 - r3 , l r } )
.endm
.macro mcount_get_lr reg
ldr \ r e g , [ s p , #20 ]
.endm
.macro mcount_exit
ldmia s p ! , { r0 - r3 , i p , l r }
ret i p
.endm
ENTRY( _ _ g n u _ m c o u n t _ n c )
UNWIND( . f n s t a r t )
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E
mov i p , l r
ldmia s p ! , { l r }
ret i p
# else
_ _ mcount
# endif
UNWIND( . f n e n d )
ENDPROC( _ _ g n u _ m c o u n t _ n c )
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E
ENTRY( f t r a c e _ c a l l e r )
UNWIND( . f n s t a r t )
_ _ ftrace_ c a l l e r
UNWIND( . f n e n d )
ENDPROC( f t r a c e _ c a l l e r )
2017-05-26 23:49:47 +03:00
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E _ W I T H _ R E G S
ENTRY( f t r a c e _ r e g s _ c a l l e r )
UNWIND( . f n s t a r t )
_ _ ftrace_ r e g s _ c a l l e r
UNWIND( . f n e n d )
ENDPROC( f t r a c e _ r e g s _ c a l l e r )
# endif
2014-10-28 16:26:48 +03:00
# endif
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
ENTRY( f t r a c e _ g r a p h _ c a l l e r )
UNWIND( . f n s t a r t )
_ _ ftrace_ g r a p h _ c a l l e r
UNWIND( . f n e n d )
ENDPROC( f t r a c e _ g r a p h _ c a l l e r )
2017-05-26 23:49:47 +03:00
# ifdef C O N F I G _ D Y N A M I C _ F T R A C E _ W I T H _ R E G S
ENTRY( f t r a c e _ g r a p h _ r e g s _ c a l l e r )
UNWIND( . f n s t a r t )
_ _ ftrace_ g r a p h _ r e g s _ c a l l e r
UNWIND( . f n e n d )
ENDPROC( f t r a c e _ g r a p h _ r e g s _ c a l l e r )
# endif
2014-10-28 16:26:48 +03:00
# endif
.purgem mcount_enter
.purgem mcount_get_lr
.purgem mcount_exit
# ifdef C O N F I G _ F U N C T I O N _ G R A P H _ T R A C E R
.globl return_to_handler
return_to_handler :
stmdb s p ! , { r0 - r3 }
mov r0 , f p @ frame pointer
bl f t r a c e _ r e t u r n _ t o _ h a n d l e r
mov l r , r0 @ r0 has real ret addr
ldmia s p ! , { r0 - r3 }
ret l r
# endif
ENTRY( f t r a c e _ s t u b )
.Lftrace_stub :
ret l r
ENDPROC( f t r a c e _ s t u b )