linux/kernel/trace/trace_events_synth.c

// 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);