2013-12-03 14:09:32 +01:00
/*
* Copyright ( C ) 2009 , 2010 Red Hat Inc , Steven Rostedt < srostedt @ redhat . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ;
* version 2.1 of the License ( not later ! )
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program ; if not , see < http : //www.gnu.org/licenses>
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "event-parse.h"
# include "event-utils.h"
static struct func_stack {
int size ;
char * * stack ;
} * fstack ;
static int cpus = - 1 ;
# define STK_BLK 10
2018-08-08 14:02:48 -04:00
struct tep_plugin_option plugin_options [ ] =
2014-06-02 23:20:15 -04:00
{
{
. name = " parent " ,
. plugin_alias = " ftrace " ,
. description =
" Print parent of functions for function events " ,
} ,
{
. name = " indent " ,
. plugin_alias = " ftrace " ,
. description =
" Try to show function call indents, based on parents " ,
. set = 1 ,
} ,
{
. name = NULL ,
}
} ;
2018-08-08 14:02:48 -04:00
static struct tep_plugin_option * ftrace_parent = & plugin_options [ 0 ] ;
static struct tep_plugin_option * ftrace_indent = & plugin_options [ 1 ] ;
2014-06-02 23:20:15 -04:00
2013-12-03 14:09:32 +01:00
static void add_child ( struct func_stack * stack , const char * child , int pos )
{
int i ;
if ( ! child )
return ;
if ( pos < stack - > size )
free ( stack - > stack [ pos ] ) ;
else {
2013-12-03 14:09:40 +01:00
char * * ptr ;
ptr = realloc ( stack - > stack , sizeof ( char * ) *
( stack - > size + STK_BLK ) ) ;
if ( ! ptr ) {
warning ( " could not allocate plugin memory \n " ) ;
return ;
}
stack - > stack = ptr ;
2013-12-03 14:09:32 +01:00
for ( i = stack - > size ; i < stack - > size + STK_BLK ; i + + )
stack - > stack [ i ] = NULL ;
stack - > size + = STK_BLK ;
}
stack - > stack [ pos ] = strdup ( child ) ;
}
2013-12-03 14:09:39 +01:00
static int add_and_get_index ( const char * parent , const char * child , int cpu )
2013-12-03 14:09:32 +01:00
{
int i ;
if ( cpu < 0 )
return 0 ;
if ( cpu > cpus ) {
2013-12-03 14:09:40 +01:00
struct func_stack * ptr ;
ptr = realloc ( fstack , sizeof ( * fstack ) * ( cpu + 1 ) ) ;
if ( ! ptr ) {
warning ( " could not allocate plugin memory \n " ) ;
return 0 ;
}
fstack = ptr ;
2013-12-03 14:09:32 +01:00
/* Account for holes in the cpu count */
for ( i = cpus + 1 ; i < = cpu ; i + + )
memset ( & fstack [ i ] , 0 , sizeof ( fstack [ i ] ) ) ;
cpus = cpu ;
}
for ( i = 0 ; i < fstack [ cpu ] . size & & fstack [ cpu ] . stack [ i ] ; i + + ) {
if ( strcmp ( parent , fstack [ cpu ] . stack [ i ] ) = = 0 ) {
add_child ( & fstack [ cpu ] , child , i + 1 ) ;
return i ;
}
}
/* Not found */
add_child ( & fstack [ cpu ] , parent , 0 ) ;
add_child ( & fstack [ cpu ] , child , 1 ) ;
return 0 ;
}
2018-08-08 14:02:47 -04:00
static int function_handler ( struct trace_seq * s , struct tep_record * record ,
2013-12-03 14:09:32 +01:00
struct event_format * event , void * context )
{
2018-08-08 14:02:46 -04:00
struct tep_handle * pevent = event - > pevent ;
2013-12-03 14:09:32 +01:00
unsigned long long function ;
unsigned long long pfunction ;
const char * func ;
const char * parent ;
2017-02-13 13:33:57 -03:00
int index = 0 ;
2013-12-03 14:09:32 +01:00
2018-08-08 14:03:04 -04:00
if ( tep_get_field_val ( s , event , " ip " , record , & function , 1 ) )
2013-12-03 14:09:32 +01:00
return trace_seq_putc ( s , ' ! ' ) ;
func = pevent_find_function ( pevent , function ) ;
2018-08-08 14:03:04 -04:00
if ( tep_get_field_val ( s , event , " parent_ip " , record , & pfunction , 1 ) )
2013-12-03 14:09:32 +01:00
return trace_seq_putc ( s , ' ! ' ) ;
parent = pevent_find_function ( pevent , pfunction ) ;
2014-06-02 23:20:15 -04:00
if ( parent & & ftrace_indent - > set )
index = add_and_get_index ( parent , func , record - > cpu ) ;
2013-12-03 14:09:32 +01:00
2013-12-03 14:09:39 +01:00
trace_seq_printf ( s , " %*s " , index * 3 , " " ) ;
2013-12-03 14:09:32 +01:00
if ( func )
trace_seq_printf ( s , " %s " , func ) ;
else
trace_seq_printf ( s , " 0x%llx " , function ) ;
2014-06-02 23:20:15 -04:00
if ( ftrace_parent - > set ) {
trace_seq_printf ( s , " <-- " ) ;
if ( parent )
trace_seq_printf ( s , " %s " , parent ) ;
else
trace_seq_printf ( s , " 0x%llx " , pfunction ) ;
}
2013-12-03 14:09:32 +01:00
return 0 ;
}
2018-08-08 14:02:48 -04:00
int TEP_PLUGIN_LOADER ( struct tep_handle * pevent )
2013-12-03 14:09:32 +01:00
{
2018-08-08 14:03:02 -04:00
tep_register_event_handler ( pevent , - 1 , " ftrace " , " function " ,
function_handler , NULL ) ;
2014-06-02 23:20:15 -04:00
2018-08-08 14:03:00 -04:00
tep_plugin_add_options ( " ftrace " , plugin_options ) ;
2014-06-02 23:20:15 -04:00
2013-12-03 14:09:32 +01:00
return 0 ;
}
2018-08-08 14:02:48 -04:00
void TEP_PLUGIN_UNLOADER ( struct tep_handle * pevent )
2013-12-03 14:09:32 +01:00
{
int i , x ;
2018-08-08 14:03:02 -04:00
tep_unregister_event_handler ( pevent , - 1 , " ftrace " , " function " ,
function_handler , NULL ) ;
2014-01-16 11:31:09 +09:00
2013-12-03 14:09:32 +01:00
for ( i = 0 ; i < = cpus ; i + + ) {
for ( x = 0 ; x < fstack [ i ] . size & & fstack [ i ] . stack [ x ] ; x + + )
free ( fstack [ i ] . stack [ x ] ) ;
free ( fstack [ i ] . stack ) ;
}
2018-08-08 14:03:00 -04:00
tep_plugin_remove_options ( plugin_options ) ;
2014-06-02 23:20:15 -04:00
2013-12-03 14:09:32 +01:00
free ( fstack ) ;
fstack = NULL ;
cpus = - 1 ;
}