2009-08-17 18:18:07 +04:00
/*
* Copyright ( C ) 2009 , Steven Rostedt < srostedt @ redhat . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* The parts for function graph printing was taken and modified from the
* Linux Kernel that were written by Frederic Weisbecker .
*/
# define _GNU_SOURCE
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# undef _GNU_SOURCE
2009-08-28 05:09:58 +04:00
# include "../perf.h"
2009-08-17 18:18:07 +04:00
# include "util.h"
# include "trace-event.h"
int header_page_ts_offset ;
int header_page_ts_size ;
int header_page_size_offset ;
int header_page_size_size ;
2010-04-06 01:01:10 +04:00
int header_page_overwrite_offset ;
int header_page_overwrite_size ;
2009-08-17 18:18:07 +04:00
int header_page_data_offset ;
int header_page_data_size ;
2010-04-13 12:37:33 +04:00
bool latency_format ;
2009-10-14 23:43:42 +04:00
2009-08-17 18:18:07 +04:00
static char * input_buf ;
static unsigned long long input_buf_ptr ;
static unsigned long long input_buf_siz ;
static int cpus ;
static int long_size ;
2009-11-25 10:15:47 +03:00
static int is_flag_field ;
static int is_symbolic_field ;
static struct format_field *
find_any_field ( struct event * event , const char * name ) ;
2009-08-17 18:18:07 +04:00
static void init_input_buf ( char * buf , unsigned long long size )
{
input_buf = buf ;
input_buf_siz = size ;
input_buf_ptr = 0 ;
}
struct cmdline {
char * comm ;
int pid ;
} ;
static struct cmdline * cmdlines ;
static int cmdline_count ;
static int cmdline_cmp ( const void * a , const void * b )
{
const struct cmdline * ca = a ;
const struct cmdline * cb = b ;
if ( ca - > pid < cb - > pid )
return - 1 ;
if ( ca - > pid > cb - > pid )
return 1 ;
return 0 ;
}
void parse_cmdlines ( char * file , int size __unused )
{
struct cmdline_list {
struct cmdline_list * next ;
char * comm ;
int pid ;
} * list = NULL , * item ;
char * line ;
char * next = NULL ;
int i ;
line = strtok_r ( file , " \n " , & next ) ;
while ( line ) {
item = malloc_or_die ( sizeof ( * item ) ) ;
sscanf ( line , " %d %as " , & item - > pid ,
2009-09-02 16:55:55 +04:00
( float * ) ( void * ) & item - > comm ) ; /* workaround gcc warning */
2009-08-17 18:18:07 +04:00
item - > next = list ;
list = item ;
line = strtok_r ( NULL , " \n " , & next ) ;
cmdline_count + + ;
}
cmdlines = malloc_or_die ( sizeof ( * cmdlines ) * cmdline_count ) ;
i = 0 ;
while ( list ) {
cmdlines [ i ] . pid = list - > pid ;
cmdlines [ i ] . comm = list - > comm ;
i + + ;
item = list ;
list = list - > next ;
free ( item ) ;
}
qsort ( cmdlines , cmdline_count , sizeof ( * cmdlines ) , cmdline_cmp ) ;
}
static struct func_map {
unsigned long long addr ;
char * func ;
char * mod ;
} * func_list ;
static unsigned int func_count ;
static int func_cmp ( const void * a , const void * b )
{
const struct func_map * fa = a ;
const struct func_map * fb = b ;
if ( fa - > addr < fb - > addr )
return - 1 ;
if ( fa - > addr > fb - > addr )
return 1 ;
return 0 ;
}
void parse_proc_kallsyms ( char * file , unsigned int size __unused )
{
struct func_list {
struct func_list * next ;
unsigned long long addr ;
char * func ;
char * mod ;
} * list = NULL , * item ;
char * line ;
char * next = NULL ;
char * addr_str ;
char ch ;
int ret ;
int i ;
line = strtok_r ( file , " \n " , & next ) ;
while ( line ) {
item = malloc_or_die ( sizeof ( * item ) ) ;
item - > mod = NULL ;
ret = sscanf ( line , " %as %c %as \t [%as " ,
2009-09-02 16:55:55 +04:00
( float * ) ( void * ) & addr_str , /* workaround gcc warning */
2009-08-17 18:18:07 +04:00
& ch ,
2009-09-02 16:55:55 +04:00
( float * ) ( void * ) & item - > func ,
( float * ) ( void * ) & item - > mod ) ;
2009-08-17 18:18:07 +04:00
item - > addr = strtoull ( addr_str , NULL , 16 ) ;
free ( addr_str ) ;
/* truncate the extra ']' */
if ( item - > mod )
item - > mod [ strlen ( item - > mod ) - 1 ] = 0 ;
item - > next = list ;
list = item ;
line = strtok_r ( NULL , " \n " , & next ) ;
func_count + + ;
}
2009-12-06 14:10:49 +03:00
func_list = malloc_or_die ( sizeof ( * func_list ) * ( func_count + 1 ) ) ;
2009-08-17 18:18:07 +04:00
i = 0 ;
while ( list ) {
func_list [ i ] . func = list - > func ;
func_list [ i ] . addr = list - > addr ;
func_list [ i ] . mod = list - > mod ;
i + + ;
item = list ;
list = list - > next ;
free ( item ) ;
}
qsort ( func_list , func_count , sizeof ( * func_list ) , func_cmp ) ;
/*
* Add a special record at the end .
*/
func_list [ func_count ] . func = NULL ;
func_list [ func_count ] . addr = 0 ;
func_list [ func_count ] . mod = NULL ;
}
/*
* We are searching for a record in between , not an exact
* match .
*/
static int func_bcmp ( const void * a , const void * b )
{
const struct func_map * fa = a ;
const struct func_map * fb = b ;
if ( ( fa - > addr = = fb - > addr ) | |
( fa - > addr > fb - > addr & &
fa - > addr < ( fb + 1 ) - > addr ) )
return 0 ;
if ( fa - > addr < fb - > addr )
return - 1 ;
return 1 ;
}
static struct func_map * find_func ( unsigned long long addr )
{
struct func_map * func ;
struct func_map key ;
key . addr = addr ;
func = bsearch ( & key , func_list , func_count , sizeof ( * func_list ) ,
func_bcmp ) ;
return func ;
}
void print_funcs ( void )
{
int i ;
for ( i = 0 ; i < ( int ) func_count ; i + + ) {
printf ( " %016llx %s " ,
func_list [ i ] . addr ,
func_list [ i ] . func ) ;
if ( func_list [ i ] . mod )
printf ( " [%s] \n " , func_list [ i ] . mod ) ;
else
printf ( " \n " ) ;
}
}
static struct printk_map {
unsigned long long addr ;
char * printk ;
} * printk_list ;
static unsigned int printk_count ;
static int printk_cmp ( const void * a , const void * b )
{
const struct func_map * fa = a ;
const struct func_map * fb = b ;
if ( fa - > addr < fb - > addr )
return - 1 ;
if ( fa - > addr > fb - > addr )
return 1 ;
return 0 ;
}
static struct printk_map * find_printk ( unsigned long long addr )
{
struct printk_map * printk ;
struct printk_map key ;
key . addr = addr ;
printk = bsearch ( & key , printk_list , printk_count , sizeof ( * printk_list ) ,
printk_cmp ) ;
return printk ;
}
void parse_ftrace_printk ( char * file , unsigned int size __unused )
{
struct printk_list {
struct printk_list * next ;
unsigned long long addr ;
char * printk ;
} * list = NULL , * item ;
char * line ;
char * next = NULL ;
char * addr_str ;
int i ;
line = strtok_r ( file , " \n " , & next ) ;
while ( line ) {
2009-10-21 03:19:35 +04:00
addr_str = strsep ( & line , " : " ) ;
if ( ! line ) {
warning ( " error parsing print strings " ) ;
break ;
}
2009-08-17 18:18:07 +04:00
item = malloc_or_die ( sizeof ( * item ) ) ;
item - > addr = strtoull ( addr_str , NULL , 16 ) ;
2009-10-14 23:43:40 +04:00
/* fmt still has a space, skip it */
2009-10-21 03:19:35 +04:00
item - > printk = strdup ( line + 1 ) ;
2009-08-17 18:18:07 +04:00
item - > next = list ;
list = item ;
line = strtok_r ( NULL , " \n " , & next ) ;
printk_count + + ;
}
printk_list = malloc_or_die ( sizeof ( * printk_list ) * printk_count + 1 ) ;
i = 0 ;
while ( list ) {
printk_list [ i ] . printk = list - > printk ;
printk_list [ i ] . addr = list - > addr ;
i + + ;
item = list ;
list = list - > next ;
free ( item ) ;
}
qsort ( printk_list , printk_count , sizeof ( * printk_list ) , printk_cmp ) ;
}
void print_printk ( void )
{
int i ;
for ( i = 0 ; i < ( int ) printk_count ; i + + ) {
printf ( " %016llx %s \n " ,
printk_list [ i ] . addr ,
printk_list [ i ] . printk ) ;
}
}
static struct event * alloc_event ( void )
{
struct event * event ;
event = malloc_or_die ( sizeof ( * event ) ) ;
memset ( event , 0 , sizeof ( * event ) ) ;
return event ;
}
enum event_type {
EVENT_ERROR ,
EVENT_NONE ,
EVENT_SPACE ,
EVENT_NEWLINE ,
EVENT_OP ,
EVENT_DELIM ,
EVENT_ITEM ,
EVENT_DQUOTE ,
EVENT_SQUOTE ,
} ;
static struct event * event_list ;
static void add_event ( struct event * event )
{
event - > next = event_list ;
event_list = event ;
}
static int event_item_type ( enum event_type type )
{
switch ( type ) {
case EVENT_ITEM . . . EVENT_SQUOTE :
return 1 ;
case EVENT_ERROR . . . EVENT_DELIM :
default :
return 0 ;
}
}
static void free_arg ( struct print_arg * arg )
{
if ( ! arg )
return ;
switch ( arg - > type ) {
case PRINT_ATOM :
if ( arg - > atom . atom )
free ( arg - > atom . atom ) ;
break ;
case PRINT_NULL :
case PRINT_FIELD . . . PRINT_OP :
default :
/* todo */
break ;
}
free ( arg ) ;
}
static enum event_type get_type ( int ch )
{
if ( ch = = ' \n ' )
return EVENT_NEWLINE ;
if ( isspace ( ch ) )
return EVENT_SPACE ;
if ( isalnum ( ch ) | | ch = = ' _ ' )
return EVENT_ITEM ;
if ( ch = = ' \' ' )
return EVENT_SQUOTE ;
if ( ch = = ' " ' )
return EVENT_DQUOTE ;
if ( ! isprint ( ch ) )
return EVENT_NONE ;
if ( ch = = ' ( ' | | ch = = ' ) ' | | ch = = ' , ' )
return EVENT_DELIM ;
return EVENT_OP ;
}
static int __read_char ( void )
{
if ( input_buf_ptr > = input_buf_siz )
return - 1 ;
return input_buf [ input_buf_ptr + + ] ;
}
static int __peek_char ( void )
{
if ( input_buf_ptr > = input_buf_siz )
return - 1 ;
return input_buf [ input_buf_ptr ] ;
}
static enum event_type __read_token ( char * * tok )
{
char buf [ BUFSIZ ] ;
int ch , last_ch , quote_ch , next_ch ;
int i = 0 ;
int tok_size = 0 ;
enum event_type type ;
* tok = NULL ;
ch = __read_char ( ) ;
if ( ch < 0 )
return EVENT_NONE ;
type = get_type ( ch ) ;
if ( type = = EVENT_NONE )
return type ;
buf [ i + + ] = ch ;
switch ( type ) {
case EVENT_NEWLINE :
case EVENT_DELIM :
* tok = malloc_or_die ( 2 ) ;
( * tok ) [ 0 ] = ch ;
( * tok ) [ 1 ] = 0 ;
return type ;
case EVENT_OP :
switch ( ch ) {
case ' - ' :
next_ch = __peek_char ( ) ;
if ( next_ch = = ' > ' ) {
buf [ i + + ] = __read_char ( ) ;
break ;
}
/* fall through */
case ' + ' :
case ' | ' :
case ' & ' :
case ' > ' :
case ' < ' :
last_ch = ch ;
ch = __peek_char ( ) ;
if ( ch ! = last_ch )
goto test_equal ;
buf [ i + + ] = __read_char ( ) ;
switch ( last_ch ) {
case ' > ' :
case ' < ' :
goto test_equal ;
default :
break ;
}
break ;
case ' ! ' :
case ' = ' :
goto test_equal ;
default : /* what should we do instead? */
break ;
}
buf [ i ] = 0 ;
* tok = strdup ( buf ) ;
return type ;
test_equal :
ch = __peek_char ( ) ;
if ( ch = = ' = ' )
buf [ i + + ] = __read_char ( ) ;
break ;
case EVENT_DQUOTE :
case EVENT_SQUOTE :
/* don't keep quotes */
i - - ;
quote_ch = ch ;
last_ch = 0 ;
do {
if ( i = = ( BUFSIZ - 1 ) ) {
buf [ i ] = 0 ;
if ( * tok ) {
* tok = realloc ( * tok , tok_size + BUFSIZ ) ;
if ( ! * tok )
return EVENT_NONE ;
strcat ( * tok , buf ) ;
} else
* tok = strdup ( buf ) ;
if ( ! * tok )
return EVENT_NONE ;
tok_size + = BUFSIZ ;
i = 0 ;
}
last_ch = ch ;
ch = __read_char ( ) ;
buf [ i + + ] = ch ;
2009-10-14 23:43:33 +04:00
/* the '\' '\' will cancel itself */
if ( ch = = ' \\ ' & & last_ch = = ' \\ ' )
last_ch = 0 ;
} while ( ch ! = quote_ch | | last_ch = = ' \\ ' ) ;
2009-08-17 18:18:07 +04:00
/* remove the last quote */
i - - ;
goto out ;
case EVENT_ERROR . . . EVENT_SPACE :
case EVENT_ITEM :
default :
break ;
}
while ( get_type ( __peek_char ( ) ) = = type ) {
if ( i = = ( BUFSIZ - 1 ) ) {
buf [ i ] = 0 ;
if ( * tok ) {
* tok = realloc ( * tok , tok_size + BUFSIZ ) ;
if ( ! * tok )
return EVENT_NONE ;
strcat ( * tok , buf ) ;
} else
* tok = strdup ( buf ) ;
if ( ! * tok )
return EVENT_NONE ;
tok_size + = BUFSIZ ;
i = 0 ;
}
ch = __read_char ( ) ;
buf [ i + + ] = ch ;
}
out :
buf [ i ] = 0 ;
if ( * tok ) {
* tok = realloc ( * tok , tok_size + i ) ;
if ( ! * tok )
return EVENT_NONE ;
strcat ( * tok , buf ) ;
} else
* tok = strdup ( buf ) ;
if ( ! * tok )
return EVENT_NONE ;
return type ;
}
static void free_token ( char * tok )
{
if ( tok )
free ( tok ) ;
}
static enum event_type read_token ( char * * tok )
{
enum event_type type ;
for ( ; ; ) {
type = __read_token ( tok ) ;
if ( type ! = EVENT_SPACE )
return type ;
free_token ( * tok ) ;
}
/* not reached */
return EVENT_NONE ;
}
/* no newline */
static enum event_type read_token_item ( char * * tok )
{
enum event_type type ;
for ( ; ; ) {
type = __read_token ( tok ) ;
if ( type ! = EVENT_SPACE & & type ! = EVENT_NEWLINE )
return type ;
free_token ( * tok ) ;
}
/* not reached */
return EVENT_NONE ;
}
static int test_type ( enum event_type type , enum event_type expect )
{
if ( type ! = expect ) {
2009-10-14 23:43:39 +04:00
warning ( " Error: expected type %d but read %d " ,
2009-08-17 18:18:07 +04:00
expect , type ) ;
return - 1 ;
}
return 0 ;
}
2010-04-06 01:01:10 +04:00
static int __test_type_token ( enum event_type type , char * token ,
enum event_type expect , const char * expect_tok ,
bool warn )
2009-08-17 18:18:07 +04:00
{
if ( type ! = expect ) {
2010-04-06 01:01:10 +04:00
if ( warn )
warning ( " Error: expected type %d but read %d " ,
expect , type ) ;
2009-08-17 18:18:07 +04:00
return - 1 ;
}
if ( strcmp ( token , expect_tok ) ! = 0 ) {
2010-04-06 01:01:10 +04:00
if ( warn )
warning ( " Error: expected '%s' but read '%s' " ,
expect_tok , token ) ;
2009-08-17 18:18:07 +04:00
return - 1 ;
}
return 0 ;
}
2010-04-06 01:01:10 +04:00
static int test_type_token ( enum event_type type , char * token ,
enum event_type expect , const char * expect_tok )
{
return __test_type_token ( type , token , expect , expect_tok , true ) ;
}
2009-08-17 18:18:07 +04:00
static int __read_expect_type ( enum event_type expect , char * * tok , int newline_ok )
{
enum event_type type ;
if ( newline_ok )
type = read_token ( tok ) ;
else
type = read_token_item ( tok ) ;
return test_type ( type , expect ) ;
}
static int read_expect_type ( enum event_type expect , char * * tok )
{
return __read_expect_type ( expect , tok , 1 ) ;
}
2010-04-06 01:01:10 +04:00
static int __read_expected ( enum event_type expect , const char * str ,
int newline_ok , bool warn )
2009-08-17 18:18:07 +04:00
{
enum event_type type ;
char * token ;
int ret ;
if ( newline_ok )
type = read_token ( & token ) ;
else
type = read_token_item ( & token ) ;
2010-04-06 01:01:10 +04:00
ret = __test_type_token ( type , token , expect , str , warn ) ;
2009-08-17 18:18:07 +04:00
free_token ( token ) ;
2009-10-14 23:43:39 +04:00
return ret ;
2009-08-17 18:18:07 +04:00
}
2009-10-06 00:17:29 +04:00
static int read_expected ( enum event_type expect , const char * str )
2009-08-17 18:18:07 +04:00
{
2010-04-06 01:01:10 +04:00
return __read_expected ( expect , str , 1 , true ) ;
2009-08-17 18:18:07 +04:00
}
2009-10-06 00:17:29 +04:00
static int read_expected_item ( enum event_type expect , const char * str )
2009-08-17 18:18:07 +04:00
{
2010-04-06 01:01:10 +04:00
return __read_expected ( expect , str , 0 , true ) ;
2009-08-17 18:18:07 +04:00
}
static char * event_read_name ( void )
{
char * token ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_ITEM , " name " ) < 0 )
2009-08-17 18:18:07 +04:00
return NULL ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
return NULL ;
if ( read_expect_type ( EVENT_ITEM , & token ) < 0 )
goto fail ;
return token ;
fail :
free_token ( token ) ;
return NULL ;
}
static int event_read_id ( void )
{
char * token ;
int id ;
2009-10-14 23:43:44 +04:00
if ( read_expected_item ( EVENT_ITEM , " ID " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
if ( read_expect_type ( EVENT_ITEM , & token ) < 0 )
goto fail ;
id = strtoul ( token , NULL , 0 ) ;
free_token ( token ) ;
return id ;
fail :
free_token ( token ) ;
return - 1 ;
}
2009-10-06 10:09:52 +04:00
static int field_is_string ( struct format_field * field )
{
if ( ( field - > flags & FIELD_IS_ARRAY ) & &
( ! strstr ( field - > type , " char " ) | | ! strstr ( field - > type , " u8 " ) | |
! strstr ( field - > type , " s8 " ) ) )
return 1 ;
return 0 ;
}
static int field_is_dynamic ( struct format_field * field )
{
2010-04-15 01:58:03 +04:00
if ( ! strncmp ( field - > type , " __data_loc " , 10 ) )
2009-10-06 10:09:52 +04:00
return 1 ;
return 0 ;
}
2009-08-17 18:18:07 +04:00
static int event_read_fields ( struct event * event , struct format_field * * fields )
{
struct format_field * field = NULL ;
enum event_type type ;
char * token ;
char * last_token ;
int count = 0 ;
do {
type = read_token ( & token ) ;
if ( type = = EVENT_NEWLINE ) {
free_token ( token ) ;
return count ;
}
count + + ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_ITEM , " field " ) )
2009-08-17 18:18:07 +04:00
goto fail ;
free_token ( token ) ;
type = read_token ( & token ) ;
/*
* The ftrace fields may still use the " special " name .
* Just ignore it .
*/
if ( event - > flags & EVENT_FL_ISFTRACE & &
type = = EVENT_ITEM & & strcmp ( token , " special " ) = = 0 ) {
free_token ( token ) ;
type = read_token ( & token ) ;
}
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
if ( read_expect_type ( EVENT_ITEM , & token ) < 0 )
goto fail ;
last_token = token ;
field = malloc_or_die ( sizeof ( * field ) ) ;
memset ( field , 0 , sizeof ( * field ) ) ;
/* read the rest of the type */
for ( ; ; ) {
type = read_token ( & token ) ;
if ( type = = EVENT_ITEM | |
( type = = EVENT_OP & & strcmp ( token , " * " ) = = 0 ) | |
/*
* Some of the ftrace fields are broken and have
* an illegal " . " in them .
*/
( event - > flags & EVENT_FL_ISFTRACE & &
type = = EVENT_OP & & strcmp ( token , " . " ) = = 0 ) ) {
if ( strcmp ( token , " * " ) = = 0 )
field - > flags | = FIELD_IS_POINTER ;
if ( field - > type ) {
field - > type = realloc ( field - > type ,
strlen ( field - > type ) +
strlen ( last_token ) + 2 ) ;
strcat ( field - > type , " " ) ;
strcat ( field - > type , last_token ) ;
} else
field - > type = last_token ;
last_token = token ;
continue ;
}
break ;
}
if ( ! field - > type ) {
die ( " no type found " ) ;
goto fail ;
}
field - > name = last_token ;
if ( test_type ( type , EVENT_OP ) )
goto fail ;
if ( strcmp ( token , " [ " ) = = 0 ) {
enum event_type last_type = type ;
char * brackets = token ;
int len ;
field - > flags | = FIELD_IS_ARRAY ;
type = read_token ( & token ) ;
while ( strcmp ( token , " ] " ) ! = 0 ) {
if ( last_type = = EVENT_ITEM & &
type = = EVENT_ITEM )
len = 2 ;
else
len = 1 ;
last_type = type ;
brackets = realloc ( brackets ,
strlen ( brackets ) +
strlen ( token ) + len ) ;
if ( len = = 2 )
strcat ( brackets , " " ) ;
strcat ( brackets , token ) ;
free_token ( token ) ;
type = read_token ( & token ) ;
if ( type = = EVENT_NONE ) {
die ( " failed to find token " ) ;
goto fail ;
}
}
free_token ( token ) ;
brackets = realloc ( brackets , strlen ( brackets ) + 2 ) ;
strcat ( brackets , " ] " ) ;
/* add brackets to type */
type = read_token ( & token ) ;
/*
* If the next token is not an OP , then it is of
* the format : type [ ] item ;
*/
if ( type = = EVENT_ITEM ) {
field - > type = realloc ( field - > type ,
strlen ( field - > type ) +
strlen ( field - > name ) +
strlen ( brackets ) + 2 ) ;
strcat ( field - > type , " " ) ;
strcat ( field - > type , field - > name ) ;
free_token ( field - > name ) ;
strcat ( field - > type , brackets ) ;
field - > name = token ;
type = read_token ( & token ) ;
} else {
field - > type = realloc ( field - > type ,
strlen ( field - > type ) +
strlen ( brackets ) + 1 ) ;
strcat ( field - > type , brackets ) ;
}
free ( brackets ) ;
}
2009-10-06 10:09:52 +04:00
if ( field_is_string ( field ) ) {
field - > flags | = FIELD_IS_STRING ;
if ( field_is_dynamic ( field ) )
field - > flags | = FIELD_IS_DYNAMIC ;
}
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " ; " ) )
2009-08-17 18:18:07 +04:00
goto fail ;
free_token ( token ) ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_ITEM , " offset " ) < 0 )
2009-08-17 18:18:07 +04:00
goto fail_expect ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
goto fail_expect ;
if ( read_expect_type ( EVENT_ITEM , & token ) )
goto fail ;
field - > offset = strtoul ( token , NULL , 0 ) ;
free_token ( token ) ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " ; " ) < 0 )
2009-08-17 18:18:07 +04:00
goto fail_expect ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_ITEM , " size " ) < 0 )
2009-08-17 18:18:07 +04:00
goto fail_expect ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
goto fail_expect ;
if ( read_expect_type ( EVENT_ITEM , & token ) )
goto fail ;
field - > size = strtoul ( token , NULL , 0 ) ;
free_token ( token ) ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " ; " ) < 0 )
2009-10-06 10:09:50 +04:00
goto fail_expect ;
2009-10-14 23:43:38 +04:00
type = read_token ( & token ) ;
if ( type ! = EVENT_NEWLINE ) {
/* newer versions of the kernel have a "signed" type */
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_ITEM , " signed " ) )
2009-10-14 23:43:38 +04:00
goto fail ;
2009-10-06 10:09:50 +04:00
2009-10-14 23:43:38 +04:00
free_token ( token ) ;
2009-10-06 10:09:50 +04:00
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-10-14 23:43:38 +04:00
goto fail_expect ;
2009-10-06 10:09:50 +04:00
2009-10-14 23:43:38 +04:00
if ( read_expect_type ( EVENT_ITEM , & token ) )
goto fail ;
2009-11-25 10:14:58 +03:00
if ( strtoul ( token , NULL , 0 ) )
field - > flags | = FIELD_IS_SIGNED ;
2009-10-14 23:43:38 +04:00
free_token ( token ) ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " ; " ) < 0 )
2009-10-14 23:43:38 +04:00
goto fail_expect ;
if ( read_expect_type ( EVENT_NEWLINE , & token ) )
goto fail ;
}
2009-08-17 18:18:07 +04:00
free_token ( token ) ;
* fields = field ;
fields = & field - > next ;
} while ( 1 ) ;
return 0 ;
fail :
free_token ( token ) ;
fail_expect :
if ( field )
free ( field ) ;
return - 1 ;
}
static int event_read_format ( struct event * event )
{
char * token ;
int ret ;
2009-10-14 23:43:44 +04:00
if ( read_expected_item ( EVENT_ITEM , " format " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
if ( read_expect_type ( EVENT_NEWLINE , & token ) )
goto fail ;
free_token ( token ) ;
ret = event_read_fields ( event , & event - > format . common_fields ) ;
if ( ret < 0 )
return ret ;
event - > format . nr_common = ret ;
ret = event_read_fields ( event , & event - > format . fields ) ;
if ( ret < 0 )
return ret ;
event - > format . nr_fields = ret ;
return 0 ;
fail :
free_token ( token ) ;
return - 1 ;
}
enum event_type
process_arg_token ( struct event * event , struct print_arg * arg ,
char * * tok , enum event_type type ) ;
static enum event_type
process_arg ( struct event * event , struct print_arg * arg , char * * tok )
{
enum event_type type ;
char * token ;
type = read_token ( & token ) ;
* tok = token ;
return process_arg_token ( event , arg , tok , type ) ;
}
static enum event_type
process_cond ( struct event * event , struct print_arg * top , char * * tok )
{
struct print_arg * arg , * left , * right ;
enum event_type type ;
char * token = NULL ;
arg = malloc_or_die ( sizeof ( * arg ) ) ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
left = malloc_or_die ( sizeof ( * left ) ) ;
right = malloc_or_die ( sizeof ( * right ) ) ;
arg - > type = PRINT_OP ;
arg - > op . left = left ;
arg - > op . right = right ;
* tok = NULL ;
type = process_arg ( event , left , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " : " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
arg - > op . op = token ;
type = process_arg ( event , right , & token ) ;
top - > op . right = arg ;
* tok = token ;
return type ;
out_free :
free_token ( * tok ) ;
free ( right ) ;
free ( left ) ;
free_arg ( arg ) ;
return EVENT_ERROR ;
}
2009-10-14 23:43:35 +04:00
static enum event_type
process_array ( struct event * event , struct print_arg * top , char * * tok )
{
struct print_arg * arg ;
enum event_type type ;
char * token = NULL ;
arg = malloc_or_die ( sizeof ( * arg ) ) ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
* tok = NULL ;
type = process_arg ( event , arg , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " ] " ) )
2009-10-14 23:43:35 +04:00
goto out_free ;
top - > op . right = arg ;
free_token ( token ) ;
type = read_token_item ( & token ) ;
* tok = token ;
return type ;
out_free :
free_token ( * tok ) ;
free_arg ( arg ) ;
return EVENT_ERROR ;
}
2009-08-17 18:18:07 +04:00
static int get_op_prio ( char * op )
{
if ( ! op [ 1 ] ) {
switch ( op [ 0 ] ) {
case ' * ' :
case ' / ' :
case ' % ' :
return 6 ;
case ' + ' :
case ' - ' :
return 7 ;
/* '>>' and '<<' are 8 */
case ' < ' :
case ' > ' :
return 9 ;
/* '==' and '!=' are 10 */
case ' & ' :
return 11 ;
case ' ^ ' :
return 12 ;
case ' | ' :
return 13 ;
case ' ? ' :
return 16 ;
default :
die ( " unknown op '%c' " , op [ 0 ] ) ;
return - 1 ;
}
} else {
if ( strcmp ( op , " ++ " ) = = 0 | |
strcmp ( op , " -- " ) = = 0 ) {
return 3 ;
} else if ( strcmp ( op , " >> " ) = = 0 | |
strcmp ( op , " << " ) = = 0 ) {
return 8 ;
} else if ( strcmp ( op , " >= " ) = = 0 | |
strcmp ( op , " <= " ) = = 0 ) {
return 9 ;
} else if ( strcmp ( op , " == " ) = = 0 | |
strcmp ( op , " != " ) = = 0 ) {
return 10 ;
} else if ( strcmp ( op , " && " ) = = 0 ) {
return 14 ;
} else if ( strcmp ( op , " || " ) = = 0 ) {
return 15 ;
} else {
die ( " unknown op '%s' " , op ) ;
return - 1 ;
}
}
}
static void set_op_prio ( struct print_arg * arg )
{
/* single ops are the greatest */
if ( ! arg - > op . left | | arg - > op . left - > type = = PRINT_NULL ) {
arg - > op . prio = 0 ;
return ;
}
arg - > op . prio = get_op_prio ( arg - > op . op ) ;
}
static enum event_type
process_op ( struct event * event , struct print_arg * arg , char * * tok )
{
struct print_arg * left , * right = NULL ;
enum event_type type ;
char * token ;
/* the op is passed in via tok */
token = * tok ;
if ( arg - > type = = PRINT_OP & & ! arg - > op . left ) {
/* handle single op */
if ( token [ 1 ] ) {
die ( " bad op token %s " , token ) ;
return EVENT_ERROR ;
}
switch ( token [ 0 ] ) {
case ' ! ' :
case ' + ' :
case ' - ' :
break ;
default :
die ( " bad op token %s " , token ) ;
return EVENT_ERROR ;
}
/* make an empty left */
left = malloc_or_die ( sizeof ( * left ) ) ;
left - > type = PRINT_NULL ;
arg - > op . left = left ;
right = malloc_or_die ( sizeof ( * right ) ) ;
arg - > op . right = right ;
type = process_arg ( event , right , tok ) ;
} else if ( strcmp ( token , " ? " ) = = 0 ) {
left = malloc_or_die ( sizeof ( * left ) ) ;
/* copy the top arg to the left */
* left = * arg ;
arg - > type = PRINT_OP ;
arg - > op . op = token ;
arg - > op . left = left ;
arg - > op . prio = 0 ;
type = process_cond ( event , arg , tok ) ;
} else if ( strcmp ( token , " >> " ) = = 0 | |
strcmp ( token , " << " ) = = 0 | |
strcmp ( token , " & " ) = = 0 | |
strcmp ( token , " | " ) = = 0 | |
strcmp ( token , " && " ) = = 0 | |
strcmp ( token , " || " ) = = 0 | |
strcmp ( token , " - " ) = = 0 | |
strcmp ( token , " + " ) = = 0 | |
strcmp ( token , " * " ) = = 0 | |
strcmp ( token , " ^ " ) = = 0 | |
strcmp ( token , " / " ) = = 0 | |
2009-10-14 23:43:34 +04:00
strcmp ( token , " < " ) = = 0 | |
strcmp ( token , " > " ) = = 0 | |
2009-08-17 18:18:07 +04:00
strcmp ( token , " == " ) = = 0 | |
strcmp ( token , " != " ) = = 0 ) {
left = malloc_or_die ( sizeof ( * left ) ) ;
/* copy the top arg to the left */
* left = * arg ;
arg - > type = PRINT_OP ;
arg - > op . op = token ;
arg - > op . left = left ;
set_op_prio ( arg ) ;
right = malloc_or_die ( sizeof ( * right ) ) ;
2009-10-14 23:43:36 +04:00
type = read_token_item ( & token ) ;
* tok = token ;
/* could just be a type pointer */
if ( ( strcmp ( arg - > op . op , " * " ) = = 0 ) & &
type = = EVENT_DELIM & & ( strcmp ( token , " ) " ) = = 0 ) ) {
if ( left - > type ! = PRINT_ATOM )
die ( " bad pointer type " ) ;
left - > atom . atom = realloc ( left - > atom . atom ,
sizeof ( left - > atom . atom ) + 3 ) ;
strcat ( left - > atom . atom , " * " ) ;
* arg = * left ;
free ( arg ) ;
return type ;
}
type = process_arg_token ( event , right , tok , type ) ;
2009-08-17 18:18:07 +04:00
arg - > op . right = right ;
2009-10-14 23:43:35 +04:00
} else if ( strcmp ( token , " [ " ) = = 0 ) {
left = malloc_or_die ( sizeof ( * left ) ) ;
* left = * arg ;
arg - > type = PRINT_OP ;
arg - > op . op = token ;
arg - > op . left = left ;
arg - > op . prio = 0 ;
type = process_array ( event , arg , tok ) ;
2009-08-17 18:18:07 +04:00
} else {
2009-10-14 23:43:39 +04:00
warning ( " unknown op '%s' " , token ) ;
event - > flags | = EVENT_FL_FAILED ;
2009-08-17 18:18:07 +04:00
/* the arg is now the left side */
return EVENT_NONE ;
}
if ( type = = EVENT_OP ) {
int prio ;
/* higher prios need to be closer to the root */
prio = get_op_prio ( * tok ) ;
if ( prio > arg - > op . prio )
return process_op ( event , arg , tok ) ;
return process_op ( event , right , tok ) ;
}
return type ;
}
static enum event_type
process_entry ( struct event * event __unused , struct print_arg * arg ,
char * * tok )
{
enum event_type type ;
char * field ;
char * token ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " -> " ) < 0 )
2009-08-17 18:18:07 +04:00
return EVENT_ERROR ;
if ( read_expect_type ( EVENT_ITEM , & token ) < 0 )
goto fail ;
field = token ;
arg - > type = PRINT_FIELD ;
arg - > field . name = field ;
2009-11-25 10:15:47 +03:00
if ( is_flag_field ) {
arg - > field . field = find_any_field ( event , arg - > field . name ) ;
arg - > field . field - > flags | = FIELD_IS_FLAG ;
is_flag_field = 0 ;
} else if ( is_symbolic_field ) {
arg - > field . field = find_any_field ( event , arg - > field . name ) ;
arg - > field . field - > flags | = FIELD_IS_SYMBOLIC ;
is_symbolic_field = 0 ;
}
2009-08-17 18:18:07 +04:00
type = read_token ( & token ) ;
* tok = token ;
return type ;
fail :
free_token ( token ) ;
return EVENT_ERROR ;
}
static char * arg_eval ( struct print_arg * arg ) ;
static long long arg_num_eval ( struct print_arg * arg )
{
long long left , right ;
long long val = 0 ;
switch ( arg - > type ) {
case PRINT_ATOM :
val = strtoll ( arg - > atom . atom , NULL , 0 ) ;
break ;
case PRINT_TYPE :
val = arg_num_eval ( arg - > typecast . item ) ;
break ;
case PRINT_OP :
switch ( arg - > op . op [ 0 ] ) {
case ' | ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
if ( arg - > op . op [ 1 ] )
val = left | | right ;
else
val = left | right ;
break ;
case ' & ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
if ( arg - > op . op [ 1 ] )
val = left & & right ;
else
val = left & right ;
break ;
case ' < ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
switch ( arg - > op . op [ 1 ] ) {
case 0 :
val = left < right ;
break ;
case ' < ' :
val = left < < right ;
break ;
case ' = ' :
val = left < = right ;
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
case ' > ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
switch ( arg - > op . op [ 1 ] ) {
case 0 :
val = left > right ;
break ;
case ' > ' :
val = left > > right ;
break ;
case ' = ' :
val = left > = right ;
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
case ' = ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
if ( arg - > op . op [ 1 ] ! = ' = ' )
die ( " unknown op '%s' " , arg - > op . op ) ;
val = left = = right ;
break ;
case ' ! ' :
left = arg_num_eval ( arg - > op . left ) ;
right = arg_num_eval ( arg - > op . right ) ;
switch ( arg - > op . op [ 1 ] ) {
case ' = ' :
val = left ! = right ;
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
case PRINT_NULL :
case PRINT_FIELD . . . PRINT_SYMBOL :
case PRINT_STRING :
default :
die ( " invalid eval type %d " , arg - > type ) ;
}
return val ;
}
static char * arg_eval ( struct print_arg * arg )
{
long long val ;
static char buf [ 20 ] ;
switch ( arg - > type ) {
case PRINT_ATOM :
return arg - > atom . atom ;
case PRINT_TYPE :
return arg_eval ( arg - > typecast . item ) ;
case PRINT_OP :
val = arg_num_eval ( arg ) ;
sprintf ( buf , " %lld " , val ) ;
return buf ;
case PRINT_NULL :
case PRINT_FIELD . . . PRINT_SYMBOL :
case PRINT_STRING :
default :
die ( " invalid eval type %d " , arg - > type ) ;
break ;
}
return NULL ;
}
static enum event_type
process_fields ( struct event * event , struct print_flag_sym * * list , char * * tok )
{
enum event_type type ;
struct print_arg * arg = NULL ;
struct print_flag_sym * field ;
char * token = NULL ;
char * value ;
do {
free_token ( token ) ;
type = read_token_item ( & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " { " ) )
2009-08-17 18:18:07 +04:00
break ;
arg = malloc_or_die ( sizeof ( * arg ) ) ;
free_token ( token ) ;
type = process_arg ( event , arg , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " , " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
field = malloc_or_die ( sizeof ( * field ) ) ;
2009-12-09 22:26:18 +03:00
memset ( field , 0 , sizeof ( * field ) ) ;
2009-08-17 18:18:07 +04:00
value = arg_eval ( arg ) ;
field - > value = strdup ( value ) ;
free_token ( token ) ;
type = process_arg ( event , arg , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_OP , " } " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
value = arg_eval ( arg ) ;
field - > str = strdup ( value ) ;
free_arg ( arg ) ;
arg = NULL ;
* list = field ;
list = & field - > next ;
free_token ( token ) ;
type = read_token_item ( & token ) ;
} while ( type = = EVENT_DELIM & & strcmp ( token , " , " ) = = 0 ) ;
* tok = token ;
return type ;
out_free :
free_arg ( arg ) ;
free_token ( token ) ;
return EVENT_ERROR ;
}
static enum event_type
process_flags ( struct event * event , struct print_arg * arg , char * * tok )
{
struct print_arg * field ;
enum event_type type ;
char * token ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
arg - > type = PRINT_FLAGS ;
2009-10-14 23:43:44 +04:00
if ( read_expected_item ( EVENT_DELIM , " ( " ) < 0 )
2009-08-17 18:18:07 +04:00
return EVENT_ERROR ;
field = malloc_or_die ( sizeof ( * field ) ) ;
type = process_arg ( event , field , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " , " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
arg - > flags . field = field ;
type = read_token_item ( & token ) ;
if ( event_item_type ( type ) ) {
arg - > flags . delim = token ;
type = read_token_item ( & token ) ;
}
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " , " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
type = process_fields ( event , & arg - > flags . flags , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " ) " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
free_token ( token ) ;
type = read_token_item ( tok ) ;
return type ;
out_free :
free_token ( token ) ;
return EVENT_ERROR ;
}
static enum event_type
process_symbols ( struct event * event , struct print_arg * arg , char * * tok )
{
struct print_arg * field ;
enum event_type type ;
char * token ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
arg - > type = PRINT_SYMBOL ;
2009-10-14 23:43:44 +04:00
if ( read_expected_item ( EVENT_DELIM , " ( " ) < 0 )
2009-08-17 18:18:07 +04:00
return EVENT_ERROR ;
field = malloc_or_die ( sizeof ( * field ) ) ;
type = process_arg ( event , field , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " , " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
arg - > symbol . field = field ;
type = process_fields ( event , & arg - > symbol . symbols , & token ) ;
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " ) " ) )
2009-08-17 18:18:07 +04:00
goto out_free ;
free_token ( token ) ;
type = read_token_item ( tok ) ;
return type ;
out_free :
free_token ( token ) ;
return EVENT_ERROR ;
}
static enum event_type
process_paren ( struct event * event , struct print_arg * arg , char * * tok )
{
struct print_arg * item_arg ;
enum event_type type ;
char * token ;
type = process_arg ( event , arg , & token ) ;
if ( type = = EVENT_ERROR )
return EVENT_ERROR ;
2009-10-14 23:43:36 +04:00
if ( type = = EVENT_OP )
type = process_op ( event , arg , & token ) ;
2009-08-17 18:18:07 +04:00
2009-10-14 23:43:36 +04:00
if ( type = = EVENT_ERROR )
return EVENT_ERROR ;
2009-08-17 18:18:07 +04:00
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " ) " ) ) {
2009-08-17 18:18:07 +04:00
free_token ( token ) ;
return EVENT_ERROR ;
}
free_token ( token ) ;
type = read_token_item ( & token ) ;
/*
* If the next token is an item or another open paren , then
* this was a typecast .
*/
if ( event_item_type ( type ) | |
( type = = EVENT_DELIM & & strcmp ( token , " ( " ) = = 0 ) ) {
/* make this a typecast and contine */
/* prevous must be an atom */
if ( arg - > type ! = PRINT_ATOM )
die ( " previous needed to be PRINT_ATOM " ) ;
item_arg = malloc_or_die ( sizeof ( * item_arg ) ) ;
arg - > type = PRINT_TYPE ;
arg - > typecast . type = arg - > atom . atom ;
arg - > typecast . item = item_arg ;
type = process_arg_token ( event , item_arg , & token , type ) ;
}
* tok = token ;
return type ;
}
static enum event_type
process_str ( struct event * event __unused , struct print_arg * arg , char * * tok )
{
enum event_type type ;
char * token ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_DELIM , " ( " ) < 0 )
2009-08-17 18:18:07 +04:00
return EVENT_ERROR ;
if ( read_expect_type ( EVENT_ITEM , & token ) < 0 )
goto fail ;
arg - > type = PRINT_STRING ;
arg - > string . string = token ;
2009-08-31 08:45:21 +04:00
arg - > string . offset = - 1 ;
2009-08-17 18:18:07 +04:00
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_DELIM , " ) " ) < 0 )
2009-08-17 18:18:07 +04:00
return EVENT_ERROR ;
type = read_token ( & token ) ;
* tok = token ;
return type ;
fail :
free_token ( token ) ;
return EVENT_ERROR ;
}
enum event_type
process_arg_token ( struct event * event , struct print_arg * arg ,
char * * tok , enum event_type type )
{
char * token ;
char * atom ;
token = * tok ;
switch ( type ) {
case EVENT_ITEM :
if ( strcmp ( token , " REC " ) = = 0 ) {
free_token ( token ) ;
type = process_entry ( event , arg , & token ) ;
} else if ( strcmp ( token , " __print_flags " ) = = 0 ) {
free_token ( token ) ;
2009-11-25 10:15:47 +03:00
is_flag_field = 1 ;
2009-08-17 18:18:07 +04:00
type = process_flags ( event , arg , & token ) ;
} else if ( strcmp ( token , " __print_symbolic " ) = = 0 ) {
free_token ( token ) ;
2009-11-25 10:15:47 +03:00
is_symbolic_field = 1 ;
2009-08-17 18:18:07 +04:00
type = process_symbols ( event , arg , & token ) ;
} else if ( strcmp ( token , " __get_str " ) = = 0 ) {
free_token ( token ) ;
type = process_str ( event , arg , & token ) ;
} else {
atom = token ;
/* test the next token */
type = read_token_item ( & token ) ;
/* atoms can be more than one token long */
while ( type = = EVENT_ITEM ) {
atom = realloc ( atom , strlen ( atom ) + strlen ( token ) + 2 ) ;
strcat ( atom , " " ) ;
strcat ( atom , token ) ;
free_token ( token ) ;
type = read_token_item ( & token ) ;
}
/* todo, test for function */
arg - > type = PRINT_ATOM ;
arg - > atom . atom = atom ;
}
break ;
case EVENT_DQUOTE :
case EVENT_SQUOTE :
arg - > type = PRINT_ATOM ;
arg - > atom . atom = token ;
type = read_token_item ( & token ) ;
break ;
case EVENT_DELIM :
if ( strcmp ( token , " ( " ) = = 0 ) {
free_token ( token ) ;
type = process_paren ( event , arg , & token ) ;
break ;
}
case EVENT_OP :
/* handle single ops */
arg - > type = PRINT_OP ;
arg - > op . op = token ;
arg - > op . left = NULL ;
type = process_op ( event , arg , & token ) ;
break ;
case EVENT_ERROR . . . EVENT_NEWLINE :
default :
die ( " unexpected type %d " , type ) ;
}
* tok = token ;
return type ;
}
static int event_read_print_args ( struct event * event , struct print_arg * * list )
{
2009-10-14 23:43:37 +04:00
enum event_type type = EVENT_ERROR ;
2009-08-17 18:18:07 +04:00
struct print_arg * arg ;
char * token ;
int args = 0 ;
do {
2009-10-14 23:43:37 +04:00
if ( type = = EVENT_NEWLINE ) {
free_token ( token ) ;
type = read_token_item ( & token ) ;
continue ;
}
2009-08-17 18:18:07 +04:00
arg = malloc_or_die ( sizeof ( * arg ) ) ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
type = process_arg ( event , arg , & token ) ;
if ( type = = EVENT_ERROR ) {
free_arg ( arg ) ;
return - 1 ;
}
* list = arg ;
args + + ;
if ( type = = EVENT_OP ) {
type = process_op ( event , arg , & token ) ;
list = & arg - > next ;
continue ;
}
if ( type = = EVENT_DELIM & & strcmp ( token , " , " ) = = 0 ) {
free_token ( token ) ;
* list = arg ;
list = & arg - > next ;
continue ;
}
break ;
} while ( type ! = EVENT_NONE ) ;
if ( type ! = EVENT_NONE )
free_token ( token ) ;
return args ;
}
static int event_read_print ( struct event * event )
{
enum event_type type ;
char * token ;
int ret ;
2009-10-14 23:43:44 +04:00
if ( read_expected_item ( EVENT_ITEM , " print " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_ITEM , " fmt " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
2009-10-14 23:43:44 +04:00
if ( read_expected ( EVENT_OP , " : " ) < 0 )
2009-08-17 18:18:07 +04:00
return - 1 ;
if ( read_expect_type ( EVENT_DQUOTE , & token ) < 0 )
goto fail ;
2009-10-14 23:43:32 +04:00
concat :
2009-08-17 18:18:07 +04:00
event - > print_fmt . format = token ;
event - > print_fmt . args = NULL ;
/* ok to have no arg */
type = read_token_item ( & token ) ;
if ( type = = EVENT_NONE )
return 0 ;
2009-10-14 23:43:32 +04:00
/* Handle concatination of print lines */
if ( type = = EVENT_DQUOTE ) {
char * cat ;
cat = malloc_or_die ( strlen ( event - > print_fmt . format ) +
strlen ( token ) + 1 ) ;
strcpy ( cat , event - > print_fmt . format ) ;
strcat ( cat , token ) ;
free_token ( token ) ;
free_token ( event - > print_fmt . format ) ;
event - > print_fmt . format = NULL ;
token = cat ;
goto concat ;
}
2009-10-14 23:43:44 +04:00
if ( test_type_token ( type , token , EVENT_DELIM , " , " ) )
2009-08-17 18:18:07 +04:00
goto fail ;
free_token ( token ) ;
ret = event_read_print_args ( event , & event - > print_fmt . args ) ;
if ( ret < 0 )
return - 1 ;
2009-10-14 23:43:41 +04:00
return ret ;
2009-08-17 18:18:07 +04:00
fail :
free_token ( token ) ;
return - 1 ;
}
static struct format_field *
find_common_field ( struct event * event , const char * name )
{
struct format_field * format ;
for ( format = event - > format . common_fields ;
format ; format = format - > next ) {
if ( strcmp ( format - > name , name ) = = 0 )
break ;
}
return format ;
}
static struct format_field *
find_field ( struct event * event , const char * name )
{
struct format_field * format ;
for ( format = event - > format . fields ;
format ; format = format - > next ) {
if ( strcmp ( format - > name , name ) = = 0 )
break ;
}
return format ;
}
static struct format_field *
find_any_field ( struct event * event , const char * name )
{
struct format_field * format ;
format = find_common_field ( event , name ) ;
if ( format )
return format ;
return find_field ( event , name ) ;
}
2009-11-25 10:15:48 +03:00
unsigned long long read_size ( void * ptr , int size )
2009-08-17 18:18:07 +04:00
{
switch ( size ) {
case 1 :
return * ( unsigned char * ) ptr ;
case 2 :
return data2host2 ( ptr ) ;
case 4 :
return data2host4 ( ptr ) ;
case 8 :
return data2host8 ( ptr ) ;
default :
/* BUG! */
return 0 ;
}
}
2009-09-12 04:43:45 +04:00
unsigned long long
raw_field_value ( struct event * event , const char * name , void * data )
{
struct format_field * field ;
field = find_any_field ( event , name ) ;
if ( ! field )
return 0ULL ;
return read_size ( data + field - > offset , field - > size ) ;
}
void * raw_field_ptr ( struct event * event , const char * name , void * data )
{
struct format_field * field ;
field = find_any_field ( event , name ) ;
if ( ! field )
return NULL ;
2010-05-06 00:07:39 +04:00
if ( field - > flags & FIELD_IS_DYNAMIC ) {
2010-01-30 14:43:23 +03:00
int offset ;
offset = * ( int * ) ( data + field - > offset ) ;
offset & = 0xffff ;
return data + offset ;
}
2009-09-12 04:43:45 +04:00
return data + field - > offset ;
}
2009-08-17 18:18:07 +04:00
static int get_common_info ( const char * type , int * offset , int * size )
{
struct event * event ;
struct format_field * field ;
/*
* All events should have the same common elements .
* Pick any event to find where the type is ;
*/
if ( ! event_list )
die ( " no event_list! " ) ;
event = event_list ;
field = find_common_field ( event , type ) ;
if ( ! field )
die ( " field '%s' not found " , type ) ;
* offset = field - > offset ;
* size = field - > size ;
return 0 ;
}
2009-10-14 23:43:42 +04:00
static int __parse_common ( void * data , int * size , int * offset ,
2009-10-14 23:43:44 +04:00
const char * name )
2009-08-17 18:18:07 +04:00
{
int ret ;
2009-10-14 23:43:42 +04:00
if ( ! * size ) {
ret = get_common_info ( name , offset , size ) ;
2009-08-17 18:18:07 +04:00
if ( ret < 0 )
return ret ;
}
2009-10-14 23:43:42 +04:00
return read_size ( data + * offset , * size ) ;
}
int trace_parse_common_type ( void * data )
{
static int type_offset ;
static int type_size ;
return __parse_common ( data , & type_size , & type_offset ,
2009-10-14 23:43:44 +04:00
" common_type " ) ;
2009-08-17 18:18:07 +04:00
}
2009-11-25 10:15:48 +03:00
int trace_parse_common_pid ( void * data )
2009-08-17 18:18:07 +04:00
{
static int pid_offset ;
static int pid_size ;
2009-10-14 23:43:42 +04:00
return __parse_common ( data , & pid_size , & pid_offset ,
2009-10-14 23:43:44 +04:00
" common_pid " ) ;
2009-10-14 23:43:42 +04:00
}
2009-11-25 10:15:50 +03:00
int parse_common_pc ( void * data )
2009-10-14 23:43:42 +04:00
{
static int pc_offset ;
static int pc_size ;
return __parse_common ( data , & pc_size , & pc_offset ,
2009-10-14 23:43:44 +04:00
" common_preempt_count " ) ;
2009-10-14 23:43:42 +04:00
}
2009-11-25 10:15:50 +03:00
int parse_common_flags ( void * data )
2009-10-14 23:43:42 +04:00
{
static int flags_offset ;
static int flags_size ;
return __parse_common ( data , & flags_size , & flags_offset ,
2009-10-14 23:43:44 +04:00
" common_flags " ) ;
2009-10-14 23:43:42 +04:00
}
2009-11-25 10:15:50 +03:00
int parse_common_lock_depth ( void * data )
2009-10-14 23:43:42 +04:00
{
static int ld_offset ;
static int ld_size ;
2009-08-17 18:18:07 +04:00
int ret ;
2009-10-14 23:43:42 +04:00
ret = __parse_common ( data , & ld_size , & ld_offset ,
2009-10-14 23:43:44 +04:00
" common_lock_depth " ) ;
2009-10-14 23:43:42 +04:00
if ( ret < 0 )
return - 1 ;
2009-08-17 18:18:07 +04:00
2009-10-14 23:43:42 +04:00
return ret ;
2009-08-17 18:18:07 +04:00
}
2009-09-11 14:12:54 +04:00
struct event * trace_find_event ( int id )
2009-08-17 18:18:07 +04:00
{
struct event * event ;
for ( event = event_list ; event ; event = event - > next ) {
if ( event - > id = = id )
break ;
}
return event ;
}
2009-11-25 10:15:48 +03:00
struct event * trace_find_next_event ( struct event * event )
{
if ( ! event )
return event_list ;
return event - > next ;
}
2009-08-17 18:18:07 +04:00
static unsigned long long eval_num_arg ( void * data , int size ,
struct event * event , struct print_arg * arg )
{
unsigned long long val = 0 ;
unsigned long long left , right ;
2009-10-14 23:43:35 +04:00
struct print_arg * larg ;
2009-08-17 18:18:07 +04:00
switch ( arg - > type ) {
case PRINT_NULL :
/* ?? */
return 0 ;
case PRINT_ATOM :
return strtoull ( arg - > atom . atom , NULL , 0 ) ;
case PRINT_FIELD :
if ( ! arg - > field . field ) {
arg - > field . field = find_any_field ( event , arg - > field . name ) ;
if ( ! arg - > field . field )
die ( " field %s not found " , arg - > field . name ) ;
}
/* must be a number */
val = read_size ( data + arg - > field . field - > offset ,
arg - > field . field - > size ) ;
break ;
case PRINT_FLAGS :
case PRINT_SYMBOL :
break ;
case PRINT_TYPE :
return eval_num_arg ( data , size , event , arg - > typecast . item ) ;
case PRINT_STRING :
return 0 ;
break ;
case PRINT_OP :
2009-10-14 23:43:35 +04:00
if ( strcmp ( arg - > op . op , " [ " ) = = 0 ) {
/*
* Arrays are special , since we don ' t want
* to read the arg as is .
*/
if ( arg - > op . left - > type ! = PRINT_FIELD )
goto default_op ; /* oops, all bets off */
larg = arg - > op . left ;
if ( ! larg - > field . field ) {
larg - > field . field =
find_any_field ( event , larg - > field . name ) ;
if ( ! larg - > field . field )
die ( " field %s not found " , larg - > field . name ) ;
}
right = eval_num_arg ( data , size , event , arg - > op . right ) ;
val = read_size ( data + larg - > field . field - > offset +
right * long_size , long_size ) ;
break ;
}
default_op :
2009-08-17 18:18:07 +04:00
left = eval_num_arg ( data , size , event , arg - > op . left ) ;
right = eval_num_arg ( data , size , event , arg - > op . right ) ;
switch ( arg - > op . op [ 0 ] ) {
case ' | ' :
if ( arg - > op . op [ 1 ] )
val = left | | right ;
else
val = left | right ;
break ;
case ' & ' :
if ( arg - > op . op [ 1 ] )
val = left & & right ;
else
val = left & right ;
break ;
case ' < ' :
switch ( arg - > op . op [ 1 ] ) {
case 0 :
val = left < right ;
break ;
case ' < ' :
val = left < < right ;
break ;
case ' = ' :
val = left < = right ;
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
case ' > ' :
switch ( arg - > op . op [ 1 ] ) {
case 0 :
val = left > right ;
break ;
case ' > ' :
val = left > > right ;
break ;
case ' = ' :
val = left > = right ;
break ;
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
case ' = ' :
if ( arg - > op . op [ 1 ] ! = ' = ' )
die ( " unknown op '%s' " , arg - > op . op ) ;
val = left = = right ;
break ;
2009-10-14 23:43:43 +04:00
case ' - ' :
val = left - right ;
break ;
case ' + ' :
val = left + right ;
break ;
2009-08-17 18:18:07 +04:00
default :
die ( " unknown op '%s' " , arg - > op . op ) ;
}
break ;
default : /* not sure what to do there */
return 0 ;
}
return val ;
}
struct flag {
const char * name ;
unsigned long long value ;
} ;
static const struct flag flags [ ] = {
{ " HI_SOFTIRQ " , 0 } ,
{ " TIMER_SOFTIRQ " , 1 } ,
{ " NET_TX_SOFTIRQ " , 2 } ,
{ " NET_RX_SOFTIRQ " , 3 } ,
{ " BLOCK_SOFTIRQ " , 4 } ,
2009-10-06 10:00:48 +04:00
{ " BLOCK_IOPOLL_SOFTIRQ " , 5 } ,
{ " TASKLET_SOFTIRQ " , 6 } ,
{ " SCHED_SOFTIRQ " , 7 } ,
{ " HRTIMER_SOFTIRQ " , 8 } ,
{ " RCU_SOFTIRQ " , 9 } ,
2009-08-17 18:18:07 +04:00
{ " HRTIMER_NORESTART " , 0 } ,
{ " HRTIMER_RESTART " , 1 } ,
} ;
2009-11-25 10:15:48 +03:00
unsigned long long eval_flag ( const char * flag )
2009-08-17 18:18:07 +04:00
{
int i ;
/*
* Some flags in the format files do not get converted .
* If the flag is not numeric , see if it is something that
* we already know about .
*/
if ( isdigit ( flag [ 0 ] ) )
return strtoull ( flag , NULL , 0 ) ;
for ( i = 0 ; i < ( int ) ( sizeof ( flags ) / sizeof ( flags [ 0 ] ) ) ; i + + )
if ( strcmp ( flags [ i ] . name , flag ) = = 0 )
return flags [ i ] . value ;
return 0 ;
}
static void print_str_arg ( void * data , int size ,
struct event * event , struct print_arg * arg )
{
struct print_flag_sym * flag ;
unsigned long long val , fval ;
char * str ;
int print ;
switch ( arg - > type ) {
case PRINT_NULL :
/* ?? */
return ;
case PRINT_ATOM :
printf ( " %s " , arg - > atom . atom ) ;
return ;
case PRINT_FIELD :
if ( ! arg - > field . field ) {
arg - > field . field = find_any_field ( event , arg - > field . name ) ;
if ( ! arg - > field . field )
die ( " field %s not found " , arg - > field . name ) ;
}
str = malloc_or_die ( arg - > field . field - > size + 1 ) ;
memcpy ( str , data + arg - > field . field - > offset ,
arg - > field . field - > size ) ;
str [ arg - > field . field - > size ] = 0 ;
2009-08-28 06:46:07 +04:00
printf ( " %s " , str ) ;
2009-08-17 18:18:07 +04:00
free ( str ) ;
break ;
case PRINT_FLAGS :
val = eval_num_arg ( data , size , event , arg - > flags . field ) ;
print = 0 ;
for ( flag = arg - > flags . flags ; flag ; flag = flag - > next ) {
fval = eval_flag ( flag - > value ) ;
if ( ! val & & ! fval ) {
printf ( " %s " , flag - > str ) ;
break ;
}
if ( fval & & ( val & fval ) = = fval ) {
if ( print & & arg - > flags . delim )
printf ( " %s " , arg - > flags . delim ) ;
printf ( " %s " , flag - > str ) ;
print = 1 ;
val & = ~ fval ;
}
}
break ;
case PRINT_SYMBOL :
val = eval_num_arg ( data , size , event , arg - > symbol . field ) ;
for ( flag = arg - > symbol . symbols ; flag ; flag = flag - > next ) {
fval = eval_flag ( flag - > value ) ;
if ( val = = fval ) {
printf ( " %s " , flag - > str ) ;
break ;
}
}
break ;
case PRINT_TYPE :
break ;
2009-08-31 08:45:21 +04:00
case PRINT_STRING : {
int str_offset ;
if ( arg - > string . offset = = - 1 ) {
struct format_field * f ;
f = find_any_field ( event , arg - > string . string ) ;
arg - > string . offset = f - > offset ;
}
str_offset = * ( int * ) ( data + arg - > string . offset ) ;
str_offset & = 0xffff ;
printf ( " %s " , ( ( char * ) data ) + str_offset ) ;
2009-08-17 18:18:07 +04:00
break ;
2009-08-31 08:45:21 +04:00
}
2009-08-17 18:18:07 +04:00
case PRINT_OP :
/*
* The only op for string should be ? :
*/
if ( arg - > op . op [ 0 ] ! = ' ? ' )
return ;
val = eval_num_arg ( data , size , event , arg - > op . left ) ;
if ( val )
print_str_arg ( data , size , event , arg - > op . right - > op . left ) ;
else
print_str_arg ( data , size , event , arg - > op . right - > op . right ) ;
break ;
default :
/* well... */
break ;
}
}
static struct print_arg * make_bprint_args ( char * fmt , void * data , int size , struct event * event )
{
static struct format_field * field , * ip_field ;
struct print_arg * args , * arg , * * next ;
unsigned long long ip , val ;
char * ptr ;
void * bptr ;
if ( ! field ) {
field = find_field ( event , " buf " ) ;
if ( ! field )
die ( " can't find buffer field for binary printk " ) ;
ip_field = find_field ( event , " ip " ) ;
if ( ! ip_field )
die ( " can't find ip field for binary printk " ) ;
}
ip = read_size ( data + ip_field - > offset , ip_field - > size ) ;
/*
* The first arg is the IP pointer .
*/
args = malloc_or_die ( sizeof ( * args ) ) ;
arg = args ;
arg - > next = NULL ;
next = & arg - > next ;
arg - > type = PRINT_ATOM ;
arg - > atom . atom = malloc_or_die ( 32 ) ;
sprintf ( arg - > atom . atom , " %lld " , ip ) ;
/* skip the first "%pf : " */
for ( ptr = fmt + 6 , bptr = data + field - > offset ;
bptr < data + size & & * ptr ; ptr + + ) {
int ls = 0 ;
if ( * ptr = = ' % ' ) {
process_again :
ptr + + ;
switch ( * ptr ) {
case ' % ' :
break ;
case ' l ' :
ls + + ;
goto process_again ;
case ' L ' :
ls = 2 ;
goto process_again ;
case ' 0 ' . . . ' 9 ' :
goto process_again ;
case ' p ' :
ls = 1 ;
/* fall through */
case ' d ' :
case ' u ' :
case ' x ' :
case ' i ' :
2009-10-14 23:43:40 +04:00
/* the pointers are always 4 bytes aligned */
bptr = ( void * ) ( ( ( unsigned long ) bptr + 3 ) &
~ 3 ) ;
2009-08-17 18:18:07 +04:00
switch ( ls ) {
case 0 :
case 1 :
ls = long_size ;
break ;
case 2 :
ls = 8 ;
default :
break ;
}
val = read_size ( bptr , ls ) ;
bptr + = ls ;
arg = malloc_or_die ( sizeof ( * arg ) ) ;
arg - > next = NULL ;
arg - > type = PRINT_ATOM ;
arg - > atom . atom = malloc_or_die ( 32 ) ;
sprintf ( arg - > atom . atom , " %lld " , val ) ;
* next = arg ;
next = & arg - > next ;
break ;
case ' s ' :
arg = malloc_or_die ( sizeof ( * arg ) ) ;
arg - > next = NULL ;
arg - > type = PRINT_STRING ;
arg - > string . string = strdup ( bptr ) ;
bptr + = strlen ( bptr ) + 1 ;
* next = arg ;
next = & arg - > next ;
default :
break ;
}
}
}
return args ;
}
static void free_args ( struct print_arg * args )
{
struct print_arg * next ;
while ( args ) {
next = args - > next ;
if ( args - > type = = PRINT_ATOM )
free ( args - > atom . atom ) ;
else
free ( args - > string . string ) ;
free ( args ) ;
args = next ;
}
}
static char * get_bprint_format ( void * data , int size __unused , struct event * event )
{
unsigned long long addr ;
static struct format_field * field ;
struct printk_map * printk ;
char * format ;
char * p ;
if ( ! field ) {
field = find_field ( event , " fmt " ) ;
if ( ! field )
die ( " can't find format field for binary printk " ) ;
printf ( " field->offset = %d size=%d \n " , field - > offset , field - > size ) ;
}
addr = read_size ( data + field - > offset , field - > size ) ;
printk = find_printk ( addr ) ;
if ( ! printk ) {
format = malloc_or_die ( 45 ) ;
sprintf ( format , " %%pf : (NO FORMAT FOUND at %llx) \n " ,
addr ) ;
return format ;
}
p = printk - > printk ;
/* Remove any quotes. */
if ( * p = = ' " ' )
p + + ;
format = malloc_or_die ( strlen ( p ) + 10 ) ;
sprintf ( format , " %s : %s " , " %pf " , p ) ;
/* remove ending quotes and new line since we will add one too */
p = format + strlen ( format ) - 1 ;
if ( * p = = ' " ' )
* p = 0 ;
p - = 2 ;
if ( strcmp ( p , " \\ n " ) = = 0 )
* p = 0 ;
return format ;
}
static void pretty_print ( void * data , int size , struct event * event )
{
struct print_fmt * print_fmt = & event - > print_fmt ;
struct print_arg * arg = print_fmt - > args ;
struct print_arg * args = NULL ;
const char * ptr = print_fmt - > format ;
unsigned long long val ;
struct func_map * func ;
const char * saveptr ;
char * bprint_fmt = NULL ;
char format [ 32 ] ;
int show_func ;
int len ;
int ls ;
if ( event - > flags & EVENT_FL_ISFUNC )
ptr = " %pF <-- %pF " ;
if ( event - > flags & EVENT_FL_ISBPRINT ) {
bprint_fmt = get_bprint_format ( data , size , event ) ;
args = make_bprint_args ( bprint_fmt , data , size , event ) ;
arg = args ;
ptr = bprint_fmt ;
}
for ( ; * ptr ; ptr + + ) {
ls = 0 ;
2009-10-14 23:43:33 +04:00
if ( * ptr = = ' \\ ' ) {
ptr + + ;
switch ( * ptr ) {
case ' n ' :
printf ( " \n " ) ;
break ;
case ' t ' :
printf ( " \t " ) ;
break ;
case ' r ' :
printf ( " \r " ) ;
break ;
case ' \\ ' :
printf ( " \\ " ) ;
break ;
default :
printf ( " %c " , * ptr ) ;
break ;
}
} else if ( * ptr = = ' % ' ) {
2009-08-17 18:18:07 +04:00
saveptr = ptr ;
show_func = 0 ;
cont_process :
ptr + + ;
switch ( * ptr ) {
case ' % ' :
printf ( " %% " ) ;
break ;
case ' l ' :
ls + + ;
goto cont_process ;
case ' L ' :
ls = 2 ;
goto cont_process ;
case ' z ' :
case ' Z ' :
case ' 0 ' . . . ' 9 ' :
goto cont_process ;
case ' p ' :
if ( long_size = = 4 )
ls = 1 ;
else
ls = 2 ;
if ( * ( ptr + 1 ) = = ' F ' | |
* ( ptr + 1 ) = = ' f ' ) {
ptr + + ;
show_func = * ptr ;
}
/* fall through */
case ' d ' :
case ' i ' :
case ' x ' :
case ' X ' :
case ' u ' :
if ( ! arg )
die ( " no argument match " ) ;
len = ( ( unsigned long ) ptr + 1 ) -
( unsigned long ) saveptr ;
/* should never happen */
if ( len > 32 )
die ( " bad format! " ) ;
memcpy ( format , saveptr , len ) ;
format [ len ] = 0 ;
val = eval_num_arg ( data , size , event , arg ) ;
arg = arg - > next ;
if ( show_func ) {
func = find_func ( val ) ;
if ( func ) {
printf ( " %s " , func - > func ) ;
if ( show_func = = ' F ' )
printf ( " +0x%llx " ,
val - func - > addr ) ;
break ;
}
}
switch ( ls ) {
case 0 :
printf ( format , ( int ) val ) ;
break ;
case 1 :
printf ( format , ( long ) val ) ;
break ;
case 2 :
printf ( format , ( long long ) val ) ;
break ;
default :
die ( " bad count (%d) " , ls ) ;
}
break ;
case ' s ' :
if ( ! arg )
die ( " no matching argument " ) ;
print_str_arg ( data , size , event , arg ) ;
arg = arg - > next ;
break ;
default :
printf ( " >%c< " , * ptr ) ;
}
} else
printf ( " %c " , * ptr ) ;
}
if ( args ) {
free_args ( args ) ;
free ( bprint_fmt ) ;
}
}
static inline int log10_cpu ( int nb )
{
if ( nb / 100 )
return 3 ;
if ( nb / 10 )
return 2 ;
return 1 ;
}
2009-10-14 23:43:42 +04:00
static void print_lat_fmt ( void * data , int size __unused )
{
unsigned int lat_flags ;
unsigned int pc ;
int lock_depth ;
int hardirq ;
int softirq ;
lat_flags = parse_common_flags ( data ) ;
pc = parse_common_pc ( data ) ;
lock_depth = parse_common_lock_depth ( data ) ;
hardirq = lat_flags & TRACE_FLAG_HARDIRQ ;
softirq = lat_flags & TRACE_FLAG_SOFTIRQ ;
printf ( " %c%c%c " ,
( lat_flags & TRACE_FLAG_IRQS_OFF ) ? ' d ' :
( lat_flags & TRACE_FLAG_IRQS_NOSUPPORT ) ?
' X ' : ' . ' ,
( lat_flags & TRACE_FLAG_NEED_RESCHED ) ?
' N ' : ' . ' ,
( hardirq & & softirq ) ? ' H ' :
hardirq ? ' h ' : softirq ? ' s ' : ' . ' ) ;
if ( pc )
printf ( " %x " , pc ) ;
else
printf ( " . " ) ;
if ( lock_depth < 0 )
printf ( " . " ) ;
else
printf ( " %d " , lock_depth ) ;
}
2009-08-17 18:18:07 +04:00
/* taken from Linux, written by Frederic Weisbecker */
static void print_graph_cpu ( int cpu )
{
int i ;
int log10_this = log10_cpu ( cpu ) ;
int log10_all = log10_cpu ( cpus ) ;
/*
* Start with a space character - to make it stand out
* to the right a bit when trace output is pasted into
* email :
*/
printf ( " " ) ;
/*
* Tricky - we space the CPU field according to the max
* number of online CPUs . On a 2 - cpu system it would take
* a maximum of 1 digit - on a 128 cpu system it would
* take up to 3 digits :
*/
for ( i = 0 ; i < log10_all - log10_this ; i + + )
printf ( " " ) ;
printf ( " %d) " , cpu ) ;
}
# define TRACE_GRAPH_PROCINFO_LENGTH 14
# define TRACE_GRAPH_INDENT 2
static void print_graph_proc ( int pid , const char * comm )
{
/* sign + log10(MAX_INT) + '\0' */
char pid_str [ 11 ] ;
int spaces = 0 ;
int len ;
int i ;
sprintf ( pid_str , " %d " , pid ) ;
/* 1 stands for the "-" character */
len = strlen ( comm ) + strlen ( pid_str ) + 1 ;
if ( len < TRACE_GRAPH_PROCINFO_LENGTH )
spaces = TRACE_GRAPH_PROCINFO_LENGTH - len ;
/* First spaces to align center */
for ( i = 0 ; i < spaces / 2 ; i + + )
printf ( " " ) ;
printf ( " %s-%s " , comm , pid_str ) ;
/* Last spaces to align center */
for ( i = 0 ; i < spaces - ( spaces / 2 ) ; i + + )
printf ( " " ) ;
}
static struct record *
get_return_for_leaf ( int cpu , int cur_pid , unsigned long long cur_func ,
struct record * next )
{
struct format_field * field ;
struct event * event ;
unsigned long val ;
int type ;
int pid ;
2009-09-11 14:12:54 +04:00
type = trace_parse_common_type ( next - > data ) ;
event = trace_find_event ( type ) ;
2009-08-17 18:18:07 +04:00
if ( ! event )
return NULL ;
if ( ! ( event - > flags & EVENT_FL_ISFUNCRET ) )
return NULL ;
2009-11-25 10:15:48 +03:00
pid = trace_parse_common_pid ( next - > data ) ;
2009-08-17 18:18:07 +04:00
field = find_field ( event , " func " ) ;
if ( ! field )
die ( " function return does not have field func " ) ;
val = read_size ( next - > data + field - > offset , field - > size ) ;
if ( cur_pid ! = pid | | cur_func ! = val )
return NULL ;
/* this is a leaf, now advance the iterator */
return trace_read_data ( cpu ) ;
}
/* Signal a overhead of time execution to the output */
static void print_graph_overhead ( unsigned long long duration )
{
/* Non nested entry or return */
if ( duration = = ~ 0ULL )
return ( void ) printf ( " " ) ;
/* Duration exceeded 100 msecs */
if ( duration > 100000ULL )
return ( void ) printf ( " ! " ) ;
/* Duration exceeded 10 msecs */
if ( duration > 10000ULL )
return ( void ) printf ( " + " ) ;
printf ( " " ) ;
}
static void print_graph_duration ( unsigned long long duration )
{
unsigned long usecs = duration / 1000 ;
unsigned long nsecs_rem = duration % 1000 ;
/* log10(ULONG_MAX) + '\0' */
char msecs_str [ 21 ] ;
char nsecs_str [ 5 ] ;
int len ;
int i ;
sprintf ( msecs_str , " %lu " , usecs ) ;
/* Print msecs */
len = printf ( " %lu " , usecs ) ;
/* Print nsecs (we don't want to exceed 7 numbers) */
if ( len < 7 ) {
snprintf ( nsecs_str , 8 - len , " %03lu " , nsecs_rem ) ;
len + = printf ( " .%s " , nsecs_str ) ;
}
printf ( " us " ) ;
/* Print remaining spaces to fit the row's width */
for ( i = len ; i < 7 ; i + + )
printf ( " " ) ;
printf ( " | " ) ;
}
static void
print_graph_entry_leaf ( struct event * event , void * data , struct record * ret_rec )
{
unsigned long long rettime , calltime ;
unsigned long long duration , depth ;
unsigned long long val ;
struct format_field * field ;
struct func_map * func ;
struct event * ret_event ;
int type ;
int i ;
2009-09-11 14:12:54 +04:00
type = trace_parse_common_type ( ret_rec - > data ) ;
ret_event = trace_find_event ( type ) ;
2009-08-17 18:18:07 +04:00
field = find_field ( ret_event , " rettime " ) ;
if ( ! field )
die ( " can't find rettime in return graph " ) ;
rettime = read_size ( ret_rec - > data + field - > offset , field - > size ) ;
field = find_field ( ret_event , " calltime " ) ;
if ( ! field )
die ( " can't find rettime in return graph " ) ;
calltime = read_size ( ret_rec - > data + field - > offset , field - > size ) ;
duration = rettime - calltime ;
/* Overhead */
print_graph_overhead ( duration ) ;
/* Duration */
print_graph_duration ( duration ) ;
field = find_field ( event , " depth " ) ;
if ( ! field )
die ( " can't find depth in entry graph " ) ;
depth = read_size ( data + field - > offset , field - > size ) ;
/* Function */
for ( i = 0 ; i < ( int ) ( depth * TRACE_GRAPH_INDENT ) ; i + + )
printf ( " " ) ;
field = find_field ( event , " func " ) ;
if ( ! field )
die ( " can't find func in entry graph " ) ;
val = read_size ( data + field - > offset , field - > size ) ;
func = find_func ( val ) ;
if ( func )
printf ( " %s(); " , func - > func ) ;
else
printf ( " %llx(); " , val ) ;
}
static void print_graph_nested ( struct event * event , void * data )
{
struct format_field * field ;
unsigned long long depth ;
unsigned long long val ;
struct func_map * func ;
int i ;
/* No overhead */
print_graph_overhead ( - 1 ) ;
/* No time */
printf ( " | " ) ;
field = find_field ( event , " depth " ) ;
if ( ! field )
die ( " can't find depth in entry graph " ) ;
depth = read_size ( data + field - > offset , field - > size ) ;
/* Function */
for ( i = 0 ; i < ( int ) ( depth * TRACE_GRAPH_INDENT ) ; i + + )
printf ( " " ) ;
field = find_field ( event , " func " ) ;
if ( ! field )
die ( " can't find func in entry graph " ) ;
val = read_size ( data + field - > offset , field - > size ) ;
func = find_func ( val ) ;
if ( func )
printf ( " %s() { " , func - > func ) ;
else
printf ( " %llx() { " , val ) ;
}
static void
pretty_print_func_ent ( void * data , int size , struct event * event ,
int cpu , int pid , const char * comm ,
unsigned long secs , unsigned long usecs )
{
struct format_field * field ;
struct record * rec ;
void * copy_data ;
unsigned long val ;
printf ( " %5lu.%06lu | " , secs , usecs ) ;
print_graph_cpu ( cpu ) ;
print_graph_proc ( pid , comm ) ;
printf ( " | " ) ;
2009-10-14 23:43:42 +04:00
if ( latency_format ) {
print_lat_fmt ( data , size ) ;
printf ( " | " ) ;
}
2009-08-17 18:18:07 +04:00
field = find_field ( event , " func " ) ;
if ( ! field )
die ( " function entry does not have func field " ) ;
val = read_size ( data + field - > offset , field - > size ) ;
/*
* peek_data may unmap the data pointer . Copy it first .
*/
copy_data = malloc_or_die ( size ) ;
memcpy ( copy_data , data , size ) ;
data = copy_data ;
rec = trace_peek_data ( cpu ) ;
if ( rec ) {
rec = get_return_for_leaf ( cpu , pid , val , rec ) ;
if ( rec ) {
print_graph_entry_leaf ( event , data , rec ) ;
goto out_free ;
}
}
print_graph_nested ( event , data ) ;
out_free :
free ( data ) ;
}
static void
pretty_print_func_ret ( void * data , int size __unused , struct event * event ,
int cpu , int pid , const char * comm ,
unsigned long secs , unsigned long usecs )
{
unsigned long long rettime , calltime ;
unsigned long long duration , depth ;
struct format_field * field ;
int i ;
printf ( " %5lu.%06lu | " , secs , usecs ) ;
print_graph_cpu ( cpu ) ;
print_graph_proc ( pid , comm ) ;
printf ( " | " ) ;
2009-10-14 23:43:42 +04:00
if ( latency_format ) {
print_lat_fmt ( data , size ) ;
printf ( " | " ) ;
}
2009-08-17 18:18:07 +04:00
field = find_field ( event , " rettime " ) ;
if ( ! field )
die ( " can't find rettime in return graph " ) ;
rettime = read_size ( data + field - > offset , field - > size ) ;
field = find_field ( event , " calltime " ) ;
if ( ! field )
die ( " can't find calltime in return graph " ) ;
calltime = read_size ( data + field - > offset , field - > size ) ;
duration = rettime - calltime ;
/* Overhead */
print_graph_overhead ( duration ) ;
/* Duration */
print_graph_duration ( duration ) ;
field = find_field ( event , " depth " ) ;
if ( ! field )
die ( " can't find depth in entry graph " ) ;
depth = read_size ( data + field - > offset , field - > size ) ;
/* Function */
for ( i = 0 ; i < ( int ) ( depth * TRACE_GRAPH_INDENT ) ; i + + )
printf ( " " ) ;
printf ( " } " ) ;
}
static void
pretty_print_func_graph ( void * data , int size , struct event * event ,
int cpu , int pid , const char * comm ,
unsigned long secs , unsigned long usecs )
{
if ( event - > flags & EVENT_FL_ISFUNCENT )
pretty_print_func_ent ( data , size , event ,
cpu , pid , comm , secs , usecs ) ;
else if ( event - > flags & EVENT_FL_ISFUNCRET )
pretty_print_func_ret ( data , size , event ,
cpu , pid , comm , secs , usecs ) ;
printf ( " \n " ) ;
}
void print_event ( int cpu , void * data , int size , unsigned long long nsecs ,
char * comm )
{
struct event * event ;
unsigned long secs ;
unsigned long usecs ;
int type ;
int pid ;
secs = nsecs / NSECS_PER_SEC ;
nsecs - = secs * NSECS_PER_SEC ;
usecs = nsecs / NSECS_PER_USEC ;
2009-09-11 14:12:54 +04:00
type = trace_parse_common_type ( data ) ;
2009-08-17 18:18:07 +04:00
2009-09-11 14:12:54 +04:00
event = trace_find_event ( type ) ;
2009-09-13 20:15:54 +04:00
if ( ! event ) {
2009-10-14 23:43:39 +04:00
warning ( " ug! no event found for type %d " , type ) ;
2009-09-13 20:15:54 +04:00
return ;
}
2009-08-17 18:18:07 +04:00
2009-11-25 10:15:48 +03:00
pid = trace_parse_common_pid ( data ) ;
2009-08-17 18:18:07 +04:00
if ( event - > flags & ( EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET ) )
return pretty_print_func_graph ( data , size , event , cpu ,
pid , comm , secs , usecs ) ;
2009-10-14 23:43:42 +04:00
if ( latency_format ) {
printf ( " %8.8s-%-5d %3d " ,
comm , pid , cpu ) ;
print_lat_fmt ( data , size ) ;
} else
printf ( " %16s-%-5d [%03d] " , comm , pid , cpu ) ;
printf ( " %5lu.%06lu: %s: " , secs , usecs , event - > name ) ;
2009-08-17 18:18:07 +04:00
2009-10-14 23:43:39 +04:00
if ( event - > flags & EVENT_FL_FAILED ) {
printf ( " EVENT '%s' FAILED TO PARSE \n " ,
event - > name ) ;
return ;
}
2009-08-17 18:18:07 +04:00
pretty_print ( data , size , event ) ;
printf ( " \n " ) ;
}
static void print_fields ( struct print_flag_sym * field )
{
printf ( " { %s, %s } " , field - > value , field - > str ) ;
if ( field - > next ) {
printf ( " , " ) ;
print_fields ( field - > next ) ;
}
}
static void print_args ( struct print_arg * args )
{
int print_paren = 1 ;
switch ( args - > type ) {
case PRINT_NULL :
printf ( " null " ) ;
break ;
case PRINT_ATOM :
printf ( " %s " , args - > atom . atom ) ;
break ;
case PRINT_FIELD :
printf ( " REC->%s " , args - > field . name ) ;
break ;
case PRINT_FLAGS :
printf ( " __print_flags( " ) ;
print_args ( args - > flags . field ) ;
printf ( " , %s, " , args - > flags . delim ) ;
print_fields ( args - > flags . flags ) ;
printf ( " ) " ) ;
break ;
case PRINT_SYMBOL :
printf ( " __print_symbolic( " ) ;
print_args ( args - > symbol . field ) ;
printf ( " , " ) ;
print_fields ( args - > symbol . symbols ) ;
printf ( " ) " ) ;
break ;
case PRINT_STRING :
printf ( " __get_str(%s) " , args - > string . string ) ;
break ;
case PRINT_TYPE :
printf ( " (%s) " , args - > typecast . type ) ;
print_args ( args - > typecast . item ) ;
break ;
case PRINT_OP :
if ( strcmp ( args - > op . op , " : " ) = = 0 )
print_paren = 0 ;
if ( print_paren )
printf ( " ( " ) ;
print_args ( args - > op . left ) ;
printf ( " %s " , args - > op . op ) ;
print_args ( args - > op . right ) ;
if ( print_paren )
printf ( " ) " ) ;
break ;
default :
/* we should warn... */
return ;
}
if ( args - > next ) {
printf ( " \n " ) ;
print_args ( args - > next ) ;
}
}
int parse_ftrace_file ( char * buf , unsigned long size )
{
struct format_field * field ;
struct print_arg * arg , * * list ;
struct event * event ;
int ret ;
init_input_buf ( buf , size ) ;
event = alloc_event ( ) ;
if ( ! event )
return - ENOMEM ;
event - > flags | = EVENT_FL_ISFTRACE ;
event - > name = event_read_name ( ) ;
if ( ! event - > name )
die ( " failed to read ftrace event name " ) ;
if ( strcmp ( event - > name , " function " ) = = 0 )
event - > flags | = EVENT_FL_ISFUNC ;
else if ( strcmp ( event - > name , " funcgraph_entry " ) = = 0 )
event - > flags | = EVENT_FL_ISFUNCENT ;
else if ( strcmp ( event - > name , " funcgraph_exit " ) = = 0 )
event - > flags | = EVENT_FL_ISFUNCRET ;
else if ( strcmp ( event - > name , " bprint " ) = = 0 )
event - > flags | = EVENT_FL_ISBPRINT ;
event - > id = event_read_id ( ) ;
if ( event - > id < 0 )
die ( " failed to read ftrace event id " ) ;
add_event ( event ) ;
ret = event_read_format ( event ) ;
if ( ret < 0 )
die ( " failed to read ftrace event format " ) ;
ret = event_read_print ( event ) ;
if ( ret < 0 )
die ( " failed to read ftrace event print fmt " ) ;
2009-10-14 23:43:41 +04:00
/* New ftrace handles args */
if ( ret > 0 )
return 0 ;
2009-08-17 18:18:07 +04:00
/*
* The arguments for ftrace files are parsed by the fields .
* Set up the fields as their arguments .
*/
list = & event - > print_fmt . args ;
for ( field = event - > format . fields ; field ; field = field - > next ) {
arg = malloc_or_die ( sizeof ( * arg ) ) ;
memset ( arg , 0 , sizeof ( * arg ) ) ;
* list = arg ;
list = & arg - > next ;
arg - > type = PRINT_FIELD ;
arg - > field . name = field - > name ;
arg - > field . field = field ;
}
return 0 ;
}
2009-10-06 10:09:51 +04:00
int parse_event_file ( char * buf , unsigned long size , char * sys )
2009-08-17 18:18:07 +04:00
{
struct event * event ;
int ret ;
init_input_buf ( buf , size ) ;
event = alloc_event ( ) ;
if ( ! event )
return - ENOMEM ;
event - > name = event_read_name ( ) ;
if ( ! event - > name )
die ( " failed to read event name " ) ;
event - > id = event_read_id ( ) ;
if ( event - > id < 0 )
die ( " failed to read event id " ) ;
ret = event_read_format ( event ) ;
2009-10-14 23:43:39 +04:00
if ( ret < 0 ) {
warning ( " failed to read event format for %s " , event - > name ) ;
goto event_failed ;
}
2009-08-17 18:18:07 +04:00
ret = event_read_print ( event ) ;
2009-10-14 23:43:39 +04:00
if ( ret < 0 ) {
warning ( " failed to read event print fmt for %s " , event - > name ) ;
goto event_failed ;
}
2009-08-17 18:18:07 +04:00
2009-10-06 10:09:51 +04:00
event - > system = strdup ( sys ) ;
2009-08-17 18:18:07 +04:00
# define PRINT_ARGS 0
if ( PRINT_ARGS & & event - > print_fmt . args )
print_args ( event - > print_fmt . args ) ;
add_event ( event ) ;
return 0 ;
2009-10-14 23:43:39 +04:00
event_failed :
event - > flags | = EVENT_FL_FAILED ;
/* still add it even if it failed */
add_event ( event ) ;
return - 1 ;
2009-08-17 18:18:07 +04:00
}
void parse_set_info ( int nr_cpus , int long_sz )
{
cpus = nr_cpus ;
long_size = long_sz ;
}
2010-01-27 11:27:54 +03:00
int common_pc ( struct scripting_context * context )
{
return parse_common_pc ( context - > event_data ) ;
}
int common_flags ( struct scripting_context * context )
{
return parse_common_flags ( context - > event_data ) ;
}
int common_lock_depth ( struct scripting_context * context )
{
return parse_common_lock_depth ( context - > event_data ) ;
}