blob: 0798088f52cd2dc453222cae97a4ed262fb28590 [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022 Google Inc, Steven Rostedt <rostedt@goodmis.org>
*/
#include "ktrace.h"
static struct ktrace_commands create_cmds[] =
{
{
"kprobe",
"create kprobe name function/address fields",
"# Create a kprobe with 'name' at a function or an address given.\n"
"# followed by a set of fields."
},
{
"eprobe",
"create eprobe name system/event fields",
"# Create an event on top of another event.\n"
"# Where 'name' is the new event.\n"
"# 'system/event' is the event to attach to.\n"
"# Followed by the fields to display",
},
{
"synthetic",
"create synthetic name system/event.field1[,field2,..] system2/event2.field1[,field2,..] field1=systemX/eventX.field[ field2=systemX/eventX.field ...]",
"# Where the synthetic event is created when the fields of system/event\n"
"# match system/event2 fields. Then add the fields of the synthetic event\n"
"# on how they will map to the other fields.\n#\n"
"# A synthetic event field may also equal timestamps:\n"
"# start=system/event.TIMESTAMP\n"
"# start=system/event.TIMESTAMP_USECS\n#\n"
"# Or even a delta:\n"
"# delta=system/event.TIMESTAMP-system2/event2.TIMESTAMP"
},
{
NULL
}
};
static struct ktrace_commands enable_cmds[] =
{
{
"tracing",
"enable tracing",
" Makes the ring buffer writable"
},
{
"event",
"enable event (all|system|system/event)",
" Enable an event.\n"
" Key word 'all' will enable all events\n"
" Specify just a system to enable all events within that system.\n"
" Specify system/event, with '/' to separate the two, to enable just one event."
},
{
NULL
}
};
static struct ktrace_commands disable_cmds[] =
{
{
"tracing",
"disable tracing",
" Disable writing to the ring buffer"
},
{
"event",
"disable event (all|system|system/event)",
" Disable an event.\n"
" Key word 'all' will disable all events\n"
" Specify just a system to disable all events within that system.\n"
" Specify system/event, with '/' to separate the two, to disable just one event."
},
{
NULL
}
};
static struct ktrace_commands ktrace_cmds[] =
{
{
"create",
"create (kprobe|eprobe|synthetic) options",
" kprobe - to create a kernel probe event.\n"
" eprobe - to create an event on top of another event.\n"
" synthetic - to create a synthetic event",
.link = create_cmds
},
{
"enable",
"enable (tracing|event)",
" tracing - to enable tracing if it is stopped.\n"
" event - to enable an event",
.link = enable_cmds
},
{
"disable",
"disable (tracing|event)",
" tracing - to disable tracing, just stops writing to the ring buffer.\n"
" event - stop an event.",
.link = disable_cmds
},
{
NULL
}
};
static int help_cmd(struct ccli *ccli, const char *arg,
struct ktrace_commands *commands)
{
int l = 1;
int i;
for (i = 0; l > 0 && commands[i].command; i++) {
if (strcmp(arg, commands[i].command) == 0) {
l = ccli_page(ccli, l, "usage: %s\n",
commands[i].usage);
l = ccli_page(ccli, l, "%s\n",
commands[i].help);
return 0;
}
}
ccli_printf(ccli, "Command %s not found\n", arg);
return 0;
}
int ktrace_help(struct ccli *ccli, const char *arg1, const char *arg2)
{
int l = 1;
int i;
if (!arg1) {
for (i = 0; l > 0 && ktrace_cmds[i].command; i++) {
if (i)
l = ccli_page(ccli, l, "\n");
l = ccli_page(ccli, l, "command: %s\n",
ktrace_cmds[i].command);
l = ccli_page(ccli, l, "usage: %s\n",
ktrace_cmds[i].usage);
l = ccli_page(ccli, l, "%s\n",
ktrace_cmds[i].help);
}
return 0;
}
if (!arg2)
return help_cmd(ccli, arg1, ktrace_cmds);
for (i = 0; l > 0 && ktrace_cmds[i].command; i++) {
if (strcmp(arg1, ktrace_cmds[i].command) == 0) {
if (ktrace_cmds[i].link)
return help_cmd(ccli, arg2, ktrace_cmds[i].link);
l = ccli_page(ccli, l, "usage: %s\n",
ktrace_cmds[i].usage);
l = ccli_page(ccli, l, "%s\n",
ktrace_cmds[i].help);
return 0;
}
ccli_printf(ccli, "Command %s not found\n", arg1);
}
return 0;
}
int cmd_help(struct ccli *ccli, const char *command, const char *line,
void *data, int argc, char **argv)
{
if (argc < 2)
return ktrace_help(ccli, NULL, NULL);
if (argc < 3)
return ktrace_help(ccli, argv[1], NULL);
return ktrace_help(ccli, argv[1], argv[2]);
}
static int help_complete(struct ccli *ccli, char ***list,
struct ktrace_commands *commands)
{
int cnt = 0;
int ret = 0;
int i;
for (i = 0; ret >= 0 && commands[i].command; i++)
ret = ccli_list_add(ccli, list, &cnt, commands[i].command);
return ret;
}
int help_completion(struct ccli *ccli, const char *command,
const char *line, int word,
char *match, char ***list, void *data)
{
char **argv;
int ret = 0;
int argc;
int i;
if (word > 2)
return 0;
if (word == 1)
return help_complete(ccli, list, ktrace_cmds);
argc = ccli_line_parse(line, &argv);
if (argc < 1)
return 0;
ret = 0;
for (i = 0; argc > 1 && ktrace_cmds[i].command; i++) {
if (strcmp(argv[1], ktrace_cmds[i].command) == 0) {
if (!ktrace_cmds[i].link)
break;
ret = help_complete(ccli, list, ktrace_cmds[i].link);
break;
}
}
ccli_argv_free(argv);
return ret;
}