Commit f6180773 authored by Steven Rostedt's avatar Steven Rostedt

ftrace: add command interface for function selection

Allow for other tracers to add their own commands for function
selection. This interface gives a trace the ability to name a
command for function selection. Right now it is pretty limited
in what it offers, but this is a building step for more features.

The :mod: command is converted to this interface and also serves
as a template for other implementations.
Signed-off-by: default avatarSteven Rostedt <srostedt@redhat.com>
parent e68746a2
...@@ -95,6 +95,13 @@ stack_trace_sysctl(struct ctl_table *table, int write, ...@@ -95,6 +95,13 @@ stack_trace_sysctl(struct ctl_table *table, int write,
loff_t *ppos); loff_t *ppos);
#endif #endif
struct ftrace_func_command {
struct list_head list;
char *name;
int (*func)(char *func, char *cmd,
char *params, int enable);
};
#ifdef CONFIG_DYNAMIC_FTRACE #ifdef CONFIG_DYNAMIC_FTRACE
/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */ /* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
#include <asm/ftrace.h> #include <asm/ftrace.h>
...@@ -119,6 +126,9 @@ struct dyn_ftrace { ...@@ -119,6 +126,9 @@ struct dyn_ftrace {
int ftrace_force_update(void); int ftrace_force_update(void);
void ftrace_set_filter(unsigned char *buf, int len, int reset); void ftrace_set_filter(unsigned char *buf, int len, int reset);
int register_ftrace_command(struct ftrace_func_command *cmd);
int unregister_ftrace_command(struct ftrace_func_command *cmd);
/* defined in arch */ /* defined in arch */
extern int ftrace_ip_converted(unsigned long ip); extern int ftrace_ip_converted(unsigned long ip);
extern int ftrace_dyn_arch_init(void *data); extern int ftrace_dyn_arch_init(void *data);
...@@ -202,6 +212,12 @@ extern void ftrace_enable_daemon(void); ...@@ -202,6 +212,12 @@ extern void ftrace_enable_daemon(void);
# define ftrace_disable_daemon() do { } while (0) # define ftrace_disable_daemon() do { } while (0)
# define ftrace_enable_daemon() do { } while (0) # define ftrace_enable_daemon() do { } while (0)
static inline void ftrace_release(void *start, unsigned long size) { } static inline void ftrace_release(void *start, unsigned long size) { }
static inline int register_ftrace_command(struct ftrace_func_command *cmd)
{
}
static inline int unregister_ftrace_command(char *cmd_name)
{
}
#endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_DYNAMIC_FTRACE */
/* totally disable ftrace - can not re-enable after this */ /* totally disable ftrace - can not re-enable after this */
......
...@@ -1239,9 +1239,93 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) ...@@ -1239,9 +1239,93 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable)
spin_unlock(&ftrace_lock); spin_unlock(&ftrace_lock);
} }
/*
* We register the module command as a template to show others how
* to register the a command as well.
*/
static int
ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
{
char *mod;
/*
* cmd == 'mod' because we only registered this func
* for the 'mod' ftrace_func_command.
* But if you register one func with multiple commands,
* you can tell which command was used by the cmd
* parameter.
*/
/* we must have a module name */
if (!param)
return -EINVAL;
mod = strsep(&param, ":");
if (!strlen(mod))
return -EINVAL;
ftrace_match_module_records(func, mod, enable);
return 0;
}
static struct ftrace_func_command ftrace_mod_cmd = {
.name = "mod",
.func = ftrace_mod_callback,
};
static int __init ftrace_mod_cmd_init(void)
{
return register_ftrace_command(&ftrace_mod_cmd);
}
device_initcall(ftrace_mod_cmd_init);
static LIST_HEAD(ftrace_commands);
static DEFINE_MUTEX(ftrace_cmd_mutex);
int register_ftrace_command(struct ftrace_func_command *cmd)
{
struct ftrace_func_command *p;
int ret = 0;
mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry(p, &ftrace_commands, list) {
if (strcmp(cmd->name, p->name) == 0) {
ret = -EBUSY;
goto out_unlock;
}
}
list_add(&cmd->list, &ftrace_commands);
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);
return ret;
}
int unregister_ftrace_command(struct ftrace_func_command *cmd)
{
struct ftrace_func_command *p, *n;
int ret = -ENODEV;
mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry_safe(p, n, &ftrace_commands, list) {
if (strcmp(cmd->name, p->name) == 0) {
ret = 0;
list_del_init(&p->list);
goto out_unlock;
}
}
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);
return ret;
}
static int ftrace_process_regex(char *buff, int len, int enable) static int ftrace_process_regex(char *buff, int len, int enable)
{ {
char *func, *mod, *command, *next = buff; struct ftrace_func_command *p;
char *func, *command, *next = buff;
int ret = -EINVAL;
func = strsep(&next, ":"); func = strsep(&next, ":");
...@@ -1250,21 +1334,21 @@ static int ftrace_process_regex(char *buff, int len, int enable) ...@@ -1250,21 +1334,21 @@ static int ftrace_process_regex(char *buff, int len, int enable)
return 0; return 0;
} }
/* command fonud */ /* command found */
command = strsep(&next, ":"); command = strsep(&next, ":");
if (strcmp(command, "mod") == 0) { mutex_lock(&ftrace_cmd_mutex);
/* only match modules */ list_for_each_entry(p, &ftrace_commands, list) {
if (!next) if (strcmp(p->name, command) == 0) {
return -EINVAL; ret = p->func(func, command, next, enable);
goto out_unlock;
mod = strsep(&next, ":"); }
ftrace_match_module_records(func, mod, enable);
return 0;
} }
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);
return -EINVAL; return ret;
} }
static ssize_t static ssize_t
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment