2009-06-09 07:25:09 -04:00
/ *
* mcount a n d f r i e n d s - - f t r a c e s t u f f
*
2010-01-22 07:35:20 -05:00
* Copyright ( C ) 2 0 0 9 - 2 0 1 0 A n a l o g D e v i c e s I n c .
2009-06-09 07:25:09 -04:00
* Licensed u n d e r t h e G P L - 2 o r l a t e r .
* /
# include < l i n u x / l i n k a g e . h >
# include < a s m / f t r a c e . h >
.text
/ * GCC w i l l h a v e c a l l e d u s b e f o r e s e t t i n g u p t h e f u n c t i o n p r o l o g u e , s o w e
* can c l o b b e r t h e n o r m a l s c r a t c h r e g i s t e r s , b u t w e n e e d t o m a k e s u r e t o
* save/ r e s t o r e t h e r e g i s t e r s u s e d f o r a r g u m e n t p a s s i n g ( R 0 - R 2 ) i n c a s e
* the p r o f i l e d f u n c t i o n i s u s i n g t h e m . W i t h d a t a r e g i s t e r s , R 3 i s t h e
* only o n e w e c a n b l o w a w a y . W i t h p o i n t e r r e g i s t e r s , w e h a v e P 0 - P 2 .
*
* Upon e n t r y , t h e R E T S w i l l p o i n t t o t h e t o p o f t h e c u r r e n t p r o f i l e d
2009-09-15 09:24:31 +00:00
* function. A n d s i n c e G C C p u s h e d t h e p r e v i o u s R E T S f o r u s , t h e p r e v i o u s
* function w i l l b e w a i t i n g t h e r e . m m m m p i e .
2009-06-09 07:25:09 -04:00
* /
ENTRY( _ _ m c o u n t )
2010-01-22 07:35:20 -05:00
# ifdef C O N F I G _ H A V E _ F U N C T I O N _ T R A C E _ M C O U N T _ T E S T
/* optional micro optimization: return if stopped */
p1 . l = _ f u n c t i o n _ t r a c e _ s t o p ;
p1 . h = _ f u n c t i o n _ t r a c e _ s t o p ;
r3 = [ p1 ] ;
cc = r3 = = 0 ;
if ! c c j u m p _ f t r a c e _ s t u b ( b p ) ;
# endif
2009-06-09 07:25:09 -04:00
/* save third function arg early so we can do testing below */
[ - - sp] = r2 ;
/* load the function pointer to the tracer */
p0 . l = _ f t r a c e _ t r a c e _ f u n c t i o n ;
p0 . h = _ f t r a c e _ t r a c e _ f u n c t i o n ;
r3 = [ p0 ] ;
/* optional micro optimization: don't call the stub tracer */
r2 . l = _ f t r a c e _ s t u b ;
r2 . h = _ f t r a c e _ s t u b ;
cc = r2 = = r3 ;
if ! c c j u m p . L d o _ t r a c e ;
2009-06-10 04:45:29 -04:00
# 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
/ * if t h e f t r a c e _ g r a p h _ r e t u r n f u n c t i o n p o i n t e r i s n o t s e t t o
* the f t r a c e _ s t u b e n t r y , c a l l p r e p a r e _ f t r a c e _ r e t u r n ( ) .
* /
p0 . l = _ f t r a c e _ g r a p h _ r e t u r n ;
p0 . h = _ f t r a c e _ g r a p h _ r e t u r n ;
r3 = [ p0 ] ;
cc = r2 = = r3 ;
if ! c c j u m p _ f t r a c e _ g r a p h _ c a l l e r ;
/ * similarly, i f t h e f t r a c e _ g r a p h _ e n t r y f u n c t i o n p o i n t e r i s n o t
* set t o t h e f t r a c e _ g r a p h _ e n t r y _ s t u b e n t r y , . . .
* /
p0 . l = _ f t r a c e _ g r a p h _ e n t r y ;
p0 . h = _ f t r a c e _ g r a p h _ e n t r y ;
r2 . l = _ f t r a c e _ g r a p h _ e n t r y _ s t u b ;
r2 . h = _ f t r a c e _ g r a p h _ e n t r y _ s t u b ;
r3 = [ p0 ] ;
cc = r2 = = r3 ;
if ! c c j u m p _ f t r a c e _ g r a p h _ c a l l e r ;
# endif
2009-06-09 07:25:09 -04:00
r2 = [ s p + + ] ;
rts;
.Ldo_trace :
/* save first/second function arg and the return register */
[ - - sp] = r0 ;
[ - - sp] = r1 ;
[ - - sp] = r e t s ;
/* setup the tracer function */
p0 = r3 ;
2009-09-15 09:24:31 +00:00
/ * function_ t r a c e _ c a l l ( u n s i g n e d l o n g i p , u n s i g n e d l o n g p a r e n t _ i p ) :
* ip : this p o i n t w a s c a l l e d b y . . .
* parent_ip : . . . this f u n c t i o n
* the i p i t s e l f w i l l n e e d a d j u s t i n g f o r t h e m c o u n t c a l l
2009-06-09 07:25:09 -04:00
* /
2009-09-15 09:24:31 +00:00
r0 = r e t s ;
r1 = [ s p + 1 6 ] ; /* skip the 4 local regs on stack */
r0 + = - M C O U N T _ I N S N _ S I Z E ;
2009-06-09 07:25:09 -04:00
/* call the tracer */
call ( p0 ) ;
/* restore state and get out of dodge */
2009-06-10 04:45:29 -04:00
.Lfinish_trace :
2009-06-09 07:25:09 -04:00
rets = [ s p + + ] ;
r1 = [ s p + + ] ;
r0 = [ s p + + ] ;
r2 = [ s p + + ] ;
.globl _ftrace_stub
_ftrace_stub :
rts;
ENDPROC( _ _ m c o u n t )
2009-06-10 04:45:29 -04:00
# 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
/ * The p r e p a r e _ f t r a c e _ r e t u r n ( ) f u n c t i o n i s s i m i l a r t o t h e t r a c e f u n c t i o n
* except i t t a k e s a p o i n t e r t o t h e l o c a t i o n o f t h e f r o m p c . T h i s i s s o
* the p r e p a r e _ f t r a c e _ r e t u r n ( ) c a n h i j a c k i t t e m p o r a r i l y f o r p r o b i n g
* purposes.
* /
ENTRY( _ f t r a c e _ g r a p h _ c a l l e r )
/* save first/second function arg and the return register */
[ - - sp] = r0 ;
[ - - sp] = r1 ;
[ - - sp] = r e t s ;
2009-09-15 09:24:31 +00:00
/* prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) */
r0 = s p ;
2009-06-10 04:45:29 -04:00
r1 = r e t s ;
2009-09-15 09:24:31 +00:00
r0 + = 1 6 ; /* skip the 4 local regs on stack */
2009-06-10 04:45:29 -04:00
r1 + = - M C O U N T _ I N S N _ S I Z E ;
call _ p r e p a r e _ f t r a c e _ r e t u r n ;
jump . L f i n i s h _ t r a c e ;
ENDPROC( _ f t r a c e _ g r a p h _ c a l l e r )
/ * Undo t h e r e w r i t e c a u s e d b y f t r a c e _ g r a p h _ c a l l e r ( ) . T h e c o m m o n f u n c t i o n
* ftrace_ r e t u r n _ t o _ h a n d l e r ( ) w i l l r e t u r n t h e o r i g i n a l r e t s s o w e c a n
* restore i t a n d b e o n o u r w a y .
* /
ENTRY( _ r e t u r n _ t o _ h a n d l e r )
/* make sure original return values are saved */
[ - - sp] = p0 ;
[ - - sp] = r0 ;
[ - - sp] = r1 ;
/* get original return address */
call _ f t r a c e _ r e t u r n _ t o _ h a n d l e r ;
rets = r0 ;
/ * anomaly 0 5 0 0 0 3 7 1 - m a k e s u r e w e h a v e a t l e a s t t h r e e i n s t r u c t i o n s
* between r e t s s e t t i n g a n d t h e r e t u r n
* /
r1 = [ s p + + ] ;
r0 = [ s p + + ] ;
p0 = [ s p + + ] ;
rts;
ENDPROC( _ r e t u r n _ t o _ h a n d l e r )
# endif