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
2010-03-16 18:05:30 -04:00
# include "util.h"
2009-11-30 19:19:58 -05:00
# 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"
2010-03-16 18:05:37 -04:00
# include "symbol.h"
# include "thread.h"
2009-11-30 19:19:58 -05:00
# include "parse-events.h" /* For debugfs_path */
# include "probe-event.h"
2010-03-16 18:06:12 -04:00
# include "probe-finder.h"
2009-11-30 19:19:58 -05:00
# define MAX_CMDLEN 256
# define MAX_PROBE_ARGS 128
# define PERFPROBE_GROUP "probe"
2010-03-16 18:06:05 -04:00
bool probe_event_dry_run ; /* Dry run flag */
2009-11-30 19:19:58 -05:00
# 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-03-16 18:05:37 -04:00
static struct map_groups kmap_groups ;
static struct map * kmaps [ MAP__NR_TYPES ] ;
/* Initialize symbol maps for vmlinux */
static void init_vmlinux ( void )
{
symbol_conf . sort_by_name = true ;
if ( symbol_conf . vmlinux_name = = NULL )
symbol_conf . try_vmlinux_path = true ;
else
pr_debug ( " Use vmlinux: %s \n " , symbol_conf . vmlinux_name ) ;
if ( symbol__init ( ) < 0 )
die ( " Failed to init symbol map. " ) ;
map_groups__init ( & kmap_groups ) ;
if ( map_groups__create_kernel_maps ( & kmap_groups , kmaps ) < 0 )
die ( " Failed to create kernel maps. " ) ;
}
# ifndef NO_DWARF_SUPPORT
static int open_vmlinux ( void )
{
if ( map__load ( kmaps [ MAP__FUNCTION ] , NULL ) < 0 ) {
pr_debug ( " Failed to load kernel map. \n " ) ;
return - EINVAL ;
}
pr_debug ( " Try to open %s \n " , kmaps [ MAP__FUNCTION ] - > dso - > long_name ) ;
return open ( kmaps [ MAP__FUNCTION ] - > dso - > long_name , O_RDONLY ) ;
}
# endif
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 ) ;
2010-03-16 18:05:30 -04:00
tmp = xstrndup ( arg , ( ptr - arg ) ) ;
2010-01-06 09:45:34 -05:00
} else
2010-03-16 18:05:30 -04:00
tmp = xstrdup ( arg ) ;
2010-01-06 09:45:34 -05:00
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. */
2010-03-16 18:06:12 -04:00
static void parse_perf_probe_point ( char * arg , struct perf_probe_event * pev )
2009-11-30 19:19:58 -05:00
{
2010-03-16 18:06:12 -04:00
struct perf_probe_point * pp = & pev - > point ;
2009-11-30 19:19:58 -05:00
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 ) ;
2010-03-16 18:06:12 -04:00
pev - > event = xstrdup ( arg ) ;
pev - > group = NULL ;
2009-12-15 10:32:18 -05:00
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 */
2010-03-16 18:05:30 -04:00
pp - > file = xstrdup ( arg ) ;
2009-11-30 19:19:58 -05:00
else /* Function */
2010-03-16 18:05:30 -04:00
pp - > function = xstrdup ( arg ) ;
2009-11-30 19:19:58 -05:00
/* 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 */
2010-03-16 18:05:30 -04:00
pp - > lazy_line = xstrdup ( arg ) ;
2010-02-25 08:36:12 -05:00
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. " ) ;
2010-03-16 18:05:30 -04:00
pp - > file = xstrdup ( arg ) ;
2009-11-30 19:19:58 -05:00
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-03-16 18:06:12 -04:00
pr_debug ( " symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s \n " ,
2010-02-25 08:36:12 -05:00
pp - > function , pp - > file , pp - > line , pp - > offset , pp - > retprobe ,
pp - > lazy_line ) ;
2009-11-30 19:19:58 -05:00
}
2010-03-16 18:06:26 -04:00
/* Parse perf-probe event argument */
static void parse_perf_probe_arg ( const char * str , struct perf_probe_arg * arg )
{
const char * tmp ;
struct perf_probe_arg_field * * fieldp ;
pr_debug ( " parsing arg: %s into " , str ) ;
tmp = strpbrk ( str , " -. " ) ;
if ( ! is_c_varname ( str ) | | ! tmp ) {
/* A variable, register, symbol or special value */
arg - > name = xstrdup ( str ) ;
pr_debug ( " %s \n " , arg - > name ) ;
return ;
}
/* Structure fields */
arg - > name = xstrndup ( str , tmp - str ) ;
pr_debug ( " %s, " , arg - > name ) ;
fieldp = & arg - > field ;
do {
* fieldp = xzalloc ( sizeof ( struct perf_probe_arg_field ) ) ;
if ( * tmp = = ' . ' ) {
str = tmp + 1 ;
( * fieldp ) - > ref = false ;
} else if ( tmp [ 1 ] = = ' > ' ) {
str = tmp + 2 ;
( * fieldp ) - > ref = true ;
} else
semantic_error ( " Argument parse error: %s " , str ) ;
tmp = strpbrk ( str , " -. " ) ;
if ( tmp ) {
( * fieldp ) - > name = xstrndup ( str , tmp - str ) ;
pr_debug ( " %s(%d), " , ( * fieldp ) - > name , ( * fieldp ) - > ref ) ;
fieldp = & ( * fieldp ) - > next ;
}
} while ( tmp ) ;
( * fieldp ) - > name = xstrdup ( str ) ;
pr_debug ( " %s(%d) \n " , ( * fieldp ) - > name , ( * fieldp ) - > ref ) ;
}
2010-03-16 18:06:12 -04:00
/* Parse perf-probe event command */
void parse_perf_probe_command ( const char * cmd , struct perf_probe_event * pev )
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 ;
2010-03-16 18:06:12 -04:00
argv = argv_split ( cmd , & argc ) ;
2009-11-30 19:20:05 -05:00
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 */
2010-03-16 18:06:12 -04:00
parse_perf_probe_point ( argv [ 0 ] , pev ) ;
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 */
2010-03-16 18:06:12 -04:00
pev - > nargs = argc - 1 ;
pev - > args = xzalloc ( sizeof ( struct perf_probe_arg ) * pev - > nargs ) ;
for ( i = 0 ; i < pev - > nargs ; i + + ) {
2010-03-16 18:06:26 -04:00
parse_perf_probe_arg ( argv [ i + 1 ] , & pev - > args [ i ] ) ;
2010-03-16 18:06:12 -04:00
if ( is_c_varname ( pev - > args [ i ] . name ) & & pev - > point . retprobe )
semantic_error ( " You can't specify local variable for "
" kretprobe " ) ;
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
}
2010-03-16 18:06:12 -04:00
/* Return true if this perf_probe_event requires debuginfo */
bool perf_probe_event_need_dwarf ( struct perf_probe_event * pev )
{
int i ;
if ( pev - > point . file | | pev - > point . line | | pev - > point . lazy_line )
return true ;
for ( i = 0 ; i < pev - > nargs ; i + + )
if ( is_c_varname ( pev - > args [ i ] . name ) )
return true ;
return false ;
}
2009-11-30 19:20:17 -05:00
/* Parse kprobe_events event into struct probe_point */
2010-03-16 18:06:12 -04:00
void parse_kprobe_trace_command ( const char * cmd , struct kprobe_trace_event * tev )
2009-11-30 19:20:17 -05:00
{
2010-03-16 18:06:12 -04:00
struct kprobe_trace_point * tp = & tev - > point ;
2009-11-30 19:20:17 -05:00
char pr ;
char * p ;
int ret , i , argc ;
char * * argv ;
2010-03-16 18:06:12 -04:00
pr_debug ( " Parsing kprobe_events: %s \n " , cmd ) ;
argv = argv_split ( cmd , & argc ) ;
2009-11-30 19:20:17 -05:00
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 ] " ,
2010-03-16 18:06:12 -04:00
& pr , ( float * ) ( void * ) & tev - > group ,
( float * ) ( void * ) & tev - > event ) ;
2009-11-30 19:20:17 -05:00
if ( ret ! = 3 )
semantic_error ( " Failed to parse event name: %s " , argv [ 0 ] ) ;
2010-03-16 18:06:12 -04:00
pr_debug ( " Group:%s Event:%s probe:%c \n " , tev - > group , tev - > event , pr ) ;
2009-11-30 19:20:17 -05:00
2010-03-16 18:06:12 -04:00
tp - > retprobe = ( pr = = ' r ' ) ;
2009-11-30 19:20:17 -05:00
/* Scan function name and offset */
2010-03-16 18:06:12 -04:00
ret = sscanf ( argv [ 1 ] , " %a[^+]+%lu " , ( float * ) ( void * ) & tp - > symbol ,
& tp - > offset ) ;
2009-11-30 19:20:17 -05:00
if ( ret = = 1 )
2010-03-16 18:06:12 -04:00
tp - > offset = 0 ;
2009-11-30 19:20:17 -05:00
2010-03-16 18:06:12 -04:00
tev - > nargs = argc - 2 ;
tev - > args = xzalloc ( sizeof ( struct kprobe_trace_arg ) * tev - > nargs ) ;
for ( i = 0 ; i < tev - > nargs ; i + + ) {
2009-11-30 19:20:17 -05:00
p = strchr ( argv [ i + 2 ] , ' = ' ) ;
if ( p ) /* We don't need which register is assigned. */
2010-03-16 18:06:12 -04:00
* p + + = ' \0 ' ;
else
p = argv [ i + 2 ] ;
tev - > args [ i ] . name = xstrdup ( argv [ i + 2 ] ) ;
/* TODO: parse regs and offset */
tev - > args [ i ] . value = xstrdup ( p ) ;
2009-11-30 19:20:17 -05:00
}
argv_free ( argv ) ;
}
2010-03-16 18:06:26 -04:00
/* Compose only probe arg */
int synthesize_perf_probe_arg ( struct perf_probe_arg * pa , char * buf , size_t len )
{
struct perf_probe_arg_field * field = pa - > field ;
int ret ;
char * tmp = buf ;
ret = e_snprintf ( tmp , len , " %s " , pa - > name ) ;
if ( ret < = 0 )
goto error ;
tmp + = ret ;
len - = ret ;
while ( field ) {
ret = e_snprintf ( tmp , len , " %s%s " , field - > ref ? " -> " : " . " ,
field - > name ) ;
if ( ret < = 0 )
goto error ;
tmp + = ret ;
len - = ret ;
field = field - > next ;
}
return tmp - buf ;
error :
die ( " Failed to synthesize perf probe argument: %s " , strerror ( - ret ) ) ;
}
2010-03-16 18:06:12 -04:00
/* Compose only probe point (not argument) */
static char * synthesize_perf_probe_point ( struct perf_probe_point * pp )
2009-11-30 19:20:17 -05:00
{
2010-03-16 18:06:19 -04:00
char * buf , * tmp ;
char offs [ 32 ] = " " , line [ 32 ] = " " , file [ 32 ] = " " ;
int ret , len ;
2009-11-30 19:20:17 -05:00
2010-03-16 18:06:12 -04:00
buf = xzalloc ( MAX_CMDLEN ) ;
2009-11-30 19:20:17 -05:00
if ( pp - > offset ) {
2010-03-16 18:06:19 -04:00
ret = e_snprintf ( offs , 32 , " +%lu " , pp - > offset ) ;
2009-11-30 19:20:17 -05:00
if ( ret < = 0 )
goto error ;
}
if ( pp - > line ) {
2010-03-16 18:06:19 -04:00
ret = e_snprintf ( line , 32 , " :%d " , pp - > line ) ;
if ( ret < = 0 )
goto error ;
}
if ( pp - > file ) {
len = strlen ( pp - > file ) - 32 ;
if ( len < 0 )
len = 0 ;
tmp = strchr ( pp - > file + len , ' / ' ) ;
if ( ! tmp )
tmp = pp - > file + len - 1 ;
ret = e_snprintf ( file , 32 , " @%s " , tmp + 1 ) ;
2009-11-30 19:20:17 -05:00
if ( ret < = 0 )
goto error ;
}
if ( pp - > function )
2010-03-16 18:06:19 -04:00
ret = e_snprintf ( buf , MAX_CMDLEN , " %s%s%s%s%s " , pp - > function ,
offs , pp - > retprobe ? " %return " : " " , line ,
file ) ;
2009-11-30 19:20:17 -05:00
else
2010-03-16 18:06:19 -04:00
ret = e_snprintf ( buf , MAX_CMDLEN , " %s%s " , file , line ) ;
2010-03-16 18:06:12 -04:00
if ( ret < = 0 )
goto error ;
return buf ;
2009-12-15 10:32:47 -05:00
error :
2010-03-16 18:06:12 -04:00
die ( " Failed to synthesize perf probe point: %s " , strerror ( - ret ) ) ;
2009-12-15 10:32:47 -05:00
}
2010-03-16 18:06:12 -04:00
#if 0
char * synthesize_perf_probe_command ( struct perf_probe_event * pev )
2009-12-15 10:32:47 -05:00
{
char * buf ;
int i , len , ret ;
2010-03-16 18:06:12 -04:00
buf = synthesize_perf_probe_point ( & pev - > point ) ;
if ( ! buf )
return NULL ;
2009-11-30 19:20:17 -05:00
2010-03-16 18:06:12 -04:00
len = strlen ( buf ) ;
for ( i = 0 ; i < pev - > nargs ; i + + ) {
2009-11-30 19:20:17 -05:00
ret = e_snprintf ( & buf [ len ] , MAX_CMDLEN - len , " %s " ,
2010-03-16 18:06:12 -04:00
pev - > args [ i ] . name ) ;
if ( ret < = 0 ) {
free ( buf ) ;
return NULL ;
}
2009-11-30 19:20:17 -05:00
len + = ret ;
}
2010-03-16 18:06:12 -04:00
return buf ;
}
# endif
static int __synthesize_kprobe_trace_arg_ref ( struct kprobe_trace_arg_ref * ref ,
char * * buf , size_t * buflen ,
int depth )
{
int ret ;
if ( ref - > next ) {
depth = __synthesize_kprobe_trace_arg_ref ( ref - > next , buf ,
buflen , depth + 1 ) ;
if ( depth < 0 )
goto out ;
}
ret = e_snprintf ( * buf , * buflen , " %+ld( " , ref - > offset ) ;
if ( ret < 0 )
depth = ret ;
else {
* buf + = ret ;
* buflen - = ret ;
}
out :
return depth ;
2009-11-30 19:20:17 -05:00
}
2010-03-16 18:06:12 -04:00
static int synthesize_kprobe_trace_arg ( struct kprobe_trace_arg * arg ,
char * buf , size_t buflen )
2009-11-30 19:19:58 -05:00
{
2010-03-16 18:06:12 -04:00
int ret , depth = 0 ;
char * tmp = buf ;
/* Argument name or separator */
if ( arg - > name )
ret = e_snprintf ( buf , buflen , " %s= " , arg - > name ) ;
else
ret = e_snprintf ( buf , buflen , " " ) ;
if ( ret < 0 )
return ret ;
buf + = ret ;
buflen - = ret ;
/* Dereferencing arguments */
if ( arg - > ref ) {
depth = __synthesize_kprobe_trace_arg_ref ( arg - > ref , & buf ,
& buflen , 1 ) ;
if ( depth < 0 )
return depth ;
}
/* Print argument value */
ret = e_snprintf ( buf , buflen , " %s " , arg - > value ) ;
if ( ret < 0 )
return ret ;
buf + = ret ;
buflen - = ret ;
/* Closing */
while ( depth - - ) {
ret = e_snprintf ( buf , buflen , " ) " ) ;
if ( ret < 0 )
return ret ;
buf + = ret ;
buflen - = ret ;
}
return buf - tmp ;
}
char * synthesize_kprobe_trace_command ( struct kprobe_trace_event * tev )
{
struct kprobe_trace_point * tp = & tev - > point ;
2009-11-30 19:19:58 -05:00
char * buf ;
int i , len , ret ;
2010-03-16 18:06:12 -04:00
buf = xzalloc ( MAX_CMDLEN ) ;
len = e_snprintf ( buf , MAX_CMDLEN , " %c:%s/%s %s+%lu " ,
tp - > retprobe ? ' r ' : ' p ' ,
tev - > group , tev - > event ,
tp - > symbol , tp - > offset ) ;
if ( len < = 0 )
2009-11-30 19:19:58 -05:00
goto error ;
2010-03-16 18:06:12 -04:00
for ( i = 0 ; i < tev - > nargs ; i + + ) {
ret = synthesize_kprobe_trace_arg ( & tev - > args [ i ] , buf + len ,
MAX_CMDLEN - len ) ;
2009-11-30 19:20:17 -05:00
if ( ret < = 0 )
2009-11-30 19:19:58 -05:00
goto error ;
len + = ret ;
}
2010-03-16 18:06:12 -04:00
return buf ;
2009-11-30 19:19:58 -05:00
error :
2010-03-16 18:06:12 -04:00
free ( buf ) ;
return NULL ;
}
2009-11-30 19:19:58 -05:00
2010-03-16 18:06:12 -04:00
void convert_to_perf_probe_event ( struct kprobe_trace_event * tev ,
struct perf_probe_event * pev )
{
char buf [ 64 ] ;
int i ;
2010-03-16 18:06:19 -04:00
# ifndef NO_DWARF_SUPPORT
struct symbol * sym ;
int fd , ret = 0 ;
sym = map__find_symbol_by_name ( kmaps [ MAP__FUNCTION ] ,
tev - > point . symbol , NULL ) ;
if ( sym ) {
fd = open_vmlinux ( ) ;
ret = find_perf_probe_point ( fd , sym - > start + tev - > point . offset ,
& pev - > point ) ;
close ( fd ) ;
}
if ( ret < = 0 ) {
pev - > point . function = xstrdup ( tev - > point . symbol ) ;
pev - > point . offset = tev - > point . offset ;
}
# else
2010-03-16 18:06:12 -04:00
/* Convert trace_point to probe_point */
pev - > point . function = xstrdup ( tev - > point . symbol ) ;
pev - > point . offset = tev - > point . offset ;
2010-03-16 18:06:19 -04:00
# endif
2010-03-16 18:06:12 -04:00
pev - > point . retprobe = tev - > point . retprobe ;
2010-03-16 18:06:19 -04:00
pev - > event = xstrdup ( tev - > event ) ;
pev - > group = xstrdup ( tev - > group ) ;
2010-03-16 18:06:12 -04:00
/* Convert trace_arg to probe_arg */
pev - > nargs = tev - > nargs ;
pev - > args = xzalloc ( sizeof ( struct perf_probe_arg ) * pev - > nargs ) ;
for ( i = 0 ; i < tev - > nargs ; i + + )
if ( tev - > args [ i ] . name )
pev - > args [ i ] . name = xstrdup ( tev - > args [ i ] . name ) ;
else {
synthesize_kprobe_trace_arg ( & tev - > args [ i ] , buf , 64 ) ;
pev - > args [ i ] . name = xstrdup ( buf ) ;
}
}
void clear_perf_probe_event ( struct perf_probe_event * pev )
{
struct perf_probe_point * pp = & pev - > point ;
2010-03-16 18:06:26 -04:00
struct perf_probe_arg_field * field , * next ;
2010-03-16 18:06:12 -04:00
int i ;
if ( pev - > event )
free ( pev - > event ) ;
if ( pev - > group )
free ( pev - > group ) ;
if ( pp - > file )
free ( pp - > file ) ;
if ( pp - > function )
free ( pp - > function ) ;
if ( pp - > lazy_line )
free ( pp - > lazy_line ) ;
2010-03-16 18:06:26 -04:00
for ( i = 0 ; i < pev - > nargs ; i + + ) {
2010-03-16 18:06:12 -04:00
if ( pev - > args [ i ] . name )
free ( pev - > args [ i ] . name ) ;
2010-03-16 18:06:26 -04:00
field = pev - > args [ i ] . field ;
while ( field ) {
next = field - > next ;
if ( field - > name )
free ( field - > name ) ;
free ( field ) ;
field = next ;
}
}
2010-03-16 18:06:12 -04:00
if ( pev - > args )
free ( pev - > args ) ;
memset ( pev , 0 , sizeof ( * pev ) ) ;
}
void clear_kprobe_trace_event ( struct kprobe_trace_event * tev )
{
struct kprobe_trace_arg_ref * ref , * next ;
int i ;
if ( tev - > event )
free ( tev - > event ) ;
if ( tev - > group )
free ( tev - > group ) ;
if ( tev - > point . symbol )
free ( tev - > point . symbol ) ;
for ( i = 0 ; i < tev - > nargs ; i + + ) {
if ( tev - > args [ i ] . name )
free ( tev - > args [ i ] . name ) ;
if ( tev - > args [ i ] . value )
free ( tev - > args [ i ] . value ) ;
ref = tev - > args [ i ] . ref ;
while ( ref ) {
next = ref - > next ;
free ( ref ) ;
ref = next ;
}
}
if ( tev - > args )
free ( tev - > args ) ;
memset ( tev , 0 , sizeof ( * tev ) ) ;
2009-11-30 19:19:58 -05:00
}
2010-03-16 18:06:05 -04:00
static int open_kprobe_events ( bool readwrite )
2009-11-30 19:20:17 -05:00
{
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. " ) ;
2010-03-16 18:06:05 -04:00
if ( readwrite & & ! probe_event_dry_run )
ret = open ( buf , O_RDWR , O_APPEND ) ;
else
ret = open ( buf , O_RDONLY , 0 ) ;
2009-11-30 19:20:17 -05:00
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 */
2010-03-16 18:06:12 -04:00
static struct strlist * get_kprobe_trace_command_rawlist ( int fd )
2009-11-30 19:20:17 -05:00
{
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 ;
}
2009-12-08 17:02:40 -05:00
/* Show an event */
2010-03-16 18:06:12 -04:00
static void show_perf_probe_event ( struct perf_probe_event * pev )
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 ] ;
2010-03-16 18:06:12 -04:00
char * place ;
2009-12-08 17:02:40 -05:00
2010-03-16 18:06:12 -04:00
/* Synthesize only event probe point */
place = synthesize_perf_probe_point ( & pev - > point ) ;
ret = e_snprintf ( buf , 128 , " %s:%s " , pev - > group , pev - > event ) ;
2009-12-15 10:31:21 -05:00
if ( ret < 0 )
die ( " Failed to copy event: %s " , strerror ( - ret ) ) ;
2010-03-16 18:06:19 -04:00
printf ( " %-20s (on %s " , buf , place ) ;
2009-12-08 17:02:40 -05:00
2010-03-16 18:06:12 -04:00
if ( pev - > nargs > 0 ) {
2009-12-08 17:02:40 -05:00
printf ( " with " ) ;
2010-03-16 18:06:26 -04:00
for ( i = 0 ; i < pev - > nargs ; i + + ) {
synthesize_perf_probe_arg ( & pev - > args [ i ] , buf , 128 ) ;
printf ( " %s " , buf ) ;
}
2009-12-08 17:02:40 -05:00
}
printf ( " ) \n " ) ;
2010-03-16 18:06:12 -04:00
free ( place ) ;
2009-12-08 17:02:40 -05:00
}
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 ;
2010-03-16 18:06:12 -04:00
struct kprobe_trace_event tev ;
struct perf_probe_event pev ;
2009-11-30 19:20:17 -05:00
struct strlist * rawlist ;
struct str_node * ent ;
2010-01-05 17:47:10 -05:00
setup_pager ( ) ;
2010-03-16 18:06:19 -04:00
init_vmlinux ( ) ;
2010-03-16 18:06:12 -04:00
memset ( & tev , 0 , sizeof ( tev ) ) ;
memset ( & pev , 0 , sizeof ( pev ) ) ;
2010-01-05 17:47:10 -05:00
2010-03-16 18:06:05 -04:00
fd = open_kprobe_events ( false ) ;
2010-03-16 18:06:12 -04:00
rawlist = get_kprobe_trace_command_rawlist ( fd ) ;
2009-11-30 19:20:17 -05:00
close ( fd ) ;
2009-12-15 10:32:03 -05:00
strlist__for_each ( ent , rawlist ) {
2010-03-16 18:06:12 -04:00
parse_kprobe_trace_command ( ent - > s , & tev ) ;
convert_to_perf_probe_event ( & tev , & pev ) ;
2009-12-08 17:02:40 -05:00
/* Show an event */
2010-03-16 18:06:12 -04:00
show_perf_probe_event ( & pev ) ;
clear_perf_probe_event ( & pev ) ;
clear_kprobe_trace_event ( & tev ) ;
2009-11-30 19:20:17 -05:00
}
strlist__delete ( rawlist ) ;
}
2009-11-30 19:20:25 -05:00
/* Get current perf-probe event names */
2010-03-16 18:06:12 -04:00
static struct strlist * get_kprobe_trace_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 ;
2010-03-16 18:06:12 -04:00
struct kprobe_trace_event tev ;
2009-11-30 19:20:25 -05:00
2010-03-16 18:06:12 -04:00
memset ( & tev , 0 , sizeof ( tev ) ) ;
2009-11-30 19:20:25 -05:00
2010-03-16 18:06:12 -04:00
rawlist = get_kprobe_trace_command_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 ) {
2010-03-16 18:06:12 -04:00
parse_kprobe_trace_command ( ent - > s , & tev ) ;
2009-12-08 17:03:23 -05:00
if ( include_group ) {
2010-03-16 18:06:12 -04:00
if ( e_snprintf ( buf , 128 , " %s:%s " , tev . group ,
tev . event ) < 0 )
2009-12-08 17:03:23 -05:00
die ( " Failed to copy group:event name. " ) ;
strlist__add ( sl , buf ) ;
} else
2010-03-16 18:06:12 -04:00
strlist__add ( sl , tev . event ) ;
clear_kprobe_trace_event ( & tev ) ;
2009-11-30 19:20:25 -05:00
}
strlist__delete ( rawlist ) ;
return sl ;
}
2010-03-16 18:06:12 -04:00
static void write_kprobe_trace_event ( int fd , struct kprobe_trace_event * tev )
2009-11-30 19:19:58 -05:00
{
int ret ;
2010-03-16 18:06:12 -04:00
char * buf = synthesize_kprobe_trace_command ( tev ) ;
2009-11-30 19:19:58 -05:00
2009-12-08 17:03:23 -05:00
pr_debug ( " Writing event: %s \n " , buf ) ;
2010-03-16 18:06:05 -04:00
if ( ! probe_event_dry_run ) {
ret = write ( fd , buf , strlen ( buf ) ) ;
if ( ret < = 0 )
die ( " Failed to write event: %s " , strerror ( errno ) ) ;
}
2010-03-16 18:06:12 -04:00
free ( buf ) ;
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. " ) ;
}
2010-03-16 18:06:12 -04:00
static void __add_kprobe_trace_events ( struct perf_probe_event * pev ,
struct kprobe_trace_event * tevs ,
int ntevs , bool allow_suffix )
2009-11-30 19:19:58 -05:00
{
2010-03-16 18:06:12 -04:00
int i , fd ;
2010-03-18 16:51:16 +01:00
struct kprobe_trace_event * tev = NULL ;
2010-03-16 18:06:12 -04:00
char buf [ 64 ] ;
const char * event , * group ;
2009-11-30 19:20:25 -05:00
struct strlist * namelist ;
2009-11-30 19:19:58 -05:00
2010-03-16 18:06:05 -04:00
fd = open_kprobe_events ( true ) ;
2009-11-30 19:20:25 -05:00
/* Get current event names */
2010-03-16 18:06:12 -04:00
namelist = get_kprobe_trace_event_names ( fd , false ) ;
printf ( " Add new event%s \n " , ( ntevs > 1 ) ? " s: " : " : " ) ;
for ( i = 0 ; i < ntevs ; i + + ) {
tev = & tevs [ i ] ;
if ( pev - > event )
event = pev - > event ;
else
if ( pev - > point . function )
event = pev - > point . function ;
else
event = tev - > point . symbol ;
if ( pev - > group )
group = pev - > group ;
else
group = PERFPROBE_GROUP ;
/* Get an unused new event name */
get_new_event_name ( buf , 64 , event , namelist , allow_suffix ) ;
event = buf ;
tev - > event = xstrdup ( event ) ;
tev - > group = xstrdup ( group ) ;
write_kprobe_trace_event ( fd , tev ) ;
/* Add added event name to namelist */
strlist__add ( namelist , event ) ;
/* Trick here - save current event/group */
event = pev - > event ;
group = pev - > group ;
pev - > event = tev - > event ;
pev - > group = tev - > group ;
show_perf_probe_event ( pev ) ;
/* Trick here - restore current event/group */
pev - > event = ( char * ) event ;
pev - > group = ( char * ) group ;
/*
* 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: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 " ) ;
2010-03-16 18:06:12 -04:00
printf ( " \t perf record -e %s:%s -a sleep 1 \n \n " , tev - > group , tev - > event ) ;
2009-12-08 17:02:47 -05:00
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
2010-03-16 18:06:12 -04:00
static int convert_to_kprobe_trace_events ( struct perf_probe_event * pev ,
struct kprobe_trace_event * * tevs )
2010-03-16 18:05:37 -04:00
{
struct symbol * sym ;
2010-03-16 18:06:12 -04:00
bool need_dwarf ;
2010-03-16 18:05:37 -04:00
# ifndef NO_DWARF_SUPPORT
int fd ;
# endif
2010-03-16 18:06:12 -04:00
int ntevs = 0 , i ;
struct kprobe_trace_event * tev ;
need_dwarf = perf_probe_event_need_dwarf ( pev ) ;
2010-03-16 18:05:37 -04:00
if ( need_dwarf )
# ifdef NO_DWARF_SUPPORT
die ( " Debuginfo-analysis is not supported " ) ;
# else /* !NO_DWARF_SUPPORT */
pr_debug ( " Some probes require debuginfo. \n " ) ;
fd = open_vmlinux ( ) ;
if ( fd < 0 ) {
if ( need_dwarf )
die ( " Could not open debuginfo file. " ) ;
pr_debug ( " Could not open vmlinux/module file. "
" Try to use symbols. \n " ) ;
goto end_dwarf ;
}
/* Searching probe points */
2010-03-16 18:06:12 -04:00
ntevs = find_kprobe_trace_events ( fd , pev , tevs ) ;
if ( ntevs > 0 ) /* Found */
goto found ;
if ( ntevs = = 0 ) /* No error but failed to find probe point. */
die ( " Probe point '%s' not found. - probe not added. " ,
synthesize_perf_probe_point ( & pev - > point ) ) ;
/* Error path */
if ( need_dwarf ) {
if ( ntevs = = - ENOENT )
pr_warning ( " No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y. \n " ) ;
die ( " Could not analyze debuginfo. " ) ;
2010-03-16 18:05:37 -04:00
}
2010-03-16 18:06:12 -04:00
pr_debug ( " An error occurred in debuginfo analysis. "
" Try to use symbols. \n " ) ;
2010-03-16 18:05:37 -04:00
end_dwarf :
# endif /* !NO_DWARF_SUPPORT */
2010-03-16 18:06:12 -04:00
/* Allocate trace event buffer */
ntevs = 1 ;
tev = * tevs = xzalloc ( sizeof ( struct kprobe_trace_event ) ) ;
/* Copy parameters */
tev - > point . symbol = xstrdup ( pev - > point . function ) ;
tev - > point . offset = pev - > point . offset ;
tev - > nargs = pev - > nargs ;
if ( tev - > nargs ) {
tev - > args = xzalloc ( sizeof ( struct kprobe_trace_arg )
* tev - > nargs ) ;
for ( i = 0 ; i < tev - > nargs ; i + + )
tev - > args [ i ] . value = xstrdup ( pev - > args [ i ] . name ) ;
}
/* Currently just checking function name from symbol map */
sym = map__find_symbol_by_name ( kmaps [ MAP__FUNCTION ] ,
tev - > point . symbol , NULL ) ;
if ( ! sym )
die ( " Kernel symbol \' %s \' not found - probe not added. " ,
tev - > point . symbol ) ;
2010-03-17 12:13:28 +01:00
# ifndef NO_DWARF_SUPPORT
2010-03-16 18:06:12 -04:00
found :
close ( fd ) ;
2010-03-17 12:13:28 +01:00
# endif
2010-03-16 18:06:12 -04:00
return ntevs ;
}
struct __event_package {
struct perf_probe_event * pev ;
struct kprobe_trace_event * tevs ;
int ntevs ;
} ;
void add_perf_probe_events ( struct perf_probe_event * pevs , int npevs ,
bool force_add )
{
int i ;
struct __event_package * pkgs ;
pkgs = xzalloc ( sizeof ( struct __event_package ) * npevs ) ;
/* Init vmlinux path */
init_vmlinux ( ) ;
/* Loop 1: convert all events */
for ( i = 0 ; i < npevs ; i + + ) {
pkgs [ i ] . pev = & pevs [ i ] ;
/* Convert with or without debuginfo */
pkgs [ i ] . ntevs = convert_to_kprobe_trace_events ( pkgs [ i ] . pev ,
& pkgs [ i ] . tevs ) ;
2010-03-16 18:05:37 -04:00
}
2010-03-16 18:06:12 -04:00
/* Loop 2: add all events */
for ( i = 0 ; i < npevs ; i + + )
__add_kprobe_trace_events ( pkgs [ i ] . pev , pkgs [ i ] . tevs ,
pkgs [ i ] . ntevs , force_add ) ;
/* TODO: cleanup all trace events? */
2010-03-16 18:05:37 -04: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 ] ;
2010-03-16 18:06:12 -04:00
int ret ;
2009-12-15 10:32:10 -05:00
/* 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 = ' / ' ;
2010-03-16 18:06:12 -04:00
pr_debug ( " Writing event: %s \n " , buf ) ;
ret = write ( fd , buf , strlen ( buf ) ) ;
if ( ret < = 0 )
die ( " Failed to write event: %s " , strerror ( errno ) ) ;
2009-12-15 10:32:10 -05:00
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
}
2010-03-16 18:06:12 -04:00
void del_perf_probe_events ( struct strlist * dellist )
2009-12-08 17:03:23 -05:00
{
int fd ;
const char * group , * event ;
char * p , * str ;
struct str_node * ent ;
struct strlist * namelist ;
2010-03-16 18:06:05 -04:00
fd = open_kprobe_events ( true ) ;
2009-12-08 17:03:23 -05:00
/* Get current event names */
2010-03-16 18:06:12 -04:00
namelist = get_kprobe_trace_event_names ( fd , true ) ;
2009-12-08 17:03:23 -05:00
2009-12-15 10:32:03 -05:00
strlist__for_each ( ent , dellist ) {
2010-03-16 18:05:30 -04:00
str = xstrdup ( ent - > s ) ;
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 ;
2010-03-17 12:13:28 +01:00
# ifndef NO_DWARF_SUPPORT
2010-03-16 18:05:37 -04:00
int fd , ret ;
2010-03-17 12:13:28 +01:00
# endif
2010-03-16 18:05:37 -04:00
/* Search a line range */
init_vmlinux ( ) ;
2010-03-17 12:13:28 +01:00
# ifndef NO_DWARF_SUPPORT
2010-03-16 18:05:37 -04:00
fd = open_vmlinux ( ) ;
if ( fd < 0 )
die ( " Could not open debuginfo file. " ) ;
ret = find_line_range ( fd , lr ) ;
if ( ret < = 0 )
die ( " Source line is not found. \n " ) ;
close ( fd ) ;
2010-03-17 12:13:28 +01:00
# endif
2010-01-06 09:45:34 -05:00
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 ) ;
}
2010-03-16 18:05:37 -04:00