Skip to content

Commit 2a588dd

Browse files
Tom Zanussirostedt
authored andcommitted
tracing: Add kprobe event command generation functions
Add functions used to generate kprobe event commands, built on top of the dynevent_cmd interface. kprobe_event_gen_cmd_start() is used to create a kprobe event command using a variable arg list, and kretprobe_event_gen_cmd_start() does the same for kretprobe event commands. kprobe_event_add_fields() can be used to add single fields one by one or as a group. Once all desired fields are added, kprobe_event_gen_cmd_end() or kretprobe_event_gen_cmd_end() respectively are used to actually execute the command and create the event. Link: http://lkml.kernel.org/r/95cc4696502bb6017f9126f306a45ad19b4cc14f.1580323897.git.zanussi@kernel.org Acked-by: Masami Hiramatsu <[email protected]> Signed-off-by: Tom Zanussi <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 9fe41ef commit 2a588dd

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

include/linux/trace_events.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ extern void trace_put_event_file(struct trace_event_file *file);
358358

359359
enum dynevent_type {
360360
DYNEVENT_TYPE_SYNTH = 1,
361+
DYNEVENT_TYPE_KPROBE,
361362
DYNEVENT_TYPE_NONE,
362363
};
363364

@@ -442,6 +443,36 @@ extern int synth_event_add_val(const char *field_name, u64 val,
442443
struct synth_event_trace_state *trace_state);
443444
extern int synth_event_trace_end(struct synth_event_trace_state *trace_state);
444445

446+
extern int kprobe_event_delete(const char *name);
447+
448+
extern void kprobe_event_cmd_init(struct dynevent_cmd *cmd,
449+
char *buf, int maxlen);
450+
451+
#define kprobe_event_gen_cmd_start(cmd, name, loc, ...) \
452+
__kprobe_event_gen_cmd_start(cmd, false, name, loc, ## __VA_ARGS__, NULL)
453+
454+
#define kretprobe_event_gen_cmd_start(cmd, name, loc, ...) \
455+
__kprobe_event_gen_cmd_start(cmd, true, name, loc, ## __VA_ARGS__, NULL)
456+
457+
extern int __kprobe_event_gen_cmd_start(struct dynevent_cmd *cmd,
458+
bool kretprobe,
459+
const char *name,
460+
const char *loc, ...);
461+
462+
#define kprobe_event_add_fields(cmd, ...) \
463+
__kprobe_event_add_fields(cmd, ## __VA_ARGS__, NULL)
464+
465+
#define kprobe_event_add_field(cmd, field) \
466+
__kprobe_event_add_fields(cmd, field, NULL)
467+
468+
extern int __kprobe_event_add_fields(struct dynevent_cmd *cmd, ...);
469+
470+
#define kprobe_event_gen_cmd_end(cmd) \
471+
dynevent_create(cmd)
472+
473+
#define kretprobe_event_gen_cmd_end(cmd) \
474+
dynevent_create(cmd)
475+
445476
/*
446477
* Event file flags:
447478
* ENABLED - The event is enabled

kernel/trace/trace_kprobe.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,167 @@ int trace_kprobe_run_command(const char *command)
906906
return trace_run_command(command, create_or_delete_trace_kprobe);
907907
}
908908

909+
static int trace_kprobe_run_cmd(struct dynevent_cmd *cmd)
910+
{
911+
return trace_run_command(cmd->buf, create_or_delete_trace_kprobe);
912+
}
913+
914+
/**
915+
* kprobe_event_cmd_init - Initialize a kprobe event command object
916+
* @cmd: A pointer to the dynevent_cmd struct representing the new event
917+
* @buf: A pointer to the buffer used to build the command
918+
* @maxlen: The length of the buffer passed in @buf
919+
*
920+
* Initialize a synthetic event command object. Use this before
921+
* calling any of the other kprobe_event functions.
922+
*/
923+
void kprobe_event_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen)
924+
{
925+
dynevent_cmd_init(cmd, buf, maxlen, DYNEVENT_TYPE_KPROBE,
926+
trace_kprobe_run_cmd);
927+
}
928+
EXPORT_SYMBOL_GPL(kprobe_event_cmd_init);
929+
930+
/**
931+
* __kprobe_event_gen_cmd_start - Generate a kprobe event command from arg list
932+
* @cmd: A pointer to the dynevent_cmd struct representing the new event
933+
* @name: The name of the kprobe event
934+
* @loc: The location of the kprobe event
935+
* @kretprobe: Is this a return probe?
936+
* @args: Variable number of arg (pairs), one pair for each field
937+
*
938+
* NOTE: Users normally won't want to call this function directly, but
939+
* rather use the kprobe_event_gen_cmd_start() wrapper, which automatically
940+
* adds a NULL to the end of the arg list. If this function is used
941+
* directly, make sure the last arg in the variable arg list is NULL.
942+
*
943+
* Generate a kprobe event command to be executed by
944+
* kprobe_event_gen_cmd_end(). This function can be used to generate the
945+
* complete command or only the first part of it; in the latter case,
946+
* kprobe_event_add_fields() can be used to add more fields following this.
947+
*
948+
* Return: 0 if successful, error otherwise.
949+
*/
950+
int __kprobe_event_gen_cmd_start(struct dynevent_cmd *cmd, bool kretprobe,
951+
const char *name, const char *loc, ...)
952+
{
953+
char buf[MAX_EVENT_NAME_LEN];
954+
struct dynevent_arg arg;
955+
va_list args;
956+
int ret;
957+
958+
if (cmd->type != DYNEVENT_TYPE_KPROBE)
959+
return -EINVAL;
960+
961+
if (kretprobe)
962+
snprintf(buf, MAX_EVENT_NAME_LEN, "r:kprobes/%s", name);
963+
else
964+
snprintf(buf, MAX_EVENT_NAME_LEN, "p:kprobes/%s", name);
965+
966+
ret = dynevent_str_add(cmd, buf);
967+
if (ret)
968+
return ret;
969+
970+
dynevent_arg_init(&arg, NULL, 0);
971+
arg.str = loc;
972+
ret = dynevent_arg_add(cmd, &arg);
973+
if (ret)
974+
return ret;
975+
976+
va_start(args, loc);
977+
for (;;) {
978+
const char *field;
979+
980+
field = va_arg(args, const char *);
981+
if (!field)
982+
break;
983+
984+
if (++cmd->n_fields > MAX_TRACE_ARGS) {
985+
ret = -EINVAL;
986+
break;
987+
}
988+
989+
arg.str = field;
990+
ret = dynevent_arg_add(cmd, &arg);
991+
if (ret)
992+
break;
993+
}
994+
va_end(args);
995+
996+
return ret;
997+
}
998+
EXPORT_SYMBOL_GPL(__kprobe_event_gen_cmd_start);
999+
1000+
/**
1001+
* __kprobe_event_add_fields - Add probe fields to a kprobe command from arg list
1002+
* @cmd: A pointer to the dynevent_cmd struct representing the new event
1003+
* @args: Variable number of arg (pairs), one pair for each field
1004+
*
1005+
* NOTE: Users normally won't want to call this function directly, but
1006+
* rather use the kprobe_event_add_fields() wrapper, which
1007+
* automatically adds a NULL to the end of the arg list. If this
1008+
* function is used directly, make sure the last arg in the variable
1009+
* arg list is NULL.
1010+
*
1011+
* Add probe fields to an existing kprobe command using a variable
1012+
* list of args. Fields are added in the same order they're listed.
1013+
*
1014+
* Return: 0 if successful, error otherwise.
1015+
*/
1016+
int __kprobe_event_add_fields(struct dynevent_cmd *cmd, ...)
1017+
{
1018+
struct dynevent_arg arg;
1019+
va_list args;
1020+
int ret;
1021+
1022+
if (cmd->type != DYNEVENT_TYPE_KPROBE)
1023+
return -EINVAL;
1024+
1025+
dynevent_arg_init(&arg, NULL, 0);
1026+
1027+
va_start(args, cmd);
1028+
for (;;) {
1029+
const char *field;
1030+
1031+
field = va_arg(args, const char *);
1032+
if (!field)
1033+
break;
1034+
1035+
if (++cmd->n_fields > MAX_TRACE_ARGS) {
1036+
ret = -EINVAL;
1037+
break;
1038+
}
1039+
1040+
arg.str = field;
1041+
ret = dynevent_arg_add(cmd, &arg);
1042+
if (ret)
1043+
break;
1044+
}
1045+
va_end(args);
1046+
1047+
return ret;
1048+
}
1049+
EXPORT_SYMBOL_GPL(__kprobe_event_add_fields);
1050+
1051+
/**
1052+
* kprobe_event_delete - Delete a kprobe event
1053+
* @name: The name of the kprobe event to delete
1054+
*
1055+
* Delete a kprobe event with the give @name from kernel code rather
1056+
* than directly from the command line.
1057+
*
1058+
* Return: 0 if successful, error otherwise.
1059+
*/
1060+
int kprobe_event_delete(const char *name)
1061+
{
1062+
char buf[MAX_EVENT_NAME_LEN];
1063+
1064+
snprintf(buf, MAX_EVENT_NAME_LEN, "-:%s", name);
1065+
1066+
return trace_run_command(buf, create_or_delete_trace_kprobe);
1067+
}
1068+
EXPORT_SYMBOL_GPL(kprobe_event_delete);
1069+
9091070
static int trace_kprobe_release(struct dyn_event *ev)
9101071
{
9111072
struct trace_kprobe *tk = to_trace_kprobe(ev);

0 commit comments

Comments
 (0)