// SPDX-License-Identifier: GPL-2.0 /* * trace_events_synth - synthetic trace events * * Copyright (C) 2015, 2020 Tom Zanussi <[email protected]> */ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/security.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/stacktrace.h> #include <linux/rculist.h> #include <linux/tracefs.h> /* for gfp flag names */ #include <linux/trace_events.h> #include <trace/events/mmflags.h> #include "trace_probe.h" #include "trace_probe_kernel.h" #include "trace_synth.h" #undef ERRORS #define ERRORS … #undef C #define C(a, b) … enum { … }; #undef C #define C(a, b) … static const char *err_text[] = …; static DEFINE_MUTEX(lastcmd_mutex); static char *last_cmd; static int errpos(const char *str) { … } static void last_cmd_set(const char *str) { … } static void synth_err(u8 err_type, u16 err_pos) { … } static int create_synth_event(const char *raw_command); static int synth_event_show(struct seq_file *m, struct dyn_event *ev); static int synth_event_release(struct dyn_event *ev); static bool synth_event_is_busy(struct dyn_event *ev); static bool synth_event_match(const char *system, const char *event, int argc, const char **argv, struct dyn_event *ev); static struct dyn_event_operations synth_event_ops = …; static bool is_synth_event(struct dyn_event *ev) { … } static struct synth_event *to_synth_event(struct dyn_event *ev) { … } static bool synth_event_is_busy(struct dyn_event *ev) { … } static bool synth_event_match(const char *system, const char *event, int argc, const char **argv, struct dyn_event *ev) { … } struct synth_trace_event { … }; static int synth_event_define_fields(struct trace_event_call *call) { … } static bool synth_field_signed(char *type) { … } static int synth_field_is_string(char *type) { … } static int synth_field_is_stack(char *type) { … } static int synth_field_string_size(char *type) { … } static int synth_field_size(char *type) { … } static const char *synth_field_fmt(char *type) { … } static void print_synth_event_num_val(struct trace_seq *s, char *print_fmt, char *name, int size, union trace_synth_field *val, char *space) { … } static enum print_line_t print_synth_event(struct trace_iterator *iter, int flags, struct trace_event *event) { … } static struct trace_event_functions synth_event_funcs = …; static unsigned int trace_string(struct synth_trace_event *entry, struct synth_event *event, char *str_val, bool is_dynamic, unsigned int data_size, unsigned int *n_u64) { … } static unsigned int trace_stack(struct synth_trace_event *entry, struct synth_event *event, long *stack, unsigned int data_size, unsigned int *n_u64) { … } static notrace void trace_event_raw_event_synth(void *__data, u64 *var_ref_vals, unsigned int *var_ref_idx) { … } static void free_synth_event_print_fmt(struct trace_event_call *call) { … } static int __set_synth_event_print_fmt(struct synth_event *event, char *buf, int len) { … } static int set_synth_event_print_fmt(struct trace_event_call *call) { … } static void free_synth_field(struct synth_field *field) { … } static int check_field_version(const char *prefix, const char *field_type, const char *field_name) { … } static struct synth_field *parse_synth_field(int argc, char **argv, int *consumed, int *field_version) { … } static void free_synth_tracepoint(struct tracepoint *tp) { … } static struct tracepoint *alloc_synth_tracepoint(char *name) { … } struct synth_event *find_synth_event(const char *name) { … } static struct trace_event_fields synth_event_fields_array[] = …; static int register_synth_event(struct synth_event *event) { … } static int unregister_synth_event(struct synth_event *event) { … } static void free_synth_event(struct synth_event *event) { … } static struct synth_event *alloc_synth_event(const char *name, int n_fields, struct synth_field **fields) { … } static int synth_event_check_arg_fn(void *data) { … } /** * synth_event_add_field - Add a new field to a synthetic event cmd * @cmd: A pointer to the dynevent_cmd struct representing the new event * @type: The type of the new field to add * @name: The name of the new field to add * * Add a new field to a synthetic event cmd object. Field ordering is in * the same order the fields are added. * * See synth_field_size() for available types. If field_name contains * [n] the field is considered to be an array. * * Return: 0 if successful, error otherwise. */ int synth_event_add_field(struct dynevent_cmd *cmd, const char *type, const char *name) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_add_field_str - Add a new field to a synthetic event cmd * @cmd: A pointer to the dynevent_cmd struct representing the new event * @type_name: The type and name of the new field to add, as a single string * * Add a new field to a synthetic event cmd object, as a single * string. The @type_name string is expected to be of the form 'type * name', which will be appended by ';'. No sanity checking is done - * what's passed in is assumed to already be well-formed. Field * ordering is in the same order the fields are added. * * See synth_field_size() for available types. If field_name contains * [n] the field is considered to be an array. * * Return: 0 if successful, error otherwise. */ int synth_event_add_field_str(struct dynevent_cmd *cmd, const char *type_name) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_add_fields - Add multiple fields to a synthetic event cmd * @cmd: A pointer to the dynevent_cmd struct representing the new event * @fields: An array of type/name field descriptions * @n_fields: The number of field descriptions contained in the fields array * * Add a new set of fields to a synthetic event cmd object. The event * fields that will be defined for the event should be passed in as an * array of struct synth_field_desc, and the number of elements in the * array passed in as n_fields. Field ordering will retain the * ordering given in the fields array. * * See synth_field_size() for available types. If field_name contains * [n] the field is considered to be an array. * * Return: 0 if successful, error otherwise. */ int synth_event_add_fields(struct dynevent_cmd *cmd, struct synth_field_desc *fields, unsigned int n_fields) { … } EXPORT_SYMBOL_GPL(…); /** * __synth_event_gen_cmd_start - Start a synthetic event command from arg list * @cmd: A pointer to the dynevent_cmd struct representing the new event * @name: The name of the synthetic event * @mod: The module creating the event, NULL if not created from a module * @...: Variable number of arg (pairs), one pair for each field * * NOTE: Users normally won't want to call this function directly, but * rather use the synth_event_gen_cmd_start() wrapper, which * automatically adds a NULL to the end of the arg list. If this * function is used directly, make sure the last arg in the variable * arg list is NULL. * * Generate a synthetic event command to be executed by * synth_event_gen_cmd_end(). This function can be used to generate * the complete command or only the first part of it; in the latter * case, synth_event_add_field(), synth_event_add_field_str(), or * synth_event_add_fields() can be used to add more fields following * this. * * There should be an even number variable args, each pair consisting * of a type followed by a field name. * * See synth_field_size() for available types. If field_name contains * [n] the field is considered to be an array. * * Return: 0 if successful, error otherwise. */ int __synth_event_gen_cmd_start(struct dynevent_cmd *cmd, const char *name, struct module *mod, ...) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_gen_cmd_array_start - Start synthetic event command from an array * @cmd: A pointer to the dynevent_cmd struct representing the new event * @name: The name of the synthetic event * @mod: The module creating the event, NULL if not created from a module * @fields: An array of type/name field descriptions * @n_fields: The number of field descriptions contained in the fields array * * Generate a synthetic event command to be executed by * synth_event_gen_cmd_end(). This function can be used to generate * the complete command or only the first part of it; in the latter * case, synth_event_add_field(), synth_event_add_field_str(), or * synth_event_add_fields() can be used to add more fields following * this. * * The event fields that will be defined for the event should be * passed in as an array of struct synth_field_desc, and the number of * elements in the array passed in as n_fields. Field ordering will * retain the ordering given in the fields array. * * See synth_field_size() for available types. If field_name contains * [n] the field is considered to be an array. * * Return: 0 if successful, error otherwise. */ int synth_event_gen_cmd_array_start(struct dynevent_cmd *cmd, const char *name, struct module *mod, struct synth_field_desc *fields, unsigned int n_fields) { … } EXPORT_SYMBOL_GPL(…); static int __create_synth_event(const char *name, const char *raw_fields) { … } /** * synth_event_create - Create a new synthetic event * @name: The name of the new synthetic event * @fields: An array of type/name field descriptions * @n_fields: The number of field descriptions contained in the fields array * @mod: The module creating the event, NULL if not created from a module * * Create a new synthetic event with the given name under the * trace/events/synthetic/ directory. The event fields that will be * defined for the event should be passed in as an array of struct * synth_field_desc, and the number elements in the array passed in as * n_fields. Field ordering will retain the ordering given in the * fields array. * * If the new synthetic event is being created from a module, the mod * param must be non-NULL. This will ensure that the trace buffer * won't contain unreadable events. * * The new synth event should be deleted using synth_event_delete() * function. The new synthetic event can be generated from modules or * other kernel code using trace_synth_event() and related functions. * * Return: 0 if successful, error otherwise. */ int synth_event_create(const char *name, struct synth_field_desc *fields, unsigned int n_fields, struct module *mod) { … } EXPORT_SYMBOL_GPL(…); static int destroy_synth_event(struct synth_event *se) { … } /** * synth_event_delete - Delete a synthetic event * @event_name: The name of the new synthetic event * * Delete a synthetic event that was created with synth_event_create(). * * Return: 0 if successful, error otherwise. */ int synth_event_delete(const char *event_name) { … } EXPORT_SYMBOL_GPL(…); static int check_command(const char *raw_command) { … } static int create_or_delete_synth_event(const char *raw_command) { … } static int synth_event_run_command(struct dynevent_cmd *cmd) { … } /** * synth_event_cmd_init - Initialize a synthetic event command object * @cmd: A pointer to the dynevent_cmd struct representing the new event * @buf: A pointer to the buffer used to build the command * @maxlen: The length of the buffer passed in @buf * * Initialize a synthetic event command object. Use this before * calling any of the other dyenvent_cmd functions. */ void synth_event_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen) { … } EXPORT_SYMBOL_GPL(…); static inline int __synth_event_trace_init(struct trace_event_file *file, struct synth_event_trace_state *trace_state) { … } static inline int __synth_event_trace_start(struct trace_event_file *file, struct synth_event_trace_state *trace_state, int dynamic_fields_size) { … } static inline void __synth_event_trace_end(struct synth_event_trace_state *trace_state) { … } /** * synth_event_trace - Trace a synthetic event * @file: The trace_event_file representing the synthetic event * @n_vals: The number of values in vals * @...: Variable number of args containing the event values * * Trace a synthetic event using the values passed in the variable * argument list. * * The argument list should be a list 'n_vals' u64 values. The number * of vals must match the number of field in the synthetic event, and * must be in the same order as the synthetic event fields. * * All vals should be cast to u64, and string vals are just pointers * to strings, cast to u64. Strings will be copied into space * reserved in the event for the string, using these pointers. * * Return: 0 on success, err otherwise. */ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_trace_array - Trace a synthetic event from an array * @file: The trace_event_file representing the synthetic event * @vals: Array of values * @n_vals: The number of values in vals * * Trace a synthetic event using the values passed in as 'vals'. * * The 'vals' array is just an array of 'n_vals' u64. The number of * vals must match the number of field in the synthetic event, and * must be in the same order as the synthetic event fields. * * All vals should be cast to u64, and string vals are just pointers * to strings, cast to u64. Strings will be copied into space * reserved in the event for the string, using these pointers. * * Return: 0 on success, err otherwise. */ int synth_event_trace_array(struct trace_event_file *file, u64 *vals, unsigned int n_vals) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_trace_start - Start piecewise synthetic event trace * @file: The trace_event_file representing the synthetic event * @trace_state: A pointer to object tracking the piecewise trace state * * Start the trace of a synthetic event field-by-field rather than all * at once. * * This function 'opens' an event trace, which means space is reserved * for the event in the trace buffer, after which the event's * individual field values can be set through either * synth_event_add_next_val() or synth_event_add_val(). * * A pointer to a trace_state object is passed in, which will keep * track of the current event trace state until the event trace is * closed (and the event finally traced) using * synth_event_trace_end(). * * Note that synth_event_trace_end() must be called after all values * have been added for each event trace, regardless of whether adding * all field values succeeded or not. * * Note also that for a given event trace, all fields must be added * using either synth_event_add_next_val() or synth_event_add_val() * but not both together or interleaved. * * Return: 0 on success, err otherwise. */ int synth_event_trace_start(struct trace_event_file *file, struct synth_event_trace_state *trace_state) { … } EXPORT_SYMBOL_GPL(…); static int __synth_event_add_val(const char *field_name, u64 val, struct synth_event_trace_state *trace_state) { … } /** * synth_event_add_next_val - Add the next field's value to an open synth trace * @val: The value to set the next field to * @trace_state: A pointer to object tracking the piecewise trace state * * Set the value of the next field in an event that's been opened by * synth_event_trace_start(). * * The val param should be the value cast to u64. If the value points * to a string, the val param should be a char * cast to u64. * * This function assumes all the fields in an event are to be set one * after another - successive calls to this function are made, one for * each field, in the order of the fields in the event, until all * fields have been set. If you'd rather set each field individually * without regard to ordering, synth_event_add_val() can be used * instead. * * Note however that synth_event_add_next_val() and * synth_event_add_val() can't be intermixed for a given event trace - * one or the other but not both can be used at the same time. * * Note also that synth_event_trace_end() must be called after all * values have been added for each event trace, regardless of whether * adding all field values succeeded or not. * * Return: 0 on success, err otherwise. */ int synth_event_add_next_val(u64 val, struct synth_event_trace_state *trace_state) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_add_val - Add a named field's value to an open synth trace * @field_name: The name of the synthetic event field value to set * @val: The value to set the named field to * @trace_state: A pointer to object tracking the piecewise trace state * * Set the value of the named field in an event that's been opened by * synth_event_trace_start(). * * The val param should be the value cast to u64. If the value points * to a string, the val param should be a char * cast to u64. * * This function looks up the field name, and if found, sets the field * to the specified value. This lookup makes this function more * expensive than synth_event_add_next_val(), so use that or the * none-piecewise synth_event_trace() instead if efficiency is more * important. * * Note however that synth_event_add_next_val() and * synth_event_add_val() can't be intermixed for a given event trace - * one or the other but not both can be used at the same time. * * Note also that synth_event_trace_end() must be called after all * values have been added for each event trace, regardless of whether * adding all field values succeeded or not. * * Return: 0 on success, err otherwise. */ int synth_event_add_val(const char *field_name, u64 val, struct synth_event_trace_state *trace_state) { … } EXPORT_SYMBOL_GPL(…); /** * synth_event_trace_end - End piecewise synthetic event trace * @trace_state: A pointer to object tracking the piecewise trace state * * End the trace of a synthetic event opened by * synth_event_trace__start(). * * This function 'closes' an event trace, which basically means that * it commits the reserved event and cleans up other loose ends. * * A pointer to a trace_state object is passed in, which will keep * track of the current event trace state opened with * synth_event_trace_start(). * * Note that this function must be called after all values have been * added for each event trace, regardless of whether adding all field * values succeeded or not. * * Return: 0 on success, err otherwise. */ int synth_event_trace_end(struct synth_event_trace_state *trace_state) { … } EXPORT_SYMBOL_GPL(…); static int create_synth_event(const char *raw_command) { … } static int synth_event_release(struct dyn_event *ev) { … } static int __synth_event_show(struct seq_file *m, struct synth_event *event) { … } static int synth_event_show(struct seq_file *m, struct dyn_event *ev) { … } static int synth_events_seq_show(struct seq_file *m, void *v) { … } static const struct seq_operations synth_events_seq_op = …; static int synth_events_open(struct inode *inode, struct file *file) { … } static ssize_t synth_events_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { … } static const struct file_operations synth_events_fops = …; /* * Register dynevent at core_initcall. This allows kernel to setup kprobe * events in postcore_initcall without tracefs. */ static __init int trace_events_synth_init_early(void) { … } core_initcall(trace_events_synth_init_early); static __init int trace_events_synth_init(void) { … } fs_initcall(trace_events_synth_init);