2009-11-30 19:19:58 -05:00
/*
* probe - event . c : perf - probe definition to kprobe_events format converter
*
* Written by Masami Hiramatsu < mhiramat @ 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 ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*
*/
# define _GNU_SOURCE
# include <sys/utsname.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <errno.h>
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
2009-11-30 19:20:17 -05:00
# include <stdarg.h>
# include <limits.h>
2009-11-30 19:19:58 -05:00
# undef _GNU_SOURCE
# include "event.h"
2009-11-30 19:20:05 -05:00
# include "string.h"
2009-11-30 19:20:17 -05:00
# include "strlist.h"
2009-11-30 19:19:58 -05:00
# include "debug.h"
2010-01-05 17:47:10 -05:00
# include "cache.h"
2010-01-06 09:45:34 -05:00
# include "color.h"
2009-11-30 19:19:58 -05:00
# include "parse-events.h" /* For debugfs_path */
# include "probe-event.h"
# define MAX_CMDLEN 256
# define MAX_PROBE_ARGS 128
# define PERFPROBE_GROUP "probe"
# define semantic_error(msg ...) die("Semantic error :" msg)
2009-11-30 19:20:17 -05:00
/* If there is no space to write, returns -E2BIG. */
2009-12-07 12:00:53 -05:00
static int e_snprintf ( char * str , size_t size , const char * format , . . . )
__attribute__ ( ( format ( printf , 3 , 4 ) ) ) ;
2009-11-30 19:20:17 -05:00
static int e_snprintf ( char * str , size_t size , const char * format , . . . )
{
int ret ;
va_list ap ;
va_start ( ap , format ) ;
ret = vsnprintf ( str , size , format , ap ) ;
va_end ( ap ) ;
if ( ret > = ( int ) size )
ret = - E2BIG ;
return ret ;
}
2010-01-06 09:45:34 -05:00
void parse_line_range_desc ( const char * arg , struct line_range * lr )
{
const char * ptr ;
char * tmp ;
/*
* < Syntax >
* SRC : SLN [ + NUM | - ELN ]
* FUNC [ : SLN [ + NUM | - ELN ] ]
*/
ptr = strchr ( arg , ' : ' ) ;
if ( ptr ) {
lr - > start = ( unsigned int ) strtoul ( ptr + 1 , & tmp , 0 ) ;
if ( * tmp = = ' + ' )
lr - > end = lr - > start + ( unsigned int ) strtoul ( tmp + 1 ,
& tmp , 0 ) ;
else if ( * tmp = = ' - ' )
lr - > end = ( unsigned int ) strtoul ( tmp + 1 , & tmp , 0 ) ;
else
lr - > end = 0 ;
pr_debug ( " Line range is %u to %u \n " , lr - > start , lr - > end ) ;
if ( lr - > end & & lr - > start > lr - > end )
semantic_error ( " Start line must be smaller "
" than end line. " ) ;
if ( * tmp ! = ' \0 ' )
semantic_error ( " Tailing with invalid character '%d'. " ,
* tmp ) ;
tmp = strndup ( arg , ( ptr - arg ) ) ;
} else
tmp = strdup ( arg ) ;
if ( strchr ( tmp , ' . ' ) )
lr - > file = tmp ;
else
lr - > function = tmp ;
}
2009-12-16 17:24:15 -05:00
/* Check the name is good for event/group */
static bool check_event_name ( const char * name )
{
if ( ! isalpha ( * name ) & & * name ! = ' _ ' )
return false ;
while ( * + + name ! = ' \0 ' ) {
if ( ! isalpha ( * name ) & & ! isdigit ( * name ) & & * name ! = ' _ ' )
return false ;
}
return true ;
}
2009-11-30 19:19:58 -05:00
/* Parse probepoint definition. */
static void parse_perf_probe_probepoint ( char * arg , struct probe_point * pp )
{
char * ptr , * tmp ;
char c , nc = 0 ;
/*
* < Syntax >
2010-02-25 08:36:12 -05:00
* perf probe [ EVENT = ] SRC [ : LN | ; PTN ]
* perf probe [ EVENT = ] FUNC [ @ SRC ] [ + OFFS | % return | : LN | ; PAT ]
2009-12-15 10:32:18 -05:00
*
* TODO : Group name support
2009-11-30 19:19:58 -05:00
*/
2010-02-25 08:36:12 -05:00
ptr = strpbrk ( arg , " ;=@+% " ) ;
if ( ptr & & * ptr = = ' = ' ) { /* Event name */
2009-12-15 10:32:18 -05:00
* ptr = ' \0 ' ;
tmp = ptr + 1 ;
ptr = strchr ( arg , ' : ' ) ;
if ( ptr ) /* Group name is not supported yet. */
semantic_error ( " Group name is not supported yet. " ) ;
2009-12-16 17:24:15 -05:00
if ( ! check_event_name ( arg ) )
semantic_error ( " %s is bad for event name -it must "
" follow C symbol-naming rule. " , arg ) ;
2009-12-15 10:32:18 -05:00
pp - > event = strdup ( arg ) ;
arg = tmp ;
}
2010-02-25 08:36:12 -05:00
ptr = strpbrk ( arg , " ;:+@% " ) ;
2009-11-30 19:19:58 -05:00
if ( ptr ) {
nc = * ptr ;
* ptr + + = ' \0 ' ;
}
/* Check arg is function or file and copy it */
if ( strchr ( arg , ' . ' ) ) /* File */
pp - > file = strdup ( arg ) ;
else /* Function */
pp - > function = strdup ( arg ) ;
DIE_IF ( pp - > file = = NULL & & pp - > function = = NULL ) ;
/* Parse other options */
while ( ptr ) {
arg = ptr ;
c = nc ;
2010-02-25 08:36:12 -05:00
if ( c = = ' ; ' ) { /* Lazy pattern must be the last part */
pp - > lazy_line = strdup ( arg ) ;
break ;
}
ptr = strpbrk ( arg , " ;:+@% " ) ;
2009-11-30 19:19:58 -05:00
if ( ptr ) {
nc = * ptr ;
* ptr + + = ' \0 ' ;
}
switch ( c ) {
case ' : ' : /* Line number */
pp - > line = strtoul ( arg , & tmp , 0 ) ;
if ( * tmp ! = ' \0 ' )
2010-02-25 08:36:12 -05:00
semantic_error ( " There is non-digit char "
" in line number. " ) ;
2009-11-30 19:19:58 -05:00
break ;
case ' + ' : /* Byte offset from a symbol */
pp - > offset = strtoul ( arg , & tmp , 0 ) ;
if ( * tmp ! = ' \0 ' )
2010-02-25 08:36:12 -05:00
semantic_error ( " There is non-digit character "
2009-11-30 19:19:58 -05:00
" in offset. " ) ;
break ;
case ' @ ' : /* File name */
if ( pp - > file )
semantic_error ( " SRC@SRC is not allowed. " ) ;
pp - > file = strdup ( arg ) ;
DIE_IF ( pp - > file = = NULL ) ;
break ;
case ' % ' : /* Probe places */
if ( strcmp ( arg , " return " ) = = 0 ) {
pp - > retprobe = 1 ;
} else /* Others not supported yet */
semantic_error ( " %%%s is not supported. " , arg ) ;
break ;
default :
DIE_IF ( " Program has a bug. " ) ;
break ;
}
}
/* Exclusion check */
2010-02-25 08:36:12 -05:00
if ( pp - > lazy_line & & pp - > line )
semantic_error ( " Lazy pattern can't be used with line number. " ) ;
if ( pp - > lazy_line & & pp - > offset )
semantic_error ( " Lazy pattern can't be used with offset. " ) ;
2009-11-30 19:19:58 -05:00
if ( pp - > line & & pp - > offset )
semantic_error ( " Offset can't be used with line number. " ) ;
2010-02-25 08:36:12 -05:00
if ( ! pp - > line & & ! pp - > lazy_line & & pp - > file & & ! pp - > function )
semantic_error ( " File always requires line number or "
" lazy pattern. " ) ;
2009-11-30 19:19:58 -05:00
if ( pp - > offset & & ! pp - > function )
semantic_error ( " Offset requires an entry function. " ) ;
if ( pp - > retprobe & & ! pp - > function )
semantic_error ( " Return probe requires an entry function. " ) ;
2010-02-25 08:36:12 -05:00
if ( ( pp - > offset | | pp - > line | | pp - > lazy_line ) & & pp - > retprobe )
semantic_error ( " Offset/Line/Lazy pattern can't be used with "
" return probe. " ) ;
2009-11-30 19:19:58 -05:00
2010-02-25 08:36:12 -05:00
pr_debug ( " symbol:%s file:%s line:%d offset:%d return:%d lazy:%s \n " ,
pp - > function , pp - > file , pp - > line , pp - > offset , pp - > retprobe ,
pp - > lazy_line ) ;
2009-11-30 19:19:58 -05:00
}
/* Parse perf-probe event definition */
2009-12-15 10:31:14 -05:00
void parse_perf_probe_event ( const char * str , struct probe_point * pp ,
bool * need_dwarf )
2009-11-30 19:19:58 -05:00
{
2009-11-30 19:20:05 -05:00
char * * argv ;
2009-12-15 10:31:14 -05:00
int argc , i ;
* need_dwarf = false ;
2009-11-30 19:19:58 -05:00
2009-11-30 19:20:05 -05:00
argv = argv_split ( str , & argc ) ;
if ( ! argv )
die ( " argv_split failed. " ) ;
if ( argc > MAX_PROBE_ARGS + 1 )
semantic_error ( " Too many arguments " ) ;
2009-11-30 19:19:58 -05:00
/* Parse probe point */
parse_perf_probe_probepoint ( argv [ 0 ] , pp ) ;
if ( pp - > file | | pp - > line )
2009-12-15 10:31:14 -05:00
* need_dwarf = true ;
2009-11-30 19:19:58 -05:00
2009-11-30 19:20:05 -05:00
/* Copy arguments and ensure return probe has no C argument */
2009-11-30 19:19:58 -05:00
pp - > nr_args = argc - 1 ;
2009-11-30 19:20:05 -05:00
pp - > args = zalloc ( sizeof ( char * ) * pp - > nr_args ) ;
for ( i = 0 ; i < pp - > nr_args ; i + + ) {
pp - > args [ i ] = strdup ( argv [ i + 1 ] ) ;
if ( ! pp - > args [ i ] )
die ( " Failed to copy argument. " ) ;
2009-11-30 19:19:58 -05:00
if ( is_c_varname ( pp - > args [ i ] ) ) {
if ( pp - > retprobe )
semantic_error ( " You can't specify local "
" variable for kretprobe " ) ;
2009-12-15 10:31:14 -05:00
* need_dwarf = true ;
2009-11-30 19:19:58 -05:00
}
2009-11-30 19:20:05 -05:00
}
2009-11-30 19:19:58 -05:00
2009-11-30 19:20:05 -05:00
argv_free ( argv ) ;
2009-11-30 19:19:58 -05:00
}
2009-11-30 19:20:17 -05:00
/* Parse kprobe_events event into struct probe_point */
2009-12-15 10:32:18 -05:00
void parse_trace_kprobe_event ( const char * str , struct probe_point * pp )
2009-11-30 19:20:17 -05:00
{
char pr ;
char * p ;
int ret , i , argc ;
char * * argv ;
pr_debug ( " Parsing kprobe_events: %s \n " , str ) ;
argv = argv_split ( str , & argc ) ;
if ( ! argv )
die ( " argv_split failed. " ) ;
if ( argc < 2 )
semantic_error ( " Too less arguments. " ) ;
/* Scan event and group name. */
2009-12-02 16:42:54 +08:00
ret = sscanf ( argv [ 0 ] , " %c:%a[^/ \t ]/%a[^ \t ] " ,
2009-12-15 10:32:18 -05:00
& pr , ( float * ) ( void * ) & pp - > group ,
( float * ) ( void * ) & pp - > event ) ;
2009-11-30 19:20:17 -05:00
if ( ret ! = 3 )
semantic_error ( " Failed to parse event name: %s " , argv [ 0 ] ) ;
2009-12-15 10:32:18 -05:00
pr_debug ( " Group:%s Event:%s probe:%c \n " , pp - > group , pp - > event , pr ) ;
2009-11-30 19:20:17 -05:00
pp - > retprobe = ( pr = = ' r ' ) ;
/* Scan function name and offset */
2009-12-15 10:32:18 -05:00
ret = sscanf ( argv [ 1 ] , " %a[^+]+%d " , ( float * ) ( void * ) & pp - > function ,
& pp - > offset ) ;
2009-11-30 19:20:17 -05:00
if ( ret = = 1 )
pp - > offset = 0 ;
/* kprobe_events doesn't have this information */
pp - > line = 0 ;
pp - > file = NULL ;
pp - > nr_args = argc - 2 ;
pp - > args = zalloc ( sizeof ( char * ) * pp - > nr_args ) ;
for ( i = 0 ; i < pp - > nr_args ; i + + ) {
p = strchr ( argv [ i + 2 ] , ' = ' ) ;
if ( p ) /* We don't need which register is assigned. */
* p = ' \0 ' ;
pp - > args [ i ] = strdup ( argv [ i + 2 ] ) ;
if ( ! pp - > args [ i ] )
die ( " Failed to copy argument. " ) ;
}
argv_free ( argv ) ;
}
2009-12-15 10:32:47 -05:00
/* Synthesize only probe point (not argument) */
int synthesize_perf_probe_point ( struct probe_point * pp )
2009-11-30 19:20:17 -05:00
{
char * buf ;
char offs [ 64 ] = " " , line [ 64 ] = " " ;
2009-12-15 10:32:47 -05:00
int ret ;
2009-11-30 19:20:17 -05:00
pp - > probes [ 0 ] = buf = zalloc ( MAX_CMDLEN ) ;
2010-02-18 13:16:52 -05:00
pp - > found = 1 ;
2009-11-30 19:20:17 -05:00
if ( ! buf )
die ( " Failed to allocate memory by zalloc. " ) ;
if ( pp - > offset ) {
ret = e_snprintf ( offs , 64 , " +%d " , pp - > offset ) ;
if ( ret < = 0 )
goto error ;
}
if ( pp - > line ) {
ret = e_snprintf ( line , 64 , " :%d " , pp - > line ) ;
if ( ret < = 0 )
goto error ;
}
if ( pp - > function )
ret = e_snprintf ( buf , MAX_CMDLEN , " %s%s%s%s " , pp - > function ,
offs , pp - > retprobe ? " %return " : " " , line ) ;
else
2009-12-07 12:00:53 -05:00
ret = e_snprintf ( buf , MAX_CMDLEN , " %s%s " , pp - > file , line ) ;
2009-12-15 10:32:47 -05:00
if ( ret < = 0 ) {
error :
free ( pp - > probes [ 0 ] ) ;
pp - > probes [ 0 ] = NULL ;
2010-02-18 13:16:52 -05:00
pp - > found = 0 ;
2009-12-15 10:32:47 -05:00
}
return ret ;
}
int synthesize_perf_probe_event ( struct probe_point * pp )
{
char * buf ;
int i , len , ret ;
len = synthesize_perf_probe_point ( pp ) ;
if ( len < 0 )
return 0 ;
2009-11-30 19:20:17 -05:00
2009-12-15 10:32:47 -05:00
buf = pp - > probes [ 0 ] ;
2009-11-30 19:20:17 -05:00
for ( i = 0 ; i < pp - > nr_args ; i + + ) {
ret = e_snprintf ( & buf [ len ] , MAX_CMDLEN - len , " %s " ,
pp - > args [ i ] ) ;
if ( ret < = 0 )
goto error ;
len + = ret ;
}
pp - > found = 1 ;
return pp - > found ;
error :
free ( pp - > probes [ 0 ] ) ;
2009-12-15 10:32:47 -05:00
pp - > probes [ 0 ] = NULL ;
2009-11-30 19:20:17 -05:00
return ret ;
}
2009-11-30 19:19:58 -05:00
int synthesize_trace_kprobe_event ( struct probe_point * pp )
{
char * buf ;
int i , len , ret ;
pp - > probes [ 0 ] = buf = zalloc ( MAX_CMDLEN ) ;
if ( ! buf )
die ( " Failed to allocate memory by zalloc. " ) ;
2009-11-30 19:20:17 -05:00
ret = e_snprintf ( buf , MAX_CMDLEN , " %s+%d " , pp - > function , pp - > offset ) ;
if ( ret < = 0 )
2009-11-30 19:19:58 -05:00
goto error ;
len = ret ;
for ( i = 0 ; i < pp - > nr_args ; i + + ) {
2009-11-30 19:20:17 -05:00
ret = e_snprintf ( & buf [ len ] , MAX_CMDLEN - len , " %s " ,
pp - > args [ i ] ) ;
if ( ret < = 0 )
2009-11-30 19:19:58 -05:00
goto error ;
len + = ret ;
}
pp - > found = 1 ;
return pp - > found ;
error :
free ( pp - > probes [ 0 ] ) ;
2009-12-15 10:32:47 -05:00
pp - > probes [ 0 ] = NULL ;
2009-11-30 19:19:58 -05:00
return ret ;
}
2009-11-30 19:20:17 -05:00
static int open_kprobe_events ( int flags , int mode )
{
char buf [ PATH_MAX ] ;
int ret ;
ret = e_snprintf ( buf , PATH_MAX , " %s/../kprobe_events " , debugfs_path ) ;
if ( ret < 0 )
die ( " Failed to make kprobe_events path. " ) ;
ret = open ( buf , flags , mode ) ;
if ( ret < 0 ) {
if ( errno = = ENOENT )
die ( " kprobe_events file does not exist - "
2009-12-29 16:37:09 +08:00
" please rebuild with CONFIG_KPROBE_EVENT. " ) ;
2009-11-30 19:20:17 -05:00
else
die ( " Could not open kprobe_events file: %s " ,
strerror ( errno ) ) ;
}
return ret ;
}
/* Get raw string list of current kprobe_events */
static struct strlist * get_trace_kprobe_event_rawlist ( int fd )
{
int ret , idx ;
FILE * fp ;
char buf [ MAX_CMDLEN ] ;
char * p ;
struct strlist * sl ;
sl = strlist__new ( true , NULL ) ;
fp = fdopen ( dup ( fd ) , " r " ) ;
while ( ! feof ( fp ) ) {
p = fgets ( buf , MAX_CMDLEN , fp ) ;
if ( ! p )
break ;
idx = strlen ( p ) - 1 ;
if ( p [ idx ] = = ' \n ' )
p [ idx ] = ' \0 ' ;
ret = strlist__add ( sl , buf ) ;
if ( ret < 0 )
die ( " strlist__add failed: %s " , strerror ( - ret ) ) ;
}
fclose ( fp ) ;
return sl ;
}
/* Free and zero clear probe_point */
static void clear_probe_point ( struct probe_point * pp )
{
int i ;
2009-12-15 10:32:18 -05:00
if ( pp - > event )
free ( pp - > event ) ;
if ( pp - > group )
free ( pp - > group ) ;
2009-11-30 19:20:17 -05:00
if ( pp - > function )
free ( pp - > function ) ;
if ( pp - > file )
free ( pp - > file ) ;
2010-02-25 08:36:12 -05:00
if ( pp - > lazy_line )
free ( pp - > lazy_line ) ;
2009-11-30 19:20:17 -05:00
for ( i = 0 ; i < pp - > nr_args ; i + + )
free ( pp - > args [ i ] ) ;
if ( pp - > args )
free ( pp - > args ) ;
for ( i = 0 ; i < pp - > found ; i + + )
free ( pp - > probes [ i ] ) ;
2009-12-09 20:26:18 +01:00
memset ( pp , 0 , sizeof ( * pp ) ) ;
2009-11-30 19:20:17 -05:00
}
2009-12-08 17:02:40 -05:00
/* Show an event */
2009-12-15 10:32:18 -05:00
static void show_perf_probe_event ( const char * event , const char * place ,
struct probe_point * pp )
2009-12-08 17:02:40 -05:00
{
2009-12-15 10:31:21 -05:00
int i , ret ;
2009-12-08 17:02:40 -05:00
char buf [ 128 ] ;
2009-12-15 10:32:18 -05:00
ret = e_snprintf ( buf , 128 , " %s:%s " , pp - > group , event ) ;
2009-12-15 10:31:21 -05:00
if ( ret < 0 )
die ( " Failed to copy event: %s " , strerror ( - ret ) ) ;
2009-12-08 17:02:40 -05:00
printf ( " %-40s (on %s " , buf , place ) ;
if ( pp - > nr_args > 0 ) {
printf ( " with " ) ;
for ( i = 0 ; i < pp - > nr_args ; i + + )
printf ( " %s " , pp - > args [ i ] ) ;
}
printf ( " ) \n " ) ;
}
2009-11-30 19:20:17 -05:00
/* List up current perf-probe events */
void show_perf_probe_events ( void )
{
2009-12-15 10:32:47 -05:00
int fd ;
2009-11-30 19:20:17 -05:00
struct probe_point pp ;
struct strlist * rawlist ;
struct str_node * ent ;
2010-01-05 17:47:10 -05:00
setup_pager ( ) ;
2010-02-18 13:16:52 -05:00
memset ( & pp , 0 , sizeof ( pp ) ) ;
2010-01-05 17:47:10 -05:00
2009-11-30 19:20:17 -05:00
fd = open_kprobe_events ( O_RDONLY , 0 ) ;
rawlist = get_trace_kprobe_event_rawlist ( fd ) ;
close ( fd ) ;
2009-12-15 10:32:03 -05:00
strlist__for_each ( ent , rawlist ) {
2009-12-15 10:32:18 -05:00
parse_trace_kprobe_event ( ent - > s , & pp ) ;
2009-12-08 17:02:40 -05:00
/* Synthesize only event probe point */
2009-12-15 10:32:47 -05:00
synthesize_perf_probe_point ( & pp ) ;
2009-12-08 17:02:40 -05:00
/* Show an event */
2009-12-15 10:32:18 -05:00
show_perf_probe_event ( pp . event , pp . probes [ 0 ] , & pp ) ;
2009-11-30 19:20:17 -05:00
clear_probe_point ( & pp ) ;
}
strlist__delete ( rawlist ) ;
}
2009-11-30 19:20:25 -05:00
/* Get current perf-probe event names */
2009-12-08 17:03:23 -05:00
static struct strlist * get_perf_event_names ( int fd , bool include_group )
2009-11-30 19:20:25 -05:00
{
2009-12-08 17:03:23 -05:00
char buf [ 128 ] ;
2009-11-30 19:20:25 -05:00
struct strlist * sl , * rawlist ;
struct str_node * ent ;
2009-12-15 10:32:18 -05:00
struct probe_point pp ;
2009-11-30 19:20:25 -05:00
2009-12-15 10:32:18 -05:00
memset ( & pp , 0 , sizeof ( pp ) ) ;
2009-11-30 19:20:25 -05:00
rawlist = get_trace_kprobe_event_rawlist ( fd ) ;
2009-12-07 12:00:46 -05:00
sl = strlist__new ( true , NULL ) ;
2009-12-15 10:32:03 -05:00
strlist__for_each ( ent , rawlist ) {
2009-12-15 10:32:18 -05:00
parse_trace_kprobe_event ( ent - > s , & pp ) ;
2009-12-08 17:03:23 -05:00
if ( include_group ) {
2009-12-15 10:32:18 -05:00
if ( e_snprintf ( buf , 128 , " %s:%s " , pp . group ,
pp . event ) < 0 )
2009-12-08 17:03:23 -05:00
die ( " Failed to copy group:event name. " ) ;
strlist__add ( sl , buf ) ;
} else
2009-12-15 10:32:18 -05:00
strlist__add ( sl , pp . event ) ;
clear_probe_point ( & pp ) ;
2009-11-30 19:20:25 -05:00
}
strlist__delete ( rawlist ) ;
return sl ;
}
2009-12-08 17:02:47 -05:00
static void write_trace_kprobe_event ( int fd , const char * buf )
2009-11-30 19:19:58 -05:00
{
int ret ;
2009-12-08 17:03:23 -05:00
pr_debug ( " Writing event: %s \n " , buf ) ;
2009-11-30 19:19:58 -05:00
ret = write ( fd , buf , strlen ( buf ) ) ;
if ( ret < = 0 )
2009-12-08 17:03:23 -05:00
die ( " Failed to write event: %s " , strerror ( errno ) ) ;
2009-11-30 19:19:58 -05:00
}
2009-11-30 19:20:25 -05:00
static void get_new_event_name ( char * buf , size_t len , const char * base ,
2009-12-15 10:32:25 -05:00
struct strlist * namelist , bool allow_suffix )
2009-11-30 19:20:25 -05:00
{
int i , ret ;
2009-12-08 17:03:02 -05:00
/* Try no suffix */
ret = e_snprintf ( buf , len , " %s " , base ) ;
if ( ret < 0 )
die ( " snprintf() failed: %s " , strerror ( - ret ) ) ;
if ( ! strlist__has_entry ( namelist , buf ) )
return ;
2009-12-15 10:32:25 -05:00
if ( ! allow_suffix ) {
pr_warning ( " Error: event \" %s \" already exists. "
" (Use -f to force duplicates.) \n " , base ) ;
die ( " Can't add new event. " ) ;
}
2009-12-08 17:03:02 -05:00
/* Try to add suffix */
for ( i = 1 ; i < MAX_EVENT_INDEX ; i + + ) {
2009-11-30 19:20:25 -05:00
ret = e_snprintf ( buf , len , " %s_%d " , base , i ) ;
if ( ret < 0 )
die ( " snprintf() failed: %s " , strerror ( - ret ) ) ;
if ( ! strlist__has_entry ( namelist , buf ) )
break ;
}
if ( i = = MAX_EVENT_INDEX )
die ( " Too many events are on the same function. " ) ;
}
2009-12-15 10:32:25 -05:00
void add_trace_kprobe_events ( struct probe_point * probes , int nr_probes ,
bool force_add )
2009-11-30 19:19:58 -05:00
{
int i , j , fd ;
struct probe_point * pp ;
char buf [ MAX_CMDLEN ] ;
2009-11-30 19:20:25 -05:00
char event [ 64 ] ;
struct strlist * namelist ;
2009-12-15 10:32:25 -05:00
bool allow_suffix ;
2009-11-30 19:19:58 -05:00
2009-11-30 19:20:25 -05:00
fd = open_kprobe_events ( O_RDWR , O_APPEND ) ;
/* Get current event names */
2009-12-08 17:03:23 -05:00
namelist = get_perf_event_names ( fd , false ) ;
2009-11-30 19:19:58 -05:00
for ( j = 0 ; j < nr_probes ; j + + ) {
pp = probes + j ;
2009-12-15 10:32:18 -05:00
if ( ! pp - > event )
pp - > event = strdup ( pp - > function ) ;
if ( ! pp - > group )
pp - > group = strdup ( PERFPROBE_GROUP ) ;
DIE_IF ( ! pp - > event | | ! pp - > group ) ;
2009-12-15 10:32:25 -05:00
/* If force_add is true, suffix search is allowed */
allow_suffix = force_add ;
2009-11-30 19:20:25 -05:00
for ( i = 0 ; i < pp - > found ; i + + ) {
/* Get an unused new event name */
2009-12-15 10:32:25 -05:00
get_new_event_name ( event , 64 , pp - > event , namelist ,
allow_suffix ) ;
2009-11-30 19:20:25 -05:00
snprintf ( buf , MAX_CMDLEN , " %c:%s/%s %s \n " ,
pp - > retprobe ? ' r ' : ' p ' ,
2009-12-15 10:32:18 -05:00
pp - > group , event ,
2009-11-30 19:20:25 -05:00
pp - > probes [ i ] ) ;
2009-11-30 19:19:58 -05:00
write_trace_kprobe_event ( fd , buf ) ;
2009-12-08 17:02:47 -05:00
printf ( " Added new event: \n " ) ;
/* Get the first parameter (probe-point) */
sscanf ( pp - > probes [ i ] , " %s " , buf ) ;
2009-12-15 10:32:18 -05:00
show_perf_probe_event ( event , buf , pp ) ;
2009-11-30 19:20:25 -05:00
/* Add added event name to namelist */
strlist__add ( namelist , event ) ;
2009-12-15 10:32:25 -05:00
/*
* Probes after the first probe which comes from same
* user input are always allowed to add suffix , because
* there might be several addresses corresponding to
* one code line .
*/
allow_suffix = true ;
2009-11-30 19:20:25 -05:00
}
2009-11-30 19:19:58 -05:00
}
2009-12-08 17:02:47 -05:00
/* Show how to use the event. */
printf ( " \n You can now use it on all perf tools, such as: \n \n " ) ;
printf ( " \t perf record -e %s:%s -a sleep 1 \n \n " , PERFPROBE_GROUP , event ) ;
2009-12-07 12:00:46 -05:00
strlist__delete ( namelist ) ;
2009-11-30 19:19:58 -05:00
close ( fd ) ;
}
2009-12-08 17:03:23 -05:00
2009-12-15 10:32:10 -05:00
static void __del_trace_kprobe_event ( int fd , struct str_node * ent )
{
char * p ;
char buf [ 128 ] ;
/* Convert from perf-probe event to trace-kprobe event */
if ( e_snprintf ( buf , 128 , " -:%s " , ent - > s ) < 0 )
die ( " Failed to copy event. " ) ;
p = strchr ( buf + 2 , ' : ' ) ;
if ( ! p )
die ( " Internal error: %s should have ':' but not. " , ent - > s ) ;
* p = ' / ' ;
write_trace_kprobe_event ( fd , buf ) ;
printf ( " Remove event: %s \n " , ent - > s ) ;
}
2009-12-08 17:03:23 -05:00
static void del_trace_kprobe_event ( int fd , const char * group ,
const char * event , struct strlist * namelist )
{
char buf [ 128 ] ;
2009-12-15 10:32:10 -05:00
struct str_node * ent , * n ;
int found = 0 ;
2009-12-08 17:03:23 -05:00
if ( e_snprintf ( buf , 128 , " %s:%s " , group , event ) < 0 )
die ( " Failed to copy event. " ) ;
2009-12-15 10:32:10 -05:00
if ( strpbrk ( buf , " *? " ) ) { /* Glob-exp */
strlist__for_each_safe ( ent , n , namelist )
if ( strglobmatch ( ent - > s , buf ) ) {
found + + ;
__del_trace_kprobe_event ( fd , ent ) ;
strlist__remove ( namelist , ent ) ;
}
} else {
ent = strlist__find ( namelist , buf ) ;
if ( ent ) {
found + + ;
__del_trace_kprobe_event ( fd , ent ) ;
strlist__remove ( namelist , ent ) ;
}
}
if ( found = = 0 )
pr_info ( " Info: event \" %s \" does not exist, could not remove it. \n " , buf ) ;
2009-12-08 17:03:23 -05:00
}
void del_trace_kprobe_events ( struct strlist * dellist )
{
int fd ;
const char * group , * event ;
char * p , * str ;
struct str_node * ent ;
struct strlist * namelist ;
fd = open_kprobe_events ( O_RDWR , O_APPEND ) ;
/* Get current event names */
namelist = get_perf_event_names ( fd , true ) ;
2009-12-15 10:32:03 -05:00
strlist__for_each ( ent , dellist ) {
2009-12-08 17:03:23 -05:00
str = strdup ( ent - > s ) ;
if ( ! str )
die ( " Failed to copy event. " ) ;
2009-12-15 10:32:10 -05:00
pr_debug ( " Parsing: %s \n " , str ) ;
2009-12-08 17:03:23 -05:00
p = strchr ( str , ' : ' ) ;
if ( p ) {
group = str ;
* p = ' \0 ' ;
event = p + 1 ;
} else {
2009-12-15 10:32:10 -05:00
group = " * " ;
2009-12-08 17:03:23 -05:00
event = str ;
}
2009-12-15 10:32:10 -05:00
pr_debug ( " Group: %s, Event: %s \n " , group , event ) ;
2009-12-08 17:03:23 -05:00
del_trace_kprobe_event ( fd , group , event , namelist ) ;
free ( str ) ;
}
strlist__delete ( namelist ) ;
close ( fd ) ;
}
2010-01-06 09:45:34 -05:00
# define LINEBUF_SIZE 256
2010-02-25 08:36:04 -05:00
# define NR_ADDITIONAL_LINES 2
2010-01-06 09:45:34 -05:00
static void show_one_line ( FILE * fp , unsigned int l , bool skip , bool show_num )
{
char buf [ LINEBUF_SIZE ] ;
const char * color = PERF_COLOR_BLUE ;
if ( fgets ( buf , LINEBUF_SIZE , fp ) = = NULL )
goto error ;
if ( ! skip ) {
if ( show_num )
fprintf ( stdout , " %7u %s " , l , buf ) ;
else
color_fprintf ( stdout , color , " %s " , buf ) ;
}
while ( strlen ( buf ) = = LINEBUF_SIZE - 1 & &
buf [ LINEBUF_SIZE - 2 ] ! = ' \n ' ) {
if ( fgets ( buf , LINEBUF_SIZE , fp ) = = NULL )
goto error ;
if ( ! skip ) {
if ( show_num )
fprintf ( stdout , " %s " , buf ) ;
else
color_fprintf ( stdout , color , " %s " , buf ) ;
}
}
return ;
error :
if ( feof ( fp ) )
die ( " Source file is shorter than expected. " ) ;
else
die ( " File read error: %s " , strerror ( errno ) ) ;
}
void show_line_range ( struct line_range * lr )
{
unsigned int l = 1 ;
struct line_node * ln ;
FILE * fp ;
setup_pager ( ) ;
if ( lr - > function )
fprintf ( stdout , " <%s:%d> \n " , lr - > function ,
lr - > start - lr - > offset ) ;
else
fprintf ( stdout , " <%s:%d> \n " , lr - > file , lr - > start ) ;
fp = fopen ( lr - > path , " r " ) ;
if ( fp = = NULL )
die ( " Failed to open %s: %s " , lr - > path , strerror ( errno ) ) ;
/* Skip to starting line number */
while ( l < lr - > start )
show_one_line ( fp , l + + , true , false ) ;
list_for_each_entry ( ln , & lr - > line_list , list ) {
while ( ln - > line > l )
show_one_line ( fp , ( l + + ) - lr - > offset , false , false ) ;
show_one_line ( fp , ( l + + ) - lr - > offset , false , true ) ;
}
2010-02-25 08:36:04 -05:00
if ( lr - > end = = INT_MAX )
lr - > end = l + NR_ADDITIONAL_LINES ;
while ( l < lr - > end & & ! feof ( fp ) )
show_one_line ( fp , ( l + + ) - lr - > offset , false , false ) ;
2010-01-06 09:45:34 -05:00
fclose ( fp ) ;
}