2008-12-24 07:24:12 +03:00
/*
* trace_output . c
*
* Copyright ( C ) 2008 Red Hat Inc , Steven Rostedt < srostedt @ redhat . com >
*
*/
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/ftrace.h>
# include "trace_output.h"
/* must be a power of 2 */
# define EVENT_HASHSIZE 128
2009-05-18 15:35:34 +04:00
static DECLARE_RWSEM ( trace_event_mutex ) ;
2009-05-26 22:25:22 +04:00
DEFINE_PER_CPU ( struct trace_seq , ftrace_event_seq ) ;
2009-06-01 18:53:35 +04:00
EXPORT_PER_CPU_SYMBOL ( ftrace_event_seq ) ;
2009-05-26 22:25:22 +04:00
2008-12-24 07:24:12 +03:00
static struct hlist_head event_hash [ EVENT_HASHSIZE ] __read_mostly ;
static int next_event_type = __TRACE_LAST_TYPE + 1 ;
2009-03-24 06:12:58 +03:00
void trace_print_seq ( struct seq_file * m , struct trace_seq * s )
{
int len = s - > len > = PAGE_SIZE ? PAGE_SIZE - 1 : s - > len ;
s - > buffer [ len ] = 0 ;
seq_puts ( m , s - > buffer ) ;
trace_seq_init ( s ) ;
}
2009-03-19 19:20:38 +03:00
enum print_line_t trace_print_bprintk_msg_only ( struct trace_iterator * iter )
{
struct trace_seq * s = & iter - > seq ;
struct trace_entry * entry = iter - > ent ;
struct bprint_entry * field ;
int ret ;
trace_assign_type ( field , entry ) ;
ret = trace_seq_bprintf ( s , field - > fmt , field - > buf ) ;
if ( ! ret )
return TRACE_TYPE_PARTIAL_LINE ;
return TRACE_TYPE_HANDLED ;
}
enum print_line_t trace_print_printk_msg_only ( struct trace_iterator * iter )
{
struct trace_seq * s = & iter - > seq ;
struct trace_entry * entry = iter - > ent ;
struct print_entry * field ;
int ret ;
trace_assign_type ( field , entry ) ;
ret = trace_seq_printf ( s , " %s " , field - > buf ) ;
if ( ! ret )
return TRACE_TYPE_PARTIAL_LINE ;
return TRACE_TYPE_HANDLED ;
}
2008-12-24 07:24:12 +03:00
/**
* trace_seq_printf - sequence printing of trace information
* @ s : trace sequence descriptor
* @ fmt : printf format string
*
* The tracer may use either sequence operations or its own
* copy to user routines . To simplify formating of a trace
* trace_seq_printf is used to store strings into a special
* buffer ( @ s ) . Then the output may be either used by
* the sequencer or pulled into another buffer .
*/
int
trace_seq_printf ( struct trace_seq * s , const char * fmt , . . . )
{
int len = ( PAGE_SIZE - 1 ) - s - > len ;
va_list ap ;
int ret ;
if ( ! len )
return 0 ;
va_start ( ap , fmt ) ;
ret = vsnprintf ( s - > buffer + s - > len , len , fmt , ap ) ;
va_end ( ap ) ;
/* If we can't write it all, don't bother writing anything */
if ( ret > = len )
return 0 ;
s - > len + = ret ;
return len ;
}
2009-04-11 02:12:50 +04:00
EXPORT_SYMBOL_GPL ( trace_seq_printf ) ;
2008-12-24 07:24:12 +03:00
2009-03-06 19:21:49 +03:00
int trace_seq_bprintf ( struct trace_seq * s , const char * fmt , const u32 * binary )
2009-03-06 19:21:47 +03:00
{
int len = ( PAGE_SIZE - 1 ) - s - > len ;
int ret ;
if ( ! len )
return 0 ;
ret = bstr_printf ( s - > buffer + s - > len , len , fmt , binary ) ;
/* If we can't write it all, don't bother writing anything */
if ( ret > = len )
return 0 ;
s - > len + = ret ;
return len ;
}
2008-12-24 07:24:12 +03:00
/**
* trace_seq_puts - trace sequence printing of simple string
* @ s : trace sequence descriptor
* @ str : simple string to record
*
* The tracer may use either the sequence operations or its own
* copy to user routines . This function records a simple string
* into a special buffer ( @ s ) for later retrieval by a sequencer
* or other mechanism .
*/
int trace_seq_puts ( struct trace_seq * s , const char * str )
{
int len = strlen ( str ) ;
if ( len > ( ( PAGE_SIZE - 1 ) - s - > len ) )
return 0 ;
memcpy ( s - > buffer + s - > len , str , len ) ;
s - > len + = len ;
return len ;
}
int trace_seq_putc ( struct trace_seq * s , unsigned char c )
{
if ( s - > len > = ( PAGE_SIZE - 1 ) )
return 0 ;
s - > buffer [ s - > len + + ] = c ;
return 1 ;
}
2009-03-27 05:21:00 +03:00
int trace_seq_putmem ( struct trace_seq * s , const void * mem , size_t len )
2008-12-24 07:24:12 +03:00
{
if ( len > ( ( PAGE_SIZE - 1 ) - s - > len ) )
return 0 ;
memcpy ( s - > buffer + s - > len , mem , len ) ;
s - > len + = len ;
return len ;
}
2009-03-27 05:21:00 +03:00
int trace_seq_putmem_hex ( struct trace_seq * s , const void * mem , size_t len )
2008-12-24 07:24:12 +03:00
{
unsigned char hex [ HEX_CHARS ] ;
2009-03-27 05:21:00 +03:00
const unsigned char * data = mem ;
2008-12-24 07:24:12 +03:00
int i , j ;
# ifdef __BIG_ENDIAN
for ( i = 0 , j = 0 ; i < len ; i + + ) {
# else
for ( i = len - 1 , j = 0 ; i > = 0 ; i - - ) {
# endif
hex [ j + + ] = hex_asc_hi ( data [ i ] ) ;
hex [ j + + ] = hex_asc_lo ( data [ i ] ) ;
}
hex [ j + + ] = ' ' ;
return trace_seq_putmem ( s , hex , j ) ;
}
2009-03-23 16:12:22 +03:00
void * trace_seq_reserve ( struct trace_seq * s , size_t len )
{
void * ret ;
if ( len > ( ( PAGE_SIZE - 1 ) - s - > len ) )
return NULL ;
ret = s - > buffer + s - > len ;
s - > len + = len ;
return ret ;
}
2008-12-24 07:24:12 +03:00
int trace_seq_path ( struct trace_seq * s , struct path * path )
{
unsigned char * p ;
if ( s - > len > = ( PAGE_SIZE - 1 ) )
return 0 ;
p = d_path ( path , s - > buffer + s - > len , PAGE_SIZE - s - > len ) ;
if ( ! IS_ERR ( p ) ) {
p = mangle_path ( s - > buffer + s - > len , p , " \n " ) ;
if ( p ) {
s - > len = p - s - > buffer ;
return 1 ;
}
} else {
s - > buffer [ s - > len + + ] = ' ? ' ;
return 1 ;
}
return 0 ;
}
2009-05-26 22:25:22 +04:00
const char *
ftrace_print_flags_seq ( struct trace_seq * p , const char * delim ,
unsigned long flags ,
const struct trace_print_flags * flag_array )
{
unsigned long mask ;
const char * str ;
int i ;
trace_seq_init ( p ) ;
for ( i = 0 ; flag_array [ i ] . name & & flags ; i + + ) {
mask = flag_array [ i ] . mask ;
if ( ( flags & mask ) ! = mask )
continue ;
str = flag_array [ i ] . name ;
flags & = ~ mask ;
if ( p - > len & & delim )
trace_seq_puts ( p , delim ) ;
trace_seq_puts ( p , str ) ;
}
/* check for left over flags */
if ( flags ) {
if ( p - > len & & delim )
trace_seq_puts ( p , delim ) ;
trace_seq_printf ( p , " 0x%lx " , flags ) ;
}
trace_seq_putc ( p , 0 ) ;
return p - > buffer ;
}
2009-06-01 18:53:35 +04:00
EXPORT_SYMBOL ( ftrace_print_flags_seq ) ;
2009-05-26 22:25:22 +04:00
2009-05-21 03:21:47 +04:00
const char *
ftrace_print_symbols_seq ( struct trace_seq * p , unsigned long val ,
const struct trace_print_flags * symbol_array )
{
int i ;
trace_seq_init ( p ) ;
for ( i = 0 ; symbol_array [ i ] . name ; i + + ) {
if ( val ! = symbol_array [ i ] . mask )
continue ;
trace_seq_puts ( p , symbol_array [ i ] . name ) ;
break ;
}
if ( ! p - > len )
trace_seq_printf ( p , " 0x%lx " , val ) ;
trace_seq_putc ( p , 0 ) ;
return p - > buffer ;
}
2009-06-01 18:53:35 +04:00
EXPORT_SYMBOL ( ftrace_print_symbols_seq ) ;
2009-05-21 03:21:47 +04:00
2008-12-24 07:24:12 +03:00
# ifdef CONFIG_KRETPROBES
static inline const char * kretprobed ( const char * name )
{
static const char tramp_name [ ] = " kretprobe_trampoline " ;
int size = sizeof ( tramp_name ) ;
if ( strncmp ( tramp_name , name , size ) = = 0 )
return " [unknown/kretprobe'd] " ;
return name ;
}
# else
static inline const char * kretprobed ( const char * name )
{
return name ;
}
# endif /* CONFIG_KRETPROBES */
static int
seq_print_sym_short ( struct trace_seq * s , const char * fmt , unsigned long address )
{
# ifdef CONFIG_KALLSYMS
char str [ KSYM_SYMBOL_LEN ] ;
const char * name ;
kallsyms_lookup ( address , NULL , NULL , NULL , str ) ;
name = kretprobed ( str ) ;
return trace_seq_printf ( s , fmt , name ) ;
# endif
return 1 ;
}
static int
seq_print_sym_offset ( struct trace_seq * s , const char * fmt ,
unsigned long address )
{
# ifdef CONFIG_KALLSYMS
char str [ KSYM_SYMBOL_LEN ] ;
const char * name ;
sprint_symbol ( str , address ) ;
name = kretprobed ( str ) ;
return trace_seq_printf ( s , fmt , name ) ;
# endif
return 1 ;
}
# ifndef CONFIG_64BIT
# define IP_FMT "%08lx"
# else
# define IP_FMT "%016lx"
# endif
int seq_print_user_ip ( struct trace_seq * s , struct mm_struct * mm ,
unsigned long ip , unsigned long sym_flags )
{
struct file * file = NULL ;
unsigned long vmstart = 0 ;
int ret = 1 ;
if ( mm ) {
const struct vm_area_struct * vma ;
down_read ( & mm - > mmap_sem ) ;
vma = find_vma ( mm , ip ) ;
if ( vma ) {
file = vma - > vm_file ;
vmstart = vma - > vm_start ;
}
if ( file ) {
ret = trace_seq_path ( s , & file - > f_path ) ;
if ( ret )
ret = trace_seq_printf ( s , " [+0x%lx] " ,
ip - vmstart ) ;
}
up_read ( & mm - > mmap_sem ) ;
}
if ( ret & & ( ( sym_flags & TRACE_ITER_SYM_ADDR ) | | ! file ) )
ret = trace_seq_printf ( s , " < " IP_FMT " > " , ip ) ;
return ret ;
}
int
seq_print_userip_objs ( const struct userstack_entry * entry , struct trace_seq * s ,
unsigned long sym_flags )
{
struct mm_struct * mm = NULL ;
int ret = 1 ;
unsigned int i ;
if ( trace_flags & TRACE_ITER_SYM_USEROBJ ) {
struct task_struct * task ;
/*
* we do the lookup on the thread group leader ,
* since individual threads might have already quit !
*/
rcu_read_lock ( ) ;
task = find_task_by_vpid ( entry - > ent . tgid ) ;
if ( task )
mm = get_task_mm ( task ) ;
rcu_read_unlock ( ) ;
}
for ( i = 0 ; i < FTRACE_STACK_ENTRIES ; i + + ) {
unsigned long ip = entry - > caller [ i ] ;
if ( ip = = ULONG_MAX | | ! ret )
break ;
2009-06-03 12:01:30 +04:00
if ( ret )
ret = trace_seq_puts ( s , " => " ) ;
2008-12-24 07:24:12 +03:00
if ( ! ip ) {
if ( ret )
ret = trace_seq_puts ( s , " ?? " ) ;
2009-06-03 12:01:30 +04:00
if ( ret )
ret = trace_seq_puts ( s , " \n " ) ;
2008-12-24 07:24:12 +03:00
continue ;
}
if ( ! ret )
break ;
if ( ret )
ret = seq_print_user_ip ( s , mm , ip , sym_flags ) ;
2009-06-03 12:01:30 +04:00
ret = trace_seq_puts ( s , " \n " ) ;
2008-12-24 07:24:12 +03:00
}
if ( mm )
mmput ( mm ) ;
return ret ;
}
int
seq_print_ip_sym ( struct trace_seq * s , unsigned long ip , unsigned long sym_flags )
{
int ret ;
if ( ! ip )
return trace_seq_printf ( s , " 0 " ) ;
if ( sym_flags & TRACE_ITER_SYM_OFFSET )
ret = seq_print_sym_offset ( s , " %s " , ip ) ;
else
ret = seq_print_sym_short ( s , " %s " , ip ) ;
if ( ! ret )
return 0 ;
if ( sym_flags & TRACE_ITER_SYM_ADDR )
ret = trace_seq_printf ( s , " < " IP_FMT " > " , ip ) ;
return ret ;
}
2009-02-04 01:20:41 +03:00
static int
2009-02-03 01:29:21 +03:00
lat_print_generic ( struct trace_seq * s , struct trace_entry * entry , int cpu )
{
int hardirq , softirq ;
2009-03-17 02:20:15 +03:00
char comm [ TASK_COMM_LEN ] ;
2009-02-03 01:29:21 +03:00
2009-03-17 02:20:15 +03:00
trace_find_cmdline ( entry - > pid , comm ) ;
2009-02-03 01:29:21 +03:00
hardirq = entry - > flags & TRACE_FLAG_HARDIRQ ;
softirq = entry - > flags & TRACE_FLAG_SOFTIRQ ;
2009-02-04 01:20:41 +03:00
if ( ! trace_seq_printf ( s , " %8.8s-%-5d %3d%c%c%c " ,
comm , entry - > pid , cpu ,
( entry - > flags & TRACE_FLAG_IRQS_OFF ) ? ' d ' :
( entry - > flags & TRACE_FLAG_IRQS_NOSUPPORT ) ?
' X ' : ' . ' ,
( entry - > flags & TRACE_FLAG_NEED_RESCHED ) ?
' N ' : ' . ' ,
( hardirq & & softirq ) ? ' H ' :
hardirq ? ' h ' : softirq ? ' s ' : ' . ' ) )
return 0 ;
2009-02-03 01:29:21 +03:00
if ( entry - > preempt_count )
2009-02-04 01:20:41 +03:00
return trace_seq_printf ( s , " %x " , entry - > preempt_count ) ;
return trace_seq_puts ( s , " . " ) ;
2009-02-03 01:29:21 +03:00
}
static unsigned long preempt_mark_thresh = 100 ;
2009-02-04 01:20:41 +03:00
static int
2009-02-03 01:29:21 +03:00
lat_print_timestamp ( struct trace_seq * s , u64 abs_usecs ,
unsigned long rel_usecs )
{
2009-02-04 01:20:41 +03:00
return trace_seq_printf ( s , " %4lldus%c: " , abs_usecs ,
rel_usecs > preempt_mark_thresh ? ' ! ' :
rel_usecs > 1 ? ' + ' : ' ' ) ;
2009-02-03 01:29:21 +03:00
}
int trace_print_context ( struct trace_iterator * iter )
{
struct trace_seq * s = & iter - > seq ;
struct trace_entry * entry = iter - > ent ;
unsigned long long t = ns2usecs ( iter - > ts ) ;
unsigned long usec_rem = do_div ( t , USEC_PER_SEC ) ;
unsigned long secs = ( unsigned long ) t ;
2009-03-17 02:20:15 +03:00
char comm [ TASK_COMM_LEN ] ;
trace_find_cmdline ( entry - > pid , comm ) ;
2009-02-03 01:29:21 +03:00
2009-02-04 01:20:41 +03:00
return trace_seq_printf ( s , " %16s-%-5d [%03d] %5lu.%06lu: " ,
2009-02-08 03:38:43 +03:00
comm , entry - > pid , iter - > cpu , secs , usec_rem ) ;
2009-02-03 01:29:21 +03:00
}
int trace_print_lat_context ( struct trace_iterator * iter )
{
u64 next_ts ;
2009-02-04 01:20:41 +03:00
int ret ;
2009-02-03 01:29:21 +03:00
struct trace_seq * s = & iter - > seq ;
struct trace_entry * entry = iter - > ent ,
* next_entry = trace_find_next_entry ( iter , NULL ,
& next_ts ) ;
unsigned long verbose = ( trace_flags & TRACE_ITER_VERBOSE ) ;
unsigned long abs_usecs = ns2usecs ( iter - > ts - iter - > tr - > time_start ) ;
unsigned long rel_usecs ;
if ( ! next_entry )
next_ts = iter - > ts ;
rel_usecs = ns2usecs ( next_ts - iter - > ts ) ;
if ( verbose ) {
2009-03-17 02:20:15 +03:00
char comm [ TASK_COMM_LEN ] ;
trace_find_cmdline ( entry - > pid , comm ) ;
2009-03-30 09:48:00 +04:00
ret = trace_seq_printf ( s , " %16s %5d %3d %d %08x %08lx [%08llx] "
2009-02-04 01:20:41 +03:00
" %ld.%03ldms (+%ld.%03ldms): " , comm ,
2009-02-08 03:38:43 +03:00
entry - > pid , iter - > cpu , entry - > flags ,
2009-02-04 01:20:41 +03:00
entry - > preempt_count , iter - > idx ,
ns2usecs ( iter - > ts ) ,
abs_usecs / USEC_PER_MSEC ,
abs_usecs % USEC_PER_MSEC ,
rel_usecs / USEC_PER_MSEC ,
rel_usecs % USEC_PER_MSEC ) ;
2009-02-03 01:29:21 +03:00
} else {
2009-02-08 03:38:43 +03:00
ret = lat_print_generic ( s , entry , iter - > cpu ) ;
2009-02-04 01:20:41 +03:00
if ( ret )
ret = lat_print_timestamp ( s , abs_usecs , rel_usecs ) ;
2009-02-03 01:29:21 +03:00
}
2009-02-04 01:20:41 +03:00
return ret ;
2009-02-03 01:29:21 +03:00
}
2008-12-24 07:24:13 +03:00
static const char state_to_char [ ] = TASK_STATE_TO_CHAR_STR ;
static int task_state_char ( unsigned long state )
{
int bit = state ? __ffs ( state ) + 1 : 0 ;
return bit < sizeof ( state_to_char ) - 1 ? state_to_char [ bit ] : ' ? ' ;
}
2008-12-24 07:24:12 +03:00
/**
* ftrace_find_event - find a registered event
* @ type : the type of event to look for
*
* Returns an event of type @ type otherwise NULL
2009-05-18 15:35:34 +04:00
* Called with trace_event_read_lock ( ) held .
2008-12-24 07:24:12 +03:00
*/
struct trace_event * ftrace_find_event ( int type )
{
struct trace_event * event ;
struct hlist_node * n ;
unsigned key ;
key = type & ( EVENT_HASHSIZE - 1 ) ;
2009-05-18 15:35:34 +04:00
hlist_for_each_entry ( event , n , & event_hash [ key ] , node ) {
2008-12-24 07:24:12 +03:00
if ( event - > type = = type )
return event ;
}
return NULL ;
}
2009-04-24 20:20:52 +04:00
static LIST_HEAD ( ftrace_event_list ) ;
static int trace_search_list ( struct list_head * * list )
{
struct trace_event * e ;
int last = __TRACE_LAST_TYPE ;
if ( list_empty ( & ftrace_event_list ) ) {
* list = & ftrace_event_list ;
return last + 1 ;
}
/*
* We used up all possible max events ,
* lets see if somebody freed one .
*/
list_for_each_entry ( e , & ftrace_event_list , list ) {
if ( e - > type ! = last + 1 )
break ;
last + + ;
}
/* Did we used up all 65 thousand events??? */
if ( ( last + 1 ) > FTRACE_MAX_EVENT )
return 0 ;
* list = & e - > list ;
return last + 1 ;
}
2009-05-18 15:35:34 +04:00
void trace_event_read_lock ( void )
{
down_read ( & trace_event_mutex ) ;
}
void trace_event_read_unlock ( void )
{
up_read ( & trace_event_mutex ) ;
}
2008-12-24 07:24:12 +03:00
/**
* register_ftrace_event - register output for an event type
* @ event : the event type to register
*
* Event types are stored in a hash and this hash is used to
* find a way to print an event . If the @ event - > type is set
* then it will use that type , otherwise it will assign a
* type to use .
*
* If you assign your own type , please make sure it is added
* to the trace_type enum in trace . h , to avoid collisions
* with the dynamic types .
*
* Returns the event type number or zero on error .
*/
int register_ftrace_event ( struct trace_event * event )
{
unsigned key ;
int ret = 0 ;
2009-05-18 15:35:34 +04:00
down_write ( & trace_event_mutex ) ;
2008-12-24 07:24:12 +03:00
2009-04-24 20:20:52 +04:00
if ( WARN_ON ( ! event ) )
2009-03-19 22:26:14 +03:00
goto out ;
2009-04-24 20:20:52 +04:00
INIT_LIST_HEAD ( & event - > list ) ;
if ( ! event - > type ) {
2009-05-06 14:15:45 +04:00
struct list_head * list = NULL ;
2009-04-24 20:20:52 +04:00
if ( next_event_type > FTRACE_MAX_EVENT ) {
event - > type = trace_search_list ( & list ) ;
if ( ! event - > type )
goto out ;
} else {
event - > type = next_event_type + + ;
list = & ftrace_event_list ;
}
if ( WARN_ON ( ftrace_find_event ( event - > type ) ) )
goto out ;
list_add_tail ( & event - > list , list ) ;
} else if ( event - > type > __TRACE_LAST_TYPE ) {
2008-12-24 07:24:12 +03:00
printk ( KERN_WARNING " Need to add type to trace.h \n " ) ;
WARN_ON ( 1 ) ;
goto out ;
2009-04-24 20:20:52 +04:00
} else {
/* Is this event already used */
if ( ftrace_find_event ( event - > type ) )
goto out ;
}
2008-12-24 07:24:12 +03:00
2009-02-05 01:16:39 +03:00
if ( event - > trace = = NULL )
event - > trace = trace_nop_print ;
if ( event - > raw = = NULL )
event - > raw = trace_nop_print ;
if ( event - > hex = = NULL )
event - > hex = trace_nop_print ;
if ( event - > binary = = NULL )
event - > binary = trace_nop_print ;
2008-12-24 07:24:12 +03:00
key = event - > type & ( EVENT_HASHSIZE - 1 ) ;
2009-05-18 15:35:34 +04:00
hlist_add_head ( & event - > node , & event_hash [ key ] ) ;
2008-12-24 07:24:12 +03:00
ret = event - > type ;
out :
2009-05-18 15:35:34 +04:00
up_write ( & trace_event_mutex ) ;
2008-12-24 07:24:12 +03:00
return ret ;
}
2009-04-11 02:12:50 +04:00
EXPORT_SYMBOL_GPL ( register_ftrace_event ) ;
2008-12-24 07:24:12 +03:00
/**
* unregister_ftrace_event - remove a no longer used event
* @ event : the event to remove
*/
int unregister_ftrace_event ( struct trace_event * event )
{
2009-05-18 15:35:34 +04:00
down_write ( & trace_event_mutex ) ;
2008-12-24 07:24:12 +03:00
hlist_del ( & event - > node ) ;
2009-04-24 20:20:52 +04:00
list_del ( & event - > list ) ;
2009-05-18 15:35:34 +04:00
up_write ( & trace_event_mutex ) ;
2008-12-24 07:24:12 +03:00
return 0 ;
}
2009-04-11 02:12:50 +04:00
EXPORT_SYMBOL_GPL ( unregister_ftrace_event ) ;
2008-12-24 07:24:13 +03:00
/*
* Standard events
*/
2009-02-04 03:05:50 +03:00
enum print_line_t trace_nop_print ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
/* TRACE_FN */
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_fn_trace ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
struct ftrace_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
if ( ! seq_print_ip_sym ( s , field - > ip , flags ) )
goto partial ;
if ( ( flags & TRACE_ITER_PRINT_PARENT ) & & field - > parent_ip ) {
if ( ! trace_seq_printf ( s , " <- " ) )
goto partial ;
if ( ! seq_print_ip_sym ( s ,
field - > parent_ip ,
flags ) )
goto partial ;
}
if ( ! trace_seq_printf ( s , " \n " ) )
goto partial ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_fn_raw ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
struct ftrace_entry * field ;
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
if ( ! trace_seq_printf ( & iter - > seq , " %lx %lx \n " ,
2009-01-15 13:05:40 +03:00
field - > ip ,
field - > parent_ip ) )
2008-12-24 07:24:13 +03:00
return TRACE_TYPE_PARTIAL_LINE ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_fn_hex ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
struct ftrace_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
SEQ_PUT_HEX_FIELD_RET ( s , field - > ip ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > parent_ip ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_fn_bin ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
struct ftrace_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
SEQ_PUT_FIELD_RET ( s , field - > ip ) ;
SEQ_PUT_FIELD_RET ( s , field - > parent_ip ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
static struct trace_event trace_fn_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_FN ,
2008-12-24 07:24:13 +03:00
. trace = trace_fn_trace ,
. raw = trace_fn_raw ,
. hex = trace_fn_hex ,
. binary = trace_fn_bin ,
} ;
/* TRACE_CTX an TRACE_WAKE */
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_ctxwake_print ( struct trace_iterator * iter ,
char * delim )
2008-12-24 07:24:13 +03:00
{
struct ctx_switch_entry * field ;
2009-03-17 02:20:15 +03:00
char comm [ TASK_COMM_LEN ] ;
2008-12-24 07:24:13 +03:00
int S , T ;
2009-03-17 02:20:15 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
T = task_state_char ( field - > next_state ) ;
S = task_state_char ( field - > prev_state ) ;
2009-03-17 02:20:15 +03:00
trace_find_cmdline ( field - > next_pid , comm ) ;
2009-02-03 01:30:12 +03:00
if ( ! trace_seq_printf ( & iter - > seq ,
" %5d:%3d:%c %s [%03d] %5d:%3d:%c %s \n " ,
2009-01-15 13:05:40 +03:00
field - > prev_pid ,
field - > prev_prio ,
S , delim ,
field - > next_cpu ,
field - > next_pid ,
field - > next_prio ,
T , comm ) )
2008-12-24 07:24:13 +03:00
return TRACE_TYPE_PARTIAL_LINE ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_ctx_print ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_print ( iter , " ==> " ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_wake_print ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_print ( iter , " + " ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-03 01:30:12 +03:00
static int trace_ctxwake_raw ( struct trace_iterator * iter , char S )
2008-12-24 07:24:13 +03:00
{
struct ctx_switch_entry * field ;
int T ;
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
if ( ! S )
task_state_char ( field - > prev_state ) ;
T = task_state_char ( field - > next_state ) ;
2009-02-03 01:30:12 +03:00
if ( ! trace_seq_printf ( & iter - > seq , " %d %d %c %d %d %d %c \n " ,
2009-01-15 13:05:40 +03:00
field - > prev_pid ,
field - > prev_prio ,
S ,
field - > next_cpu ,
field - > next_pid ,
field - > next_prio ,
T ) )
2008-12-24 07:24:13 +03:00
return TRACE_TYPE_PARTIAL_LINE ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_ctx_raw ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_raw ( iter , 0 ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_wake_raw ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_raw ( iter , ' + ' ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-03 01:30:12 +03:00
static int trace_ctxwake_hex ( struct trace_iterator * iter , char S )
2008-12-24 07:24:13 +03:00
{
struct ctx_switch_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
int T ;
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
if ( ! S )
task_state_char ( field - > prev_state ) ;
T = task_state_char ( field - > next_state ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > prev_pid ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > prev_prio ) ;
SEQ_PUT_HEX_FIELD_RET ( s , S ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > next_cpu ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > next_pid ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > next_prio ) ;
SEQ_PUT_HEX_FIELD_RET ( s , T ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_ctx_hex ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_hex ( iter , 0 ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_wake_hex ( struct trace_iterator * iter , int flags )
2008-12-24 07:24:13 +03:00
{
2009-02-03 01:30:12 +03:00
return trace_ctxwake_hex ( iter , ' + ' ) ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_ctxwake_bin ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct ctx_switch_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
SEQ_PUT_FIELD_RET ( s , field - > prev_pid ) ;
SEQ_PUT_FIELD_RET ( s , field - > prev_prio ) ;
SEQ_PUT_FIELD_RET ( s , field - > prev_state ) ;
SEQ_PUT_FIELD_RET ( s , field - > next_pid ) ;
SEQ_PUT_FIELD_RET ( s , field - > next_prio ) ;
SEQ_PUT_FIELD_RET ( s , field - > next_state ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
static struct trace_event trace_ctx_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_CTX ,
2008-12-24 07:24:13 +03:00
. trace = trace_ctx_print ,
. raw = trace_ctx_raw ,
. hex = trace_ctx_hex ,
. binary = trace_ctxwake_bin ,
} ;
static struct trace_event trace_wake_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_WAKE ,
2008-12-24 07:24:13 +03:00
. trace = trace_wake_print ,
. raw = trace_wake_raw ,
. hex = trace_wake_hex ,
. binary = trace_ctxwake_bin ,
} ;
/* TRACE_SPECIAL */
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_special_print ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct special_entry * field ;
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
if ( ! trace_seq_printf ( & iter - > seq , " # %ld %ld %ld \n " ,
2009-01-15 13:05:40 +03:00
field - > arg1 ,
field - > arg2 ,
field - > arg3 ) )
2008-12-24 07:24:13 +03:00
return TRACE_TYPE_PARTIAL_LINE ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_special_hex ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct special_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
SEQ_PUT_HEX_FIELD_RET ( s , field - > arg1 ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > arg2 ) ;
SEQ_PUT_HEX_FIELD_RET ( s , field - > arg3 ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_special_bin ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct special_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
SEQ_PUT_FIELD_RET ( s , field - > arg1 ) ;
SEQ_PUT_FIELD_RET ( s , field - > arg2 ) ;
SEQ_PUT_FIELD_RET ( s , field - > arg3 ) ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
}
static struct trace_event trace_special_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_SPECIAL ,
2008-12-24 07:24:13 +03:00
. trace = trace_special_print ,
. raw = trace_special_print ,
. hex = trace_special_hex ,
. binary = trace_special_bin ,
} ;
/* TRACE_STACK */
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_stack_print ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct stack_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
int i ;
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
2009-06-03 12:01:29 +04:00
if ( ! trace_seq_puts ( s , " \n " ) )
goto partial ;
2008-12-24 07:24:13 +03:00
for ( i = 0 ; i < FTRACE_STACK_ENTRIES ; i + + ) {
2009-06-03 12:01:29 +04:00
if ( ! field - > caller [ i ] | | ( field - > caller [ i ] = = ULONG_MAX ) )
2009-05-15 07:40:06 +04:00
break ;
2009-06-03 12:01:29 +04:00
if ( ! trace_seq_puts ( s , " => " ) )
goto partial ;
2008-12-24 07:24:13 +03:00
2009-06-03 12:01:29 +04:00
if ( ! seq_print_ip_sym ( s , field - > caller [ i ] , flags ) )
goto partial ;
2009-01-15 13:05:40 +03:00
if ( ! trace_seq_puts ( s , " \n " ) )
2008-12-24 07:24:13 +03:00
goto partial ;
}
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
static struct trace_event trace_stack_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_STACK ,
2008-12-24 07:24:13 +03:00
. trace = trace_stack_print ,
. raw = trace_special_print ,
. hex = trace_special_hex ,
. binary = trace_special_bin ,
} ;
/* TRACE_USER_STACK */
2009-02-04 03:05:50 +03:00
static enum print_line_t trace_user_stack_print ( struct trace_iterator * iter ,
int flags )
2008-12-24 07:24:13 +03:00
{
struct userstack_entry * field ;
2009-02-03 01:30:12 +03:00
struct trace_seq * s = & iter - > seq ;
2008-12-24 07:24:13 +03:00
2009-02-03 01:30:12 +03:00
trace_assign_type ( field , iter - > ent ) ;
2008-12-24 07:24:13 +03:00
2009-06-03 12:01:30 +04:00
if ( ! trace_seq_putc ( s , ' \n ' ) )
2008-12-24 07:24:13 +03:00
goto partial ;
2009-06-03 12:01:30 +04:00
if ( ! seq_print_userip_objs ( field , s , flags ) )
2008-12-24 07:24:13 +03:00
goto partial ;
2009-02-04 01:20:41 +03:00
return TRACE_TYPE_HANDLED ;
2008-12-24 07:24:13 +03:00
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
static struct trace_event trace_user_stack_event = {
2009-03-10 21:10:56 +03:00
. type = TRACE_USER_STACK ,
2008-12-24 07:24:13 +03:00
. trace = trace_user_stack_print ,
. raw = trace_special_print ,
. hex = trace_special_hex ,
. binary = trace_special_bin ,
} ;
2009-03-12 20:24:49 +03:00
/* TRACE_BPRINT */
2009-03-06 19:21:47 +03:00
static enum print_line_t
2009-03-12 20:24:49 +03:00
trace_bprint_print ( struct trace_iterator * iter , int flags )
2009-03-06 19:21:47 +03:00
{
struct trace_entry * entry = iter - > ent ;
struct trace_seq * s = & iter - > seq ;
2009-03-12 20:24:49 +03:00
struct bprint_entry * field ;
2009-03-06 19:21:47 +03:00
trace_assign_type ( field , entry ) ;
if ( ! seq_print_ip_sym ( s , field - > ip , flags ) )
goto partial ;
if ( ! trace_seq_puts ( s , " : " ) )
goto partial ;
if ( ! trace_seq_bprintf ( s , field - > fmt , field - > buf ) )
goto partial ;
return TRACE_TYPE_HANDLED ;
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
2009-03-06 19:21:49 +03:00
2009-03-12 20:24:49 +03:00
static enum print_line_t
trace_bprint_raw ( struct trace_iterator * iter , int flags )
2009-03-06 19:21:47 +03:00
{
2009-03-12 20:24:49 +03:00
struct bprint_entry * field ;
2009-03-06 19:21:47 +03:00
struct trace_seq * s = & iter - > seq ;
2009-03-06 19:21:49 +03:00
trace_assign_type ( field , iter - > ent ) ;
2009-03-06 19:21:47 +03:00
if ( ! trace_seq_printf ( s , " : %lx : " , field - > ip ) )
goto partial ;
if ( ! trace_seq_bprintf ( s , field - > fmt , field - > buf ) )
goto partial ;
return TRACE_TYPE_HANDLED ;
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
2009-03-06 19:21:49 +03:00
2009-03-12 20:24:49 +03:00
static struct trace_event trace_bprint_event = {
. type = TRACE_BPRINT ,
. trace = trace_bprint_print ,
. raw = trace_bprint_raw ,
} ;
/* TRACE_PRINT */
static enum print_line_t trace_print_print ( struct trace_iterator * iter ,
int flags )
{
struct print_entry * field ;
struct trace_seq * s = & iter - > seq ;
trace_assign_type ( field , iter - > ent ) ;
if ( ! seq_print_ip_sym ( s , field - > ip , flags ) )
goto partial ;
if ( ! trace_seq_printf ( s , " : %s " , field - > buf ) )
goto partial ;
return TRACE_TYPE_HANDLED ;
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
static enum print_line_t trace_print_raw ( struct trace_iterator * iter , int flags )
{
struct print_entry * field ;
trace_assign_type ( field , iter - > ent ) ;
if ( ! trace_seq_printf ( & iter - > seq , " # %lx %s " , field - > ip , field - > buf ) )
goto partial ;
return TRACE_TYPE_HANDLED ;
partial :
return TRACE_TYPE_PARTIAL_LINE ;
}
2009-03-06 19:21:49 +03:00
static struct trace_event trace_print_event = {
2009-03-12 20:24:49 +03:00
. type = TRACE_PRINT ,
2009-03-06 19:21:49 +03:00
. trace = trace_print_print ,
. raw = trace_print_raw ,
2009-03-06 19:21:47 +03:00
} ;
2009-03-12 20:24:49 +03:00
2008-12-24 07:24:13 +03:00
static struct trace_event * events [ ] __initdata = {
& trace_fn_event ,
& trace_ctx_event ,
& trace_wake_event ,
& trace_special_event ,
& trace_stack_event ,
& trace_user_stack_event ,
2009-03-12 20:24:49 +03:00
& trace_bprint_event ,
2008-12-24 07:24:13 +03:00
& trace_print_event ,
NULL
} ;
__init static int init_events ( void )
{
struct trace_event * event ;
int i , ret ;
for ( i = 0 ; events [ i ] ; i + + ) {
event = events [ i ] ;
ret = register_ftrace_event ( event ) ;
if ( ! ret ) {
printk ( KERN_WARNING " event %d failed to register \n " ,
event - > type ) ;
WARN_ON_ONCE ( 1 ) ;
}
}
return 0 ;
}
device_initcall ( init_events ) ;