2009-10-09 01:17:38 +04:00
/*
* builtin - probe . c
*
* Builtin probe command : Set up probe events by C expression
*
* 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>
# undef _GNU_SOURCE
# include "perf.h"
# include "builtin.h"
# include "util/util.h"
2009-12-09 01:03:23 +03:00
# include "util/strlist.h"
2011-01-20 17:15:39 +03:00
# include "util/strfilter.h"
2010-03-17 01:05:37 +03:00
# include "util/symbol.h"
2009-10-17 04:08:10 +04:00
# include "util/debug.h"
2009-12-17 01:24:00 +03:00
# include "util/debugfs.h"
2009-10-09 01:17:38 +04:00
# include "util/parse-options.h"
# include "util/probe-finder.h"
2009-12-01 03:19:58 +03:00
# include "util/probe-event.h"
2009-10-09 01:17:38 +04:00
2011-01-20 17:15:39 +03:00
# define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
2011-01-20 17:15:45 +03:00
# define DEFAULT_FUNC_FILTER "!_*"
2009-10-09 01:17:38 +04:00
# define MAX_PATH_LEN 256
/* Session management structure */
static struct {
2009-12-15 18:31:14 +03:00
bool list_events ;
2009-12-15 18:32:25 +03:00
bool force_add ;
2010-01-06 17:45:34 +03:00
bool show_lines ;
2010-10-21 14:13:23 +04:00
bool show_vars ;
2010-10-21 14:13:35 +04:00
bool show_ext_vars ;
2011-01-13 15:46:11 +03:00
bool show_funcs ;
2010-10-21 14:13:23 +04:00
bool mod_events ;
2010-03-17 01:06:12 +03:00
int nevents ;
struct perf_probe_event events [ MAX_PROBES ] ;
2009-12-09 01:03:23 +03:00
struct strlist * dellist ;
2010-01-06 17:45:34 +03:00
struct line_range line_range ;
2010-10-21 14:13:41 +04:00
const char * target_module ;
2010-04-21 23:56:40 +04:00
int max_probe_points ;
2011-01-20 17:15:39 +03:00
struct strfilter * filter ;
2010-03-17 01:05:44 +03:00
} params ;
2009-10-09 01:17:38 +04:00
2009-10-27 23:43:10 +03:00
/* Parse an event definition. Note that any error must die. */
2010-04-12 21:17:42 +04:00
static int parse_probe_event ( const char * str )
2009-10-09 01:17:38 +04:00
{
2010-03-17 01:06:12 +03:00
struct perf_probe_event * pev = & params . events [ params . nevents ] ;
2010-04-12 21:17:42 +04:00
int ret ;
2009-10-09 01:17:38 +04:00
2010-03-17 01:06:12 +03:00
pr_debug ( " probe-definition(%d): %s \n " , params . nevents , str ) ;
2010-05-19 05:57:27 +04:00
if ( + + params . nevents = = MAX_PROBES ) {
pr_err ( " Too many probes (> %d) were specified. " , MAX_PROBES ) ;
return - 1 ;
}
2009-10-09 01:17:38 +04:00
2010-03-17 01:06:12 +03:00
/* Parse a perf-probe command into event */
2010-04-12 21:17:42 +04:00
ret = parse_perf_probe_command ( str , pev ) ;
2010-03-17 01:06:12 +03:00
pr_debug ( " %d arguments \n " , pev - > nargs ) ;
2010-04-12 21:17:42 +04:00
return ret ;
2009-10-27 23:43:02 +03:00
}
2010-04-12 21:17:42 +04:00
static int parse_probe_event_argv ( int argc , const char * * argv )
2009-12-09 01:02:54 +03:00
{
2010-04-12 21:17:42 +04:00
int i , len , ret ;
2009-12-09 01:02:54 +03:00
char * buf ;
/* Bind up rest arguments */
len = 0 ;
for ( i = 0 ; i < argc ; i + + )
len + = strlen ( argv [ i ] ) + 1 ;
2010-05-19 05:57:27 +04:00
buf = zalloc ( len + 1 ) ;
if ( buf = = NULL )
return - ENOMEM ;
2009-12-09 01:02:54 +03:00
len = 0 ;
for ( i = 0 ; i < argc ; i + + )
len + = sprintf ( & buf [ len ] , " %s " , argv [ i ] ) ;
2010-10-21 14:13:23 +04:00
params . mod_events = true ;
2010-04-12 21:17:42 +04:00
ret = parse_probe_event ( buf ) ;
2009-12-09 01:02:54 +03:00
free ( buf ) ;
2010-04-12 21:17:42 +04:00
return ret ;
2009-12-09 01:02:54 +03:00
}
2009-10-27 23:43:10 +03:00
static int opt_add_probe_event ( const struct option * opt __used ,
2009-10-27 23:43:02 +03:00
const char * str , int unset __used )
{
2010-10-21 14:13:23 +04:00
if ( str ) {
params . mod_events = true ;
2010-04-12 21:17:42 +04:00
return parse_probe_event ( str ) ;
2010-10-21 14:13:23 +04:00
} else
2010-04-12 21:17:42 +04:00
return 0 ;
2009-10-09 01:17:38 +04:00
}
2009-12-09 01:03:23 +03:00
static int opt_del_probe_event ( const struct option * opt __used ,
const char * str , int unset __used )
{
if ( str ) {
2010-10-21 14:13:23 +04:00
params . mod_events = true ;
2010-03-17 01:05:44 +03:00
if ( ! params . dellist )
params . dellist = strlist__new ( true , NULL ) ;
strlist__add ( params . dellist , str ) ;
2009-12-09 01:03:23 +03:00
}
return 0 ;
}
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2010-01-16 15:31:16 +03:00
static int opt_show_lines ( const struct option * opt __used ,
const char * str , int unset __used )
{
2010-04-12 21:17:42 +04:00
int ret = 0 ;
2011-08-11 15:02:53 +04:00
if ( ! str )
return 0 ;
if ( params . show_lines ) {
pr_warning ( " Warning: more than one --line options are "
" detected. Only the first one is valid. \n " ) ;
return 0 ;
}
2010-03-17 01:05:44 +03:00
params . show_lines = true ;
2011-08-11 15:02:53 +04:00
ret = parse_line_range_desc ( str , & params . line_range ) ;
INIT_LIST_HEAD ( & params . line_range . line_list ) ;
2010-04-12 21:17:42 +04:00
return ret ;
2010-01-16 15:31:16 +03:00
}
2010-10-21 14:13:23 +04:00
static int opt_show_vars ( const struct option * opt __used ,
const char * str , int unset __used )
{
struct perf_probe_event * pev = & params . events [ params . nevents ] ;
int ret ;
if ( ! str )
return 0 ;
ret = parse_probe_event ( str ) ;
if ( ! ret & & pev - > nargs ! = 0 ) {
pr_err ( " Error: '--vars' doesn't accept arguments. \n " ) ;
return - EINVAL ;
}
params . show_vars = true ;
return ret ;
}
2011-01-20 17:15:45 +03:00
# endif
2011-01-20 17:15:39 +03:00
static int opt_set_filter ( const struct option * opt __used ,
const char * str , int unset __used )
{
const char * err ;
if ( str ) {
pr_debug2 ( " Set filter: %s \n " , str ) ;
if ( params . filter )
strfilter__delete ( params . filter ) ;
params . filter = strfilter__new ( str , & err ) ;
if ( ! params . filter ) {
2011-02-01 00:45:38 +03:00
pr_err ( " Filter parse error at %td. \n " , err - str + 1 ) ;
2011-01-20 17:15:39 +03:00
pr_err ( " Source: \" %s \" \n " , str ) ;
pr_err ( " %*c \n " , ( int ) ( err - str + 1 ) , ' ^ ' ) ;
return - EINVAL ;
}
}
return 0 ;
}
2009-10-09 01:17:38 +04:00
static const char * const probe_usage [ ] = {
2009-10-27 23:43:02 +03:00
" perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...] " ,
" perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...] " ,
2009-12-09 01:03:23 +03:00
" perf probe [<options>] --del '[GROUP:]EVENT' ... " ,
2009-12-01 03:20:17 +03:00
" perf probe --list " ,
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2010-10-21 14:13:41 +04:00
" perf probe [<options>] --line 'LINEDESC' " ,
" perf probe [<options>] --vars 'PROBEPOINT' " ,
2010-02-25 16:35:12 +03:00
# endif
2009-10-09 01:17:38 +04:00
NULL
} ;
static const struct option options [ ] = {
2010-04-13 12:37:33 +04:00
OPT_INCR ( ' v ' , " verbose " , & verbose ,
2009-10-17 04:08:10 +04:00
" be more verbose (show parsed arguments, etc) " ) ,
2010-03-17 01:05:44 +03:00
OPT_BOOLEAN ( ' l ' , " list " , & params . list_events ,
2009-12-15 18:31:14 +03:00
" list up current probe events " ) ,
2009-12-09 01:03:23 +03:00
OPT_CALLBACK ( ' d ' , " del " , NULL , " [GROUP:]EVENT " , " delete a probe event. " ,
opt_del_probe_event ) ,
2009-10-27 23:43:02 +03:00
OPT_CALLBACK ( ' a ' , " add " , NULL ,
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2010-03-04 06:38:43 +03:00
" [EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT "
2010-04-12 21:16:53 +04:00
" [[NAME=]ARG ...] " ,
2010-03-22 19:10:26 +03:00
# else
2010-04-12 21:16:53 +04:00
" [EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...] " ,
2009-10-08 02:28:30 +04:00
# endif
2009-10-09 01:17:38 +04:00
" probe point definition, where \n "
2009-12-15 18:32:18 +03:00
" \t \t GROUP: \t Group name (optional) \n "
" \t \t EVENT: \t Event name \n "
2009-10-09 01:17:38 +04:00
" \t \t FUNC: \t Function name \n "
2010-02-25 16:36:12 +03:00
" \t \t OFF: \t Offset from function entry (in byte) \n "
2009-10-27 23:43:10 +03:00
" \t \t %return: \t Put the probe at function return \n "
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2009-10-09 01:17:38 +04:00
" \t \t SRC: \t Source code path \n "
2010-02-25 16:36:12 +03:00
" \t \t RL: \t Relative line number from function entry. \n "
" \t \t AL: \t Absolute line number in file. \n "
" \t \t PT: \t Lazy expression of line code. \n "
2009-10-09 01:17:38 +04:00
" \t \t ARG: \t Probe argument (local variable name or \n "
2009-12-01 03:19:58 +03:00
" \t \t \t kprobe-tracer argument format.) \n " ,
2010-03-22 19:10:26 +03:00
# else
" \t \t ARG: \t Probe argument (kprobe-tracer argument format.) \n " ,
# endif
2009-10-27 23:43:10 +03:00
opt_add_probe_event ) ,
2010-03-17 01:05:44 +03:00
OPT_BOOLEAN ( ' f ' , " force " , & params . force_add , " forcibly add events "
2009-12-15 18:32:25 +03:00
" with existing name " ) ,
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2010-01-06 17:45:34 +03:00
OPT_CALLBACK ( ' L ' , " line " , NULL ,
2010-04-02 20:50:39 +04:00
" FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2] " ,
2010-01-06 17:45:34 +03:00
" Show source code lines. " , opt_show_lines ) ,
2010-10-21 14:13:23 +04:00
OPT_CALLBACK ( ' V ' , " vars " , NULL ,
" FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT " ,
" Show accessible variables on PROBEDEF " , opt_show_vars ) ,
2010-10-21 14:13:35 +04:00
OPT_BOOLEAN ( ' \0 ' , " externs " , & params . show_ext_vars ,
" Show external variables too (with --vars only) " ) ,
2010-03-22 19:10:26 +03:00
OPT_STRING ( ' k ' , " vmlinux " , & symbol_conf . vmlinux_name ,
" file " , " vmlinux pathname " ) ,
2010-06-14 23:26:30 +04:00
OPT_STRING ( ' s ' , " source " , & symbol_conf . source_prefix ,
" directory " , " path to kernel source " ) ,
2010-10-21 14:13:41 +04:00
OPT_STRING ( ' m ' , " module " , & params . target_module ,
2011-06-27 11:27:51 +04:00
" modname|path " ,
" target module name (for online) or path (for offline) " ) ,
2010-01-06 17:45:34 +03:00
# endif
2010-03-17 01:06:05 +03:00
OPT__DRY_RUN ( & probe_event_dry_run ) ,
2010-04-21 23:56:40 +04:00
OPT_INTEGER ( ' \0 ' , " max-probes " , & params . max_probe_points ,
" Set how many probe points can be found for a probe. " ) ,
2011-01-13 15:46:11 +03:00
OPT_BOOLEAN ( ' F ' , " funcs " , & params . show_funcs ,
" Show potential probe-able functions. " ) ,
2011-01-20 17:15:45 +03:00
OPT_CALLBACK ( ' \0 ' , " filter " , NULL ,
" [!]FILTER " , " Set a filter (with --vars/funcs only) \n "
" \t \t \t (default: \" " DEFAULT_VAR_FILTER " \" for --vars, \n "
" \t \t \t \" " DEFAULT_FUNC_FILTER " \" for --funcs) " ,
opt_set_filter ) ,
2009-10-09 01:17:38 +04:00
OPT_END ( )
} ;
int cmd_probe ( int argc , const char * * argv , const char * prefix __used )
{
2010-04-12 21:17:42 +04:00
int ret ;
2009-10-09 01:17:38 +04:00
argc = parse_options ( argc , argv , options , probe_usage ,
2009-10-27 23:43:02 +03:00
PARSE_OPT_STOP_AT_NON_OPTION ) ;
2009-12-15 18:31:28 +03:00
if ( argc > 0 ) {
if ( strcmp ( argv [ 0 ] , " - " ) = = 0 ) {
pr_warning ( " Error: '-' is not supported. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2010-04-12 21:17:42 +04:00
ret = parse_probe_event_argv ( argc , argv ) ;
if ( ret < 0 ) {
pr_err ( " Error: Parse Error. (%d) \n " , ret ) ;
return ret ;
}
2009-12-15 18:31:28 +03:00
}
2009-10-27 23:43:02 +03:00
2010-04-21 23:56:40 +04:00
if ( params . max_probe_points = = 0 )
params . max_probe_points = MAX_PROBES ;
2010-03-17 01:06:12 +03:00
if ( ( ! params . nevents & & ! params . dellist & & ! params . list_events & &
2011-01-13 15:46:11 +03:00
! params . show_lines & & ! params . show_funcs ) )
2009-10-09 01:17:38 +04:00
usage_with_options ( probe_usage , options ) ;
2010-12-10 16:06:03 +03:00
/*
* Only consider the user ' s kernel image path if given .
*/
symbol_conf . try_vmlinux_path = ( symbol_conf . vmlinux_name = = NULL ) ;
2010-03-17 01:05:44 +03:00
if ( params . list_events ) {
2010-10-21 14:13:23 +04:00
if ( params . mod_events ) {
2010-04-12 21:17:42 +04:00
pr_err ( " Error: Don't use --list with --add/--del. \n " ) ;
2009-12-09 01:03:23 +03:00
usage_with_options ( probe_usage , options ) ;
}
2010-03-17 01:05:44 +03:00
if ( params . show_lines ) {
2010-04-12 21:17:42 +04:00
pr_err ( " Error: Don't use --list with --line. \n " ) ;
2010-01-06 17:45:34 +03:00
usage_with_options ( probe_usage , options ) ;
}
2010-10-21 14:13:23 +04:00
if ( params . show_vars ) {
pr_err ( " Error: Don't use --list with --vars. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2011-01-13 15:46:11 +03:00
if ( params . show_funcs ) {
pr_err ( " Error: Don't use --list with --funcs. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2010-04-12 21:17:42 +04:00
ret = show_perf_probe_events ( ) ;
if ( ret < 0 )
pr_err ( " Error: Failed to show event list. (%d) \n " ,
ret ) ;
return ret ;
2009-12-01 03:20:17 +03:00
}
2011-01-13 15:46:11 +03:00
if ( params . show_funcs ) {
if ( params . nevents ! = 0 | | params . dellist ) {
pr_err ( " Error: Don't use --funcs with "
" --add/--del. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
if ( params . show_lines ) {
pr_err ( " Error: Don't use --funcs with --line. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
if ( params . show_vars ) {
pr_err ( " Error: Don't use --funcs with --vars. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2011-01-20 17:15:45 +03:00
if ( ! params . filter )
params . filter = strfilter__new ( DEFAULT_FUNC_FILTER ,
NULL ) ;
ret = show_available_funcs ( params . target_module ,
params . filter ) ;
strfilter__delete ( params . filter ) ;
2011-01-13 15:46:11 +03:00
if ( ret < 0 )
pr_err ( " Error: Failed to show functions. "
" (%d) \n " , ret ) ;
return ret ;
}
2009-12-01 03:20:17 +03:00
2010-03-22 19:10:26 +03:00
# ifdef DWARF_SUPPORT
2010-03-17 01:05:44 +03:00
if ( params . show_lines ) {
2010-10-21 14:13:23 +04:00
if ( params . mod_events ) {
pr_err ( " Error: Don't use --line with "
" --add/--del. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
if ( params . show_vars ) {
pr_err ( " Error: Don't use --line with --vars. \n " ) ;
2010-01-06 17:45:34 +03:00
usage_with_options ( probe_usage , options ) ;
}
2010-03-17 01:05:37 +03:00
2010-10-21 14:13:41 +04:00
ret = show_line_range ( & params . line_range , params . target_module ) ;
2010-04-12 21:17:42 +04:00
if ( ret < 0 )
pr_err ( " Error: Failed to show lines. (%d) \n " , ret ) ;
return ret ;
2010-01-06 17:45:34 +03:00
}
2010-10-21 14:13:23 +04:00
if ( params . show_vars ) {
if ( params . mod_events ) {
pr_err ( " Error: Don't use --vars with "
" --add/--del. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2011-01-20 17:15:39 +03:00
if ( ! params . filter )
params . filter = strfilter__new ( DEFAULT_VAR_FILTER ,
NULL ) ;
2010-10-21 14:13:23 +04:00
ret = show_available_vars ( params . events , params . nevents ,
2010-10-21 14:13:35 +04:00
params . max_probe_points ,
2010-10-21 14:13:41 +04:00
params . target_module ,
2011-01-20 17:15:39 +03:00
params . filter ,
2010-10-21 14:13:35 +04:00
params . show_ext_vars ) ;
2011-01-20 17:15:39 +03:00
strfilter__delete ( params . filter ) ;
2010-10-21 14:13:23 +04:00
if ( ret < 0 )
pr_err ( " Error: Failed to show vars. (%d) \n " , ret ) ;
return ret ;
}
2010-01-06 17:45:34 +03:00
# endif
2010-03-17 01:05:44 +03:00
if ( params . dellist ) {
2010-04-12 21:17:42 +04:00
ret = del_perf_probe_events ( params . dellist ) ;
2010-03-17 01:05:44 +03:00
strlist__delete ( params . dellist ) ;
2010-04-12 21:17:42 +04:00
if ( ret < 0 ) {
pr_err ( " Error: Failed to delete events. (%d) \n " , ret ) ;
return ret ;
}
2009-12-09 01:03:23 +03:00
}
2010-04-12 21:17:42 +04:00
if ( params . nevents ) {
ret = add_perf_probe_events ( params . events , params . nevents ,
2010-10-21 14:13:29 +04:00
params . max_probe_points ,
2010-10-21 14:13:41 +04:00
params . target_module ,
2010-10-21 14:13:29 +04:00
params . force_add ) ;
2010-04-12 21:17:42 +04:00
if ( ret < 0 ) {
pr_err ( " Error: Failed to add events. (%d) \n " , ret ) ;
return ret ;
}
}
2009-10-09 01:17:38 +04:00
return 0 ;
}