2009-10-08 17: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 .
*
*/
# 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>
# include "perf.h"
# include "builtin.h"
# include "util/util.h"
2009-12-08 17:03:23 -05:00
# include "util/strlist.h"
2011-01-20 23:15:39 +09:00
# include "util/strfilter.h"
2010-03-16 18:05:37 -04:00
# include "util/symbol.h"
2009-10-16 20:08:10 -04:00
# include "util/debug.h"
2013-12-09 17:14:23 +01:00
# include <api/fs/debugfs.h>
2009-10-08 17:17:38 -04:00
# include "util/parse-options.h"
# include "util/probe-finder.h"
2009-11-30 19:19:58 -05:00
# include "util/probe-event.h"
2009-10-08 17:17:38 -04:00
2011-01-20 23:15:39 +09:00
# define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
2011-01-20 23:15:45 +09:00
# define DEFAULT_FUNC_FILTER "!_*"
2015-04-24 18:47:50 +09:00
# define DEFAULT_LIST_FILTER "*:*"
2009-10-08 17:17:38 -04:00
/* Session management structure */
static struct {
2015-05-06 00:22:57 +09:00
int command ; /* Command short_name */
2009-12-15 10:31:14 -05:00
bool list_events ;
2012-04-16 17:39:09 +05:30
bool uprobes ;
2014-10-27 16:31:31 -04:00
bool quiet ;
2015-04-01 19:25:42 +09:00
bool target_used ;
2010-03-16 18:06:12 -04:00
int nevents ;
struct perf_probe_event events [ MAX_PROBES ] ;
2010-01-06 09:45:34 -05:00
struct line_range line_range ;
2014-01-16 09:39:47 +00:00
char * target ;
2011-01-20 23:15:39 +09:00
struct strfilter * filter ;
2010-03-16 18:05:44 -04:00
} params ;
2009-10-08 17:17:38 -04:00
2009-10-27 16:43:10 -04:00
/* Parse an event definition. Note that any error must die. */
2010-04-12 13:17:42 -04:00
static int parse_probe_event ( const char * str )
2009-10-08 17:17:38 -04:00
{
2010-03-16 18:06:12 -04:00
struct perf_probe_event * pev = & params . events [ params . nevents ] ;
2010-04-12 13:17:42 -04:00
int ret ;
2009-10-08 17:17:38 -04:00
2010-03-16 18:06:12 -04:00
pr_debug ( " probe-definition(%d): %s \n " , params . nevents , str ) ;
2010-05-18 22:57:27 -03:00
if ( + + params . nevents = = MAX_PROBES ) {
pr_err ( " Too many probes (> %d) were specified. " , MAX_PROBES ) ;
return - 1 ;
}
2009-10-08 17:17:38 -04:00
2012-04-16 17:39:09 +05:30
pev - > uprobes = params . uprobes ;
2015-04-01 19:25:39 +09:00
if ( params . target ) {
pev - > target = strdup ( params . target ) ;
if ( ! pev - > target )
return - ENOMEM ;
2015-04-01 19:25:42 +09:00
params . target_used = true ;
2015-04-01 19:25:39 +09:00
}
2012-04-16 17:39:09 +05:30
2010-03-16 18:06:12 -04:00
/* Parse a perf-probe command into event */
2010-04-12 13:17:42 -04:00
ret = parse_perf_probe_command ( str , pev ) ;
2010-03-16 18:06:12 -04:00
pr_debug ( " %d arguments \n " , pev - > nargs ) ;
2010-04-12 13:17:42 -04:00
return ret ;
2009-10-27 16:43:02 -04:00
}
2015-04-24 18:47:50 +09:00
static int params_add_filter ( const char * str )
{
const char * err = NULL ;
int ret = 0 ;
pr_debug2 ( " Add filter: %s \n " , str ) ;
if ( ! params . filter ) {
params . filter = strfilter__new ( str , & err ) ;
if ( ! params . filter )
ret = err ? - EINVAL : - ENOMEM ;
} else
ret = strfilter__or ( params . filter , str , & err ) ;
if ( ret = = - EINVAL ) {
pr_err ( " Filter parse error at %td. \n " , err - str + 1 ) ;
pr_err ( " Source: \" %s \" \n " , str ) ;
pr_err ( " %*c \n " , ( int ) ( err - str + 1 ) , ' ^ ' ) ;
}
return ret ;
}
2012-04-16 17:39:25 +05:30
static int set_target ( const char * ptr )
{
int found = 0 ;
const char * buf ;
/*
* The first argument after options can be an absolute path
* to an executable / library or kernel module .
*
* TODO : Support relative path , and $ PATH , $ LD_LIBRARY_PATH ,
* short module name .
*/
if ( ! params . target & & ptr & & * ptr = = ' / ' ) {
2014-01-16 09:39:47 +00:00
params . target = strdup ( ptr ) ;
if ( ! params . target )
return - ENOMEM ;
2015-04-01 19:25:42 +09:00
params . target_used = false ;
2014-01-16 09:39:47 +00:00
2012-04-16 17:39:25 +05:30
found = 1 ;
buf = ptr + ( strlen ( ptr ) - 3 ) ;
if ( strcmp ( buf , " .ko " ) )
params . uprobes = true ;
}
return found ;
}
2010-04-12 13:17:42 -04:00
static int parse_probe_event_argv ( int argc , const char * * argv )
2009-12-08 17:02:54 -05:00
{
2012-04-16 17:39:25 +05:30
int i , len , ret , found_target ;
2009-12-08 17:02:54 -05:00
char * buf ;
2012-04-16 17:39:25 +05:30
found_target = set_target ( argv [ 0 ] ) ;
2014-01-16 09:39:47 +00:00
if ( found_target < 0 )
return found_target ;
2012-04-16 17:39:25 +05:30
if ( found_target & & argc = = 1 )
return 0 ;
2009-12-08 17:02:54 -05:00
/* Bind up rest arguments */
len = 0 ;
2012-04-16 17:39:25 +05:30
for ( i = 0 ; i < argc ; i + + ) {
if ( i = = 0 & & found_target )
continue ;
2009-12-08 17:02:54 -05:00
len + = strlen ( argv [ i ] ) + 1 ;
2012-04-16 17:39:25 +05:30
}
2010-05-18 22:57:27 -03:00
buf = zalloc ( len + 1 ) ;
if ( buf = = NULL )
return - ENOMEM ;
2009-12-08 17:02:54 -05:00
len = 0 ;
2012-04-16 17:39:25 +05:30
for ( i = 0 ; i < argc ; i + + ) {
if ( i = = 0 & & found_target )
continue ;
2009-12-08 17:02:54 -05:00
len + = sprintf ( & buf [ len ] , " %s " , argv [ i ] ) ;
2012-04-16 17:39:25 +05:30
}
2010-04-12 13:17:42 -04:00
ret = parse_probe_event ( buf ) ;
2009-12-08 17:02:54 -05:00
free ( buf ) ;
2010-04-12 13:17:42 -04:00
return ret ;
2009-12-08 17:02:54 -05:00
}
2012-04-16 17:39:09 +05:30
static int opt_set_target ( const struct option * opt , const char * str ,
2012-09-11 01:15:03 +03:00
int unset __maybe_unused )
2012-04-16 17:39:09 +05:30
{
int ret = - ENOENT ;
2013-12-26 05:41:50 +00:00
char * tmp ;
2012-04-16 17:39:09 +05:30
2015-04-01 19:25:39 +09:00
if ( str ) {
2012-04-16 17:39:09 +05:30
if ( ! strcmp ( opt - > long_name , " exec " ) )
params . uprobes = true ;
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2012-04-16 17:39:09 +05:30
else if ( ! strcmp ( opt - > long_name , " module " ) )
params . uprobes = false ;
# endif
else
return ret ;
2013-12-26 05:41:50 +00:00
/* Expand given path to absolute path, except for modulename */
if ( params . uprobes | | strchr ( str , ' / ' ) ) {
tmp = realpath ( str , NULL ) ;
if ( ! tmp ) {
pr_warning ( " Failed to get the absolute path of %s: %m \n " , str ) ;
return ret ;
}
} else {
tmp = strdup ( str ) ;
if ( ! tmp )
return - ENOMEM ;
}
2015-04-01 19:25:39 +09:00
free ( params . target ) ;
2013-12-26 05:41:50 +00:00
params . target = tmp ;
2015-04-01 19:25:42 +09:00
params . target_used = false ;
2012-04-16 17:39:09 +05:30
ret = 0 ;
}
return ret ;
}
2015-05-06 00:22:57 +09:00
/* Command option callbacks */
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2015-05-06 00:22:57 +09:00
static int opt_show_lines ( const struct option * opt ,
2012-09-11 01:15:03 +03:00
const char * str , int unset __maybe_unused )
2010-01-16 21:31:16 +09:00
{
2010-04-12 13:17:42 -04:00
int ret = 0 ;
2011-08-11 20:02:53 +09:00
if ( ! str )
return 0 ;
2015-05-06 00:22:57 +09:00
if ( params . command = = ' L ' ) {
2011-08-11 20:02:53 +09:00
pr_warning ( " Warning: more than one --line options are "
" detected. Only the first one is valid. \n " ) ;
return 0 ;
}
2015-05-06 00:22:57 +09:00
params . command = opt - > short_name ;
2011-08-11 20:02:53 +09:00
ret = parse_line_range_desc ( str , & params . line_range ) ;
2010-04-12 13:17:42 -04:00
return ret ;
2010-01-16 21:31:16 +09:00
}
2010-10-21 19:13:23 +09:00
2015-05-06 00:22:57 +09:00
static int opt_show_vars ( const struct option * opt ,
2012-09-11 01:15:03 +03:00
const char * str , int unset __maybe_unused )
2010-10-21 19:13:23 +09:00
{
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 ;
}
2015-05-06 00:22:57 +09:00
params . command = opt - > short_name ;
2010-10-21 19:13:23 +09:00
return ret ;
}
2011-01-20 23:15:45 +09:00
# endif
2015-05-06 00:22:57 +09:00
static int opt_add_probe_event ( const struct option * opt ,
const char * str , int unset __maybe_unused )
{
if ( str ) {
params . command = opt - > short_name ;
return parse_probe_event ( str ) ;
}
return 0 ;
}
static int opt_set_filter_with_command ( const struct option * opt ,
const char * str , int unset )
2015-05-05 11:29:50 +09:00
{
if ( ! unset )
2015-05-06 00:22:57 +09:00
params . command = opt - > short_name ;
2015-05-05 11:29:50 +09:00
if ( str )
return params_add_filter ( str ) ;
return 0 ;
}
2011-01-20 23:15:39 +09:00
2012-09-11 01:15:03 +03:00
static int opt_set_filter ( const struct option * opt __maybe_unused ,
const char * str , int unset __maybe_unused )
2011-01-20 23:15:39 +09:00
{
2015-04-24 18:47:50 +09:00
if ( str )
return params_add_filter ( str ) ;
2011-01-20 23:15:39 +09:00
2015-04-24 18:47:50 +09:00
return 0 ;
2011-01-20 23:15:39 +09:00
}
2009-10-08 17:17:38 -04:00
2014-02-06 05:32:09 +00:00
static int init_params ( void )
2014-01-16 09:39:47 +00:00
{
2014-02-06 05:32:09 +00:00
return line_range__init ( & params . line_range ) ;
2014-01-16 09:39:47 +00:00
}
static void cleanup_params ( void )
{
int i ;
for ( i = 0 ; i < params . nevents ; i + + )
clear_perf_probe_event ( params . events + i ) ;
line_range__clear ( & params . line_range ) ;
free ( params . target ) ;
if ( params . filter )
strfilter__delete ( params . filter ) ;
memset ( & params , 0 , sizeof ( params ) ) ;
}
2014-06-06 07:13:52 +00:00
static void pr_err_with_code ( const char * msg , int err )
{
2014-08-14 02:22:34 +00:00
char sbuf [ STRERR_BUFSIZE ] ;
2014-06-06 07:13:52 +00:00
pr_err ( " %s " , msg ) ;
2014-08-14 02:22:34 +00:00
pr_debug ( " Reason: %s (Code: %d) " ,
strerror_r ( - err , sbuf , sizeof ( sbuf ) ) , err ) ;
2014-06-06 07:13:52 +00:00
pr_err ( " \n " ) ;
}
2014-01-16 09:39:47 +00:00
static int
__cmd_probe ( int argc , const char * * argv , const char * prefix __maybe_unused )
2012-10-01 15:20:58 -03:00
{
const char * const probe_usage [ ] = {
" perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...] " ,
" perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...] " ,
" perf probe [<options>] --del '[GROUP:]EVENT' ... " ,
2015-04-24 18:47:50 +09:00
" perf probe --list [GROUP:]EVENT ... " ,
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2012-10-01 15:20:58 -03:00
" perf probe [<options>] --line 'LINEDESC' " ,
" perf probe [<options>] --vars 'PROBEPOINT' " ,
2010-02-25 08:35:12 -05:00
# endif
2015-04-23 22:46:12 +09:00
" perf probe [<options>] --funcs " ,
2012-10-01 15:20:58 -03:00
NULL
2015-04-24 18:47:50 +09:00
} ;
2014-10-23 00:15:49 +09:00
struct option options [ ] = {
2010-04-13 18:37:33 +10:00
OPT_INCR ( ' v ' , " verbose " , & verbose ,
2009-10-16 20:08:10 -04:00
" be more verbose (show parsed arguments, etc) " ) ,
2014-10-27 16:31:31 -04:00
OPT_BOOLEAN ( ' q ' , " quiet " , & params . quiet ,
" be quiet (do not show any mesages) " ) ,
2015-04-24 18:47:50 +09:00
OPT_CALLBACK_DEFAULT ( ' l ' , " list " , NULL , " [GROUP:]EVENT " ,
2015-05-06 00:22:57 +09:00
" list up probe events " ,
opt_set_filter_with_command , DEFAULT_LIST_FILTER ) ,
2009-12-08 17:03:23 -05:00
OPT_CALLBACK ( ' d ' , " del " , NULL , " [GROUP:]EVENT " , " delete a probe event. " ,
2015-05-06 00:22:57 +09:00
opt_set_filter_with_command ) ,
2009-10-27 16:43:02 -04:00
OPT_CALLBACK ( ' a ' , " add " , NULL ,
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2010-03-03 22:38:43 -05:00
" [EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT "
2010-04-12 13:16:53 -04:00
" [[NAME=]ARG ...] " ,
2010-03-22 13:10:26 -03:00
# else
2010-04-12 13:16:53 -04:00
" [EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...] " ,
2009-10-07 18:28:30 -04:00
# endif
2009-10-08 17:17:38 -04:00
" probe point definition, where \n "
2009-12-15 10:32:18 -05:00
" \t \t GROUP: \t Group name (optional) \n "
" \t \t EVENT: \t Event name \n "
2009-10-08 17:17:38 -04:00
" \t \t FUNC: \t Function name \n "
2010-02-25 08:36:12 -05:00
" \t \t OFF: \t Offset from function entry (in byte) \n "
2009-10-27 16:43:10 -04:00
" \t \t %return: \t Put the probe at function return \n "
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2009-10-08 17:17:38 -04:00
" \t \t SRC: \t Source code path \n "
2010-02-25 08:36:12 -05: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-08 17:17:38 -04:00
" \t \t ARG: \t Probe argument (local variable name or \n "
2009-11-30 19:19:58 -05:00
" \t \t \t kprobe-tracer argument format.) \n " ,
2010-03-22 13:10:26 -03:00
# else
" \t \t ARG: \t Probe argument (kprobe-tracer argument format.) \n " ,
# endif
2009-10-27 16:43:10 -04:00
opt_add_probe_event ) ,
2015-05-08 10:03:31 +09:00
OPT_BOOLEAN ( ' f ' , " force " , & probe_conf . force_add , " forcibly add events "
2009-12-15 10:32:25 -05:00
" with existing name " ) ,
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2010-01-06 09:45:34 -05:00
OPT_CALLBACK ( ' L ' , " line " , NULL ,
2010-04-02 12:50:39 -04:00
" FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2] " ,
2010-01-06 09:45:34 -05:00
" Show source code lines. " , opt_show_lines ) ,
2010-10-21 19:13:23 +09:00
OPT_CALLBACK ( ' V ' , " vars " , NULL ,
" FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT " ,
" Show accessible variables on PROBEDEF " , opt_show_vars ) ,
2015-05-08 10:03:31 +09:00
OPT_BOOLEAN ( ' \0 ' , " externs " , & probe_conf . show_ext_vars ,
2010-10-21 19:13:35 +09:00
" Show external variables too (with --vars only) " ) ,
perf probe: Add --range option to show a variable's location range
It is not easy for users to get the accurate byte offset or the line
number where a local variable can be probed.
With '--range' option, local variables in the scope of the probe point
are showed with a byte offset range, and can be added according to this
range information.
For example, there are some variables in the function
generic_perform_write():
<generic_perform_write@mm/filemap.c:0>
0 ssize_t generic_perform_write(struct file *file,
1 struct iov_iter *i, loff_t pos)
2 {
3 struct address_space *mapping = file->f_mapping;
4 const struct address_space_operations *a_ops = mapping->a_ops;
...
42 status = a_ops->write_begin(file, mapping, pos, bytes, flags,
&page, &fsdata);
44 if (unlikely(status < 0))
But we fail when we try to probe the variable 'a_ops' at line 42 or 44.
$ perf probe --add 'generic_perform_write:42 a_ops'
Failed to find the location of a_ops at this address.
Perhaps, it has been optimized out.
This is because the source code do not match the assembly, so a variable
may not be available in the source code line where it appears.
After this patch, we can lookup the accurate byte offset range of a
variable, 'INV' indicates that this variable is not valid at the given
point, but available in the scope:
$ perf probe --vars 'generic_perform_write:42' --range
Available variables at generic_perform_write:42
@<generic_perform_write+141>
[INV] ssize_t written @<generic_perform_write+[324-331]>
[INV] struct address_space_operations* a_ops @<generic_perform_write+[55-61,170-176,223-246]>
[VAL] (unknown_type) fsdata @<generic_perform_write+[70-307,346-411]>
[VAL] loff_t pos @<generic_perform_write+[0-286,286-336,346-411]>
[VAL] long int status @<generic_perform_write+[83-342,346-411]>
[VAL] long unsigned int bytes @<generic_perform_write+[122-311,320-338,346-403,403-411]>
[VAL] struct address_space* mapping @<generic_perform_write+[35-344,346-411]>
[VAL] struct iov_iter* i @<generic_perform_write+[0-340,346-411]>
[VAL] struct page* page @<generic_perform_write+[70-307,346-411]>
Then it is more clear for us to add a probe with this variable:
$ perf probe --add 'generic_perform_write+170 a_ops'
Added new event:
probe:generic_perform_write (on generic_perform_write+170 with a_ops)
Signed-off-by: He Kuang <hekuang@huawei.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1431336304-16863-2-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-05-11 09:25:03 +00:00
OPT_BOOLEAN ( ' \0 ' , " range " , & probe_conf . show_location_range ,
" Show variables location range in scope (with --vars only) " ) ,
2010-03-22 13:10:26 -03:00
OPT_STRING ( ' k ' , " vmlinux " , & symbol_conf . vmlinux_name ,
" file " , " vmlinux pathname " ) ,
2010-06-14 15:26:30 -04:00
OPT_STRING ( ' s ' , " source " , & symbol_conf . source_prefix ,
" directory " , " path to kernel source " ) ,
2012-04-16 17:39:09 +05:30
OPT_CALLBACK ( ' m ' , " module " , NULL , " modname|path " ,
" target module name (for online) or path (for offline) " ,
opt_set_target ) ,
2015-05-08 10:03:33 +09:00
OPT_BOOLEAN ( ' \0 ' , " no-inlines " , & probe_conf . no_inlines ,
" Don't search inlined functions " ) ,
2010-01-06 09:45:34 -05:00
# endif
2010-03-16 18:06:05 -04:00
OPT__DRY_RUN ( & probe_event_dry_run ) ,
2015-05-08 10:03:31 +09:00
OPT_INTEGER ( ' \0 ' , " max-probes " , & probe_conf . max_probes ,
2010-04-21 15:56:40 -04:00
" Set how many probe points can be found for a probe. " ) ,
2015-05-05 11:29:50 +09:00
OPT_CALLBACK_DEFAULT ( ' F ' , " funcs " , NULL , " [FILTER] " ,
" Show potential probe-able functions. " ,
2015-05-06 00:22:57 +09:00
opt_set_filter_with_command , DEFAULT_FUNC_FILTER ) ,
2011-01-20 23:15:45 +09: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 ) ,
2012-04-16 17:39:09 +05:30
OPT_CALLBACK ( ' x ' , " exec " , NULL , " executable|path " ,
" target executable name or path " , opt_set_target ) ,
2013-10-28 12:04:24 +04:00
OPT_BOOLEAN ( 0 , " demangle " , & symbol_conf . demangle ,
2014-10-27 16:31:24 -04:00
" Enable symbol demangling " ) ,
2014-09-13 07:15:05 +03:00
OPT_BOOLEAN ( 0 , " demangle-kernel " , & symbol_conf . demangle_kernel ,
" Enable kernel symbol demangling " ) ,
2009-10-08 17:17:38 -04:00
OPT_END ( )
2012-10-01 15:20:58 -03:00
} ;
2010-04-12 13:17:42 -04:00
int ret ;
2014-10-23 00:15:49 +09:00
set_option_flag ( options , ' a ' , " add " , PARSE_OPT_EXCLUSIVE ) ;
set_option_flag ( options , ' d ' , " del " , PARSE_OPT_EXCLUSIVE ) ;
set_option_flag ( options , ' l ' , " list " , PARSE_OPT_EXCLUSIVE ) ;
# ifdef HAVE_DWARF_SUPPORT
set_option_flag ( options , ' L ' , " line " , PARSE_OPT_EXCLUSIVE ) ;
set_option_flag ( options , ' V ' , " vars " , PARSE_OPT_EXCLUSIVE ) ;
# endif
2015-04-23 22:46:12 +09:00
set_option_flag ( options , ' F ' , " funcs " , PARSE_OPT_EXCLUSIVE ) ;
2014-10-23 00:15:49 +09:00
2009-10-08 17:17:38 -04:00
argc = parse_options ( argc , argv , options , probe_usage ,
2009-10-27 16:43:02 -04:00
PARSE_OPT_STOP_AT_NON_OPTION ) ;
2009-12-15 10:31:28 -05:00
if ( argc > 0 ) {
if ( strcmp ( argv [ 0 ] , " - " ) = = 0 ) {
pr_warning ( " Error: '-' is not supported. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2015-05-06 00:22:57 +09:00
if ( params . command & & params . command ! = ' a ' ) {
pr_warning ( " Error: another command except --add is set. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2010-04-12 13:17:42 -04:00
ret = parse_probe_event_argv ( argc , argv ) ;
if ( ret < 0 ) {
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Command Parse Error. " , ret ) ;
2010-04-12 13:17:42 -04:00
return ret ;
}
2015-05-06 00:22:57 +09:00
params . command = ' a ' ;
2009-12-15 10:31:28 -05:00
}
2009-10-27 16:43:02 -04:00
2014-10-27 16:31:31 -04:00
if ( params . quiet ) {
if ( verbose ! = 0 ) {
pr_err ( " Error: -v and -q are exclusive. \n " ) ;
return - EINVAL ;
}
verbose = - 1 ;
}
2015-05-08 10:03:31 +09:00
if ( probe_conf . max_probes = = 0 )
probe_conf . max_probes = MAX_PROBES ;
2010-04-21 15:56:40 -04:00
2010-12-10 14:06:03 +01:00
/*
* Only consider the user ' s kernel image path if given .
*/
symbol_conf . try_vmlinux_path = ( symbol_conf . vmlinux_name = = NULL ) ;
2015-05-06 00:22:57 +09:00
switch ( params . command ) {
case ' l ' :
2012-04-16 17:39:09 +05:30
if ( params . uprobes ) {
pr_warning ( " Error: Don't use --list with --exec. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2015-04-24 18:47:50 +09:00
ret = show_perf_probe_events ( params . filter ) ;
2010-04-12 13:17:42 -04:00
if ( ret < 0 )
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to show event list. " , ret ) ;
2010-04-12 13:17:42 -04:00
return ret ;
2015-05-06 00:22:57 +09:00
case ' F ' :
2012-04-16 17:39:09 +05:30
ret = show_available_funcs ( params . target , params . filter ,
params . uprobes ) ;
2011-01-13 21:46:11 +09:00
if ( ret < 0 )
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to show functions. " , ret ) ;
2011-01-13 21:46:11 +09:00
return ret ;
2013-09-30 12:07:11 +02:00
# ifdef HAVE_DWARF_SUPPORT
2015-05-06 00:22:57 +09:00
case ' L ' :
2014-09-17 08:40:54 +00:00
ret = show_line_range ( & params . line_range , params . target ,
params . uprobes ) ;
2010-04-12 13:17:42 -04:00
if ( ret < 0 )
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to show lines. " , ret ) ;
2010-04-12 13:17:42 -04:00
return ret ;
2015-05-06 00:22:57 +09:00
case ' V ' :
2011-01-20 23:15:39 +09:00
if ( ! params . filter )
params . filter = strfilter__new ( DEFAULT_VAR_FILTER ,
NULL ) ;
2010-10-21 19:13:23 +09:00
ret = show_available_vars ( params . events , params . nevents ,
2015-05-08 10:03:31 +09:00
params . filter ) ;
2010-10-21 19:13:23 +09:00
if ( ret < 0 )
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to show vars. " , ret ) ;
2010-10-21 19:13:23 +09:00
return ret ;
2010-01-06 09:45:34 -05:00
# endif
2015-05-06 00:22:57 +09:00
case ' d ' :
2015-05-05 11:29:48 +09:00
ret = del_perf_probe_events ( params . filter ) ;
2010-04-12 13:17:42 -04:00
if ( ret < 0 ) {
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to delete events. " , ret ) ;
2010-04-12 13:17:42 -04:00
return ret ;
}
2015-05-06 00:22:57 +09:00
break ;
case ' a ' :
2015-04-01 19:25:42 +09:00
/* Ensure the last given target is used */
if ( params . target & & ! params . target_used ) {
pr_warning ( " Error: -x/-m must follow the probe definitions. \n " ) ;
usage_with_options ( probe_usage , options ) ;
}
2015-05-08 10:03:31 +09:00
ret = add_perf_probe_events ( params . events , params . nevents ) ;
2010-04-12 13:17:42 -04:00
if ( ret < 0 ) {
2014-06-06 07:13:52 +00:00
pr_err_with_code ( " Error: Failed to add events. " , ret ) ;
2010-04-12 13:17:42 -04:00
return ret ;
}
2015-05-06 00:22:57 +09:00
break ;
default :
usage_with_options ( probe_usage , options ) ;
2010-04-12 13:17:42 -04:00
}
2009-10-08 17:17:38 -04:00
return 0 ;
}
2014-01-16 09:39:47 +00:00
int cmd_probe ( int argc , const char * * argv , const char * prefix )
{
int ret ;
2014-02-06 05:32:09 +00:00
ret = init_params ( ) ;
if ( ! ret ) {
ret = __cmd_probe ( argc , argv , prefix ) ;
cleanup_params ( ) ;
}
2014-01-16 09:39:47 +00:00
2015-05-06 21:46:45 +09:00
return ret < 0 ? ret : 0 ;
2014-01-16 09:39:47 +00:00
}