2009-08-17 18:18:06 +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
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <dirent.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <stdarg.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/mman.h>
# include <fcntl.h>
# include <unistd.h>
# include <errno.h>
2009-08-28 05:09:58 +04:00
# include "../perf.h"
2009-08-17 18:18:06 +04:00
# include "util.h"
# include "trace-event.h"
2014-07-15 01:46:48 +04:00
# include "debug.h"
2009-08-17 18:18:06 +04:00
static int input_fd ;
2013-03-21 11:18:52 +04:00
static ssize_t trace_data_size ;
2010-05-01 10:41:20 +04:00
static bool repipe ;
2010-04-02 08:59:21 +04:00
2013-03-21 11:18:50 +04:00
static int __do_read ( int fd , void * buf , int size )
2010-04-02 08:59:21 +04:00
{
int rsize = size ;
while ( size ) {
int ret = read ( fd , buf , size ) ;
if ( ret < = 0 )
return - 1 ;
2010-05-01 10:41:20 +04:00
if ( repipe ) {
int retw = write ( STDOUT_FILENO , buf , ret ) ;
2013-03-21 11:18:50 +04:00
if ( retw < = 0 | | retw ! = ret ) {
pr_debug ( " repiping input file " ) ;
return - 1 ;
}
2010-05-01 10:41:20 +04:00
}
2010-04-02 08:59:21 +04:00
size - = ret ;
buf + = ret ;
}
return rsize ;
}
2013-03-21 11:18:50 +04:00
static int do_read ( void * data , int size )
2009-08-17 18:18:06 +04:00
{
int r ;
2013-03-21 11:18:50 +04:00
r = __do_read ( input_fd , data , size ) ;
if ( r < = 0 ) {
pr_debug ( " reading input file (size expected=%d received=%d) " ,
size , r ) ;
return - 1 ;
}
2010-04-02 08:59:21 +04:00
2013-03-21 11:18:52 +04:00
trace_data_size + = r ;
2010-04-02 08:59:21 +04:00
2009-08-17 18:18:06 +04:00
return r ;
}
2010-05-05 08:02:10 +04:00
/* If it fails, the next read will report it */
static void skip ( int size )
{
char buf [ BUFSIZ ] ;
int r ;
while ( size ) {
r = size > BUFSIZ ? BUFSIZ : size ;
2013-03-21 11:18:50 +04:00
do_read ( buf , r ) ;
2010-05-05 08:02:10 +04:00
size - = r ;
} ;
}
2012-06-27 20:08:42 +04:00
static unsigned int read4 ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned int data ;
2013-03-21 11:18:50 +04:00
if ( do_read ( & data , 4 ) < 0 )
return 0 ;
2012-06-27 20:08:42 +04:00
return __data2host4 ( pevent , data ) ;
2009-08-17 18:18:06 +04:00
}
2012-06-27 20:08:42 +04:00
static unsigned long long read8 ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned long long data ;
2013-03-21 11:18:50 +04:00
if ( do_read ( & data , 8 ) < 0 )
return 0 ;
2012-06-27 20:08:42 +04:00
return __data2host8 ( pevent , data ) ;
2009-08-17 18:18:06 +04:00
}
static char * read_string ( void )
{
char buf [ BUFSIZ ] ;
char * str = NULL ;
int size = 0 ;
2010-02-04 11:46:42 +03:00
off_t r ;
2010-04-02 08:59:21 +04:00
char c ;
2009-08-17 18:18:06 +04:00
for ( ; ; ) {
2010-04-02 08:59:21 +04:00
r = read ( input_fd , & c , 1 ) ;
2013-03-21 11:18:51 +04:00
if ( r < 0 ) {
pr_debug ( " reading input file " ) ;
goto out ;
}
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:51 +04:00
if ( ! r ) {
pr_debug ( " no data " ) ;
goto out ;
}
2009-08-17 18:18:06 +04:00
2010-05-01 10:41:20 +04:00
if ( repipe ) {
int retw = write ( STDOUT_FILENO , & c , 1 ) ;
2013-03-21 11:18:51 +04:00
if ( retw < = 0 | | retw ! = r ) {
pr_debug ( " repiping input file string " ) ;
goto out ;
}
2010-05-01 10:41:20 +04:00
}
2010-04-02 08:59:21 +04:00
buf [ size + + ] = c ;
2009-08-17 18:18:06 +04:00
2010-04-02 08:59:21 +04:00
if ( ! c )
break ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:52 +04:00
trace_data_size + = size ;
2010-04-02 08:59:21 +04:00
2013-03-21 11:18:49 +04:00
str = malloc ( size ) ;
if ( str )
memcpy ( str , buf , size ) ;
2013-03-21 11:18:51 +04:00
out :
2009-08-17 18:18:06 +04:00
return str ;
}
2013-03-21 11:18:49 +04:00
static int read_proc_kallsyms ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned int size ;
2012-06-27 20:08:42 +04:00
size = read4 ( pevent ) ;
2009-08-17 18:18:06 +04:00
if ( ! size )
2013-03-21 11:18:49 +04:00
return 0 ;
2015-07-22 22:48:16 +03:00
/*
* Just skip it , now that we configure libtraceevent to use the
* tools / perf / symbol resolver .
*
* We need to skip it so that we can continue parsing old perf . data
* files , that contains this / proc / kallsyms payload .
*
* Newer perf . data files will have just the 4 - bytes zeros " kallsyms
* payload " , so that older tools can continue reading it and interpret
* it as " no kallsyms payload is present " .
*/
lseek ( input_fd , size , SEEK_CUR ) ;
trace_data_size + = size ;
2013-03-21 11:18:49 +04:00
return 0 ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_ftrace_printk ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned int size ;
char * buf ;
2013-03-21 11:18:50 +04:00
/* it can have 0 size */
2012-06-27 20:08:42 +04:00
size = read4 ( pevent ) ;
2009-08-17 18:18:06 +04:00
if ( ! size )
2013-03-21 11:18:49 +04:00
return 0 ;
2017-03-22 16:06:23 +03:00
buf = malloc ( size + 1 ) ;
2013-03-21 11:18:49 +04:00
if ( buf = = NULL )
return - 1 ;
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , size ) < 0 ) {
free ( buf ) ;
return - 1 ;
}
2009-08-17 18:18:06 +04:00
2017-03-22 16:06:23 +03:00
buf [ size ] = ' \0 ' ;
2012-06-27 20:08:42 +04:00
parse_ftrace_printk ( pevent , buf , size ) ;
2009-08-17 18:18:06 +04:00
free ( buf ) ;
2013-03-21 11:18:49 +04:00
return 0 ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_header_files ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned long long size ;
2013-06-04 09:20:26 +04:00
char * header_page ;
2009-08-17 18:18:06 +04:00
char buf [ BUFSIZ ] ;
2013-03-21 11:18:50 +04:00
int ret = 0 ;
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , 12 ) < 0 )
return - 1 ;
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:51 +04:00
if ( memcmp ( buf , " header_page " , 12 ) ! = 0 ) {
pr_debug ( " did not read header page " ) ;
return - 1 ;
}
2009-08-17 18:18:06 +04:00
2012-06-27 20:08:42 +04:00
size = read8 ( pevent ) ;
2013-06-04 09:20:26 +04:00
header_page = malloc ( size ) ;
if ( header_page = = NULL )
return - 1 ;
if ( do_read ( header_page , size ) < 0 ) {
pr_debug ( " did not read header page " ) ;
free ( header_page ) ;
return - 1 ;
}
if ( ! pevent_parse_header_page ( pevent , header_page , size ,
pevent_get_long_size ( pevent ) ) ) {
/*
* The commit field in the page is of type long ,
* use that instead , since it represents the kernel .
*/
pevent_set_long_size ( pevent , pevent - > header_page_size_size ) ;
}
free ( header_page ) ;
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , 13 ) < 0 )
return - 1 ;
2013-03-21 11:18:51 +04:00
if ( memcmp ( buf , " header_event " , 13 ) ! = 0 ) {
pr_debug ( " did not read header event " ) ;
return - 1 ;
}
2009-08-17 18:18:06 +04:00
2012-06-27 20:08:42 +04:00
size = read8 ( pevent ) ;
2013-06-04 09:20:25 +04:00
skip ( size ) ;
2013-03-21 11:18:50 +04:00
return ret ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_ftrace_file ( struct pevent * pevent , unsigned long long size )
2009-08-17 18:18:06 +04:00
{
2013-04-18 16:24:16 +04:00
int ret ;
2009-08-17 18:18:06 +04:00
char * buf ;
2013-03-21 11:18:49 +04:00
buf = malloc ( size ) ;
2013-04-18 16:24:16 +04:00
if ( buf = = NULL ) {
pr_debug ( " memory allocation failure \n " ) ;
2013-03-21 11:18:49 +04:00
return - 1 ;
2013-04-18 16:24:16 +04:00
}
2013-03-21 11:18:49 +04:00
2013-04-18 16:24:16 +04:00
ret = do_read ( buf , size ) ;
if ( ret < 0 ) {
pr_debug ( " error reading ftrace file. \n " ) ;
goto out ;
2013-03-21 11:18:50 +04:00
}
2013-04-18 16:24:16 +04:00
ret = parse_ftrace_file ( pevent , buf , size ) ;
if ( ret < 0 )
pr_debug ( " error parsing ftrace file. \n " ) ;
out :
2009-08-17 18:18:06 +04:00
free ( buf ) ;
2013-04-18 16:24:16 +04:00
return ret ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_event_file ( struct pevent * pevent , char * sys ,
2012-06-27 20:08:42 +04:00
unsigned long long size )
2009-08-17 18:18:06 +04:00
{
2013-04-18 16:24:16 +04:00
int ret ;
2009-08-17 18:18:06 +04:00
char * buf ;
2013-03-21 11:18:49 +04:00
buf = malloc ( size ) ;
2013-04-18 16:24:16 +04:00
if ( buf = = NULL ) {
pr_debug ( " memory allocation failure \n " ) ;
2013-03-21 11:18:49 +04:00
return - 1 ;
2013-04-18 16:24:16 +04:00
}
2013-03-21 11:18:49 +04:00
2013-04-18 16:24:16 +04:00
ret = do_read ( buf , size ) ;
if ( ret < 0 ) {
2013-03-21 11:18:50 +04:00
free ( buf ) ;
2013-04-18 16:24:16 +04:00
goto out ;
2013-03-21 11:18:50 +04:00
}
2013-04-18 16:24:16 +04:00
ret = parse_event_file ( pevent , buf , size , sys ) ;
if ( ret < 0 )
pr_debug ( " error parsing event file. \n " ) ;
out :
2009-08-17 18:18:06 +04:00
free ( buf ) ;
2013-04-18 16:24:16 +04:00
return ret ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_ftrace_files ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned long long size ;
int count ;
int i ;
2013-03-21 11:18:49 +04:00
int ret ;
2009-08-17 18:18:06 +04:00
2012-06-27 20:08:42 +04:00
count = read4 ( pevent ) ;
2009-08-17 18:18:06 +04:00
for ( i = 0 ; i < count ; i + + ) {
2012-06-27 20:08:42 +04:00
size = read8 ( pevent ) ;
2013-03-21 11:18:49 +04:00
ret = read_ftrace_file ( pevent , size ) ;
if ( ret )
return ret ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
return 0 ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:49 +04:00
static int read_event_files ( struct pevent * pevent )
2009-08-17 18:18:06 +04:00
{
unsigned long long size ;
char * sys ;
int systems ;
int count ;
int i , x ;
2013-03-21 11:18:49 +04:00
int ret ;
2009-08-17 18:18:06 +04:00
2012-06-27 20:08:42 +04:00
systems = read4 ( pevent ) ;
2009-08-17 18:18:06 +04:00
for ( i = 0 ; i < systems ; i + + ) {
sys = read_string ( ) ;
2013-03-21 11:18:49 +04:00
if ( sys = = NULL )
return - 1 ;
2009-08-17 18:18:06 +04:00
2012-06-27 20:08:42 +04:00
count = read4 ( pevent ) ;
2013-03-21 11:18:50 +04:00
2009-08-17 18:18:06 +04:00
for ( x = 0 ; x < count ; x + + ) {
2012-06-27 20:08:42 +04:00
size = read8 ( pevent ) ;
2013-03-21 11:18:49 +04:00
ret = read_event_file ( pevent , sys , size ) ;
if ( ret )
return ret ;
2009-08-17 18:18:06 +04:00
}
}
2013-03-21 11:18:49 +04:00
return 0 ;
2009-08-17 18:18:06 +04:00
}
2013-04-11 12:25:04 +04:00
static int read_saved_cmdline ( struct pevent * pevent )
{
unsigned long long size ;
char * buf ;
2013-04-18 16:24:16 +04:00
int ret ;
2013-04-11 12:25:04 +04:00
/* it can have 0 size */
size = read8 ( pevent ) ;
if ( ! size )
return 0 ;
buf = malloc ( size + 1 ) ;
2013-04-18 16:24:16 +04:00
if ( buf = = NULL ) {
pr_debug ( " memory allocation failure \n " ) ;
2013-04-11 12:25:04 +04:00
return - 1 ;
2013-04-18 16:24:16 +04:00
}
2013-04-11 12:25:04 +04:00
2013-04-18 16:24:16 +04:00
ret = do_read ( buf , size ) ;
if ( ret < 0 ) {
pr_debug ( " error reading saved cmdlines \n " ) ;
goto out ;
2013-04-11 12:25:04 +04:00
}
parse_saved_cmdline ( pevent , buf , size ) ;
2013-04-18 16:24:16 +04:00
ret = 0 ;
out :
2013-04-11 12:25:04 +04:00
free ( buf ) ;
2013-04-18 16:24:16 +04:00
return ret ;
2013-04-11 12:25:04 +04:00
}
2013-12-03 17:09:23 +04:00
ssize_t trace_report ( int fd , struct trace_event * tevent , bool __repipe )
2009-08-17 18:18:06 +04:00
{
char buf [ BUFSIZ ] ;
char test [ ] = { 23 , 8 , 68 } ;
char * version ;
2009-09-12 12:08:34 +04:00
int show_version = 0 ;
2009-08-17 18:18:06 +04:00
int show_funcs = 0 ;
int show_printk = 0 ;
2013-03-21 11:18:48 +04:00
ssize_t size = - 1 ;
2013-06-04 09:20:24 +04:00
int file_bigendian ;
int host_bigendian ;
2013-06-04 09:20:23 +04:00
int file_long_size ;
2013-06-04 09:20:22 +04:00
int file_page_size ;
2013-12-03 17:09:23 +04:00
struct pevent * pevent = NULL ;
2013-03-21 11:18:49 +04:00
int err ;
2013-03-21 11:18:48 +04:00
2010-05-01 10:41:20 +04:00
repipe = __repipe ;
2009-10-07 01:36:47 +04:00
input_fd = fd ;
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , 3 ) < 0 )
return - 1 ;
2013-03-21 11:18:51 +04:00
if ( memcmp ( buf , test , 3 ) ! = 0 ) {
pr_debug ( " no trace data in the file " ) ;
return - 1 ;
}
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , 7 ) < 0 )
return - 1 ;
2013-03-21 11:18:51 +04:00
if ( memcmp ( buf , " tracing " , 7 ) ! = 0 ) {
pr_debug ( " not a trace file (missing 'tracing' tag) " ) ;
return - 1 ;
}
2009-08-17 18:18:06 +04:00
version = read_string ( ) ;
2013-03-21 11:18:49 +04:00
if ( version = = NULL )
return - 1 ;
2009-09-12 12:08:34 +04:00
if ( show_version )
printf ( " version = %s \n " , version ) ;
2009-08-17 18:18:06 +04:00
2013-04-11 12:25:04 +04:00
if ( do_read ( buf , 1 ) < 0 ) {
free ( version ) ;
2013-03-21 11:18:50 +04:00
return - 1 ;
2013-04-11 12:25:04 +04:00
}
2009-08-17 18:18:06 +04:00
file_bigendian = buf [ 0 ] ;
host_bigendian = bigendian ( ) ;
2013-12-03 17:09:23 +04:00
if ( trace_event__init ( tevent ) ) {
pr_debug ( " trace_event__init failed " ) ;
2013-03-21 11:18:48 +04:00
goto out ;
}
2012-04-06 02:47:56 +04:00
2013-12-03 17:09:23 +04:00
pevent = tevent - > pevent ;
pevent_set_flag ( pevent , PEVENT_NSEC_OUTPUT ) ;
pevent_set_file_bigendian ( pevent , file_bigendian ) ;
pevent_set_host_bigendian ( pevent , host_bigendian ) ;
2013-03-21 11:18:50 +04:00
if ( do_read ( buf , 1 ) < 0 )
goto out ;
2013-06-04 09:20:23 +04:00
file_long_size = buf [ 0 ] ;
2009-08-17 18:18:06 +04:00
2013-06-04 09:20:22 +04:00
file_page_size = read4 ( pevent ) ;
if ( ! file_page_size )
2013-03-21 11:18:50 +04:00
goto out ;
2009-08-17 18:18:06 +04:00
2013-06-04 09:20:23 +04:00
pevent_set_long_size ( pevent , file_long_size ) ;
2013-06-04 09:20:22 +04:00
pevent_set_page_size ( pevent , file_page_size ) ;
2013-03-21 11:18:49 +04:00
err = read_header_files ( pevent ) ;
if ( err )
goto out ;
err = read_ftrace_files ( pevent ) ;
if ( err )
goto out ;
err = read_event_files ( pevent ) ;
if ( err )
goto out ;
err = read_proc_kallsyms ( pevent ) ;
if ( err )
goto out ;
err = read_ftrace_printk ( pevent ) ;
if ( err )
goto out ;
2013-04-11 12:25:04 +04:00
if ( atof ( version ) > = 0.6 ) {
err = read_saved_cmdline ( pevent ) ;
if ( err )
goto out ;
}
2009-08-17 18:18:06 +04:00
2013-03-21 11:18:52 +04:00
size = trace_data_size ;
2010-05-01 10:41:20 +04:00
repipe = false ;
2010-04-02 08:59:21 +04:00
2009-08-17 18:18:06 +04:00
if ( show_funcs ) {
2013-03-21 11:18:48 +04:00
pevent_print_funcs ( pevent ) ;
} else if ( show_printk ) {
pevent_print_printk ( pevent ) ;
2009-08-17 18:18:06 +04:00
}
2013-03-21 11:18:48 +04:00
pevent = NULL ;
out :
if ( pevent )
2013-12-03 17:09:23 +04:00
trace_event__cleanup ( tevent ) ;
2013-04-11 12:25:04 +04:00
free ( version ) ;
2010-04-02 08:59:21 +04:00
return size ;
2009-08-17 18:18:06 +04:00
}