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: Steven Rostedt <srostedt@redhat.com>
This commit is contained in:
parent
e68746a271
commit
f6180773d9
@ -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 {
|
|||||||
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);
|
|||||||
# 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)
|
|||||||
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(¶m, ":");
|
||||||
|
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)
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user