// SPDX-License-Identifier: GPL-2.0/* * trace_events_hist - trace event hist triggers * * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com> */ #include <linux/module.h>#include <linux/kallsyms.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/stacktrace.h>#include <linux/rculist.h>#include <linux/tracefs.h> #include "tracing_map.h"#include "trace.h"#include "trace_dynevent.h" #define SYNTH_SYSTEM "synthetic"#define SYNTH_FIELDS_MAX 16 #define STR_VAR_LEN_MAX 32 /* must be multiple of sizeof(u64) */ struct hist_field; typedef u64 (*hist_field_fn_t) (struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event); #define HIST_FIELD_OPERANDS_MAX 2#define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)#define HIST_ACTIONS_MAX 8 enum field_op_id { FIELD_OP_NONE, FIELD_OP_PLUS, FIELD_OP_MINUS, FIELD_OP_UNARY_MINUS,}; /* * A hist_var (histogram variable) contains variable information for * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF * flag set. A hist_var has a variable name e.g. ts0, and is * associated with a given histogram trigger, as specified by * hist_data. The hist_var idx is the unique index assigned to the * variable by the hist trigger's tracing_map. The idx is what is * used to set a variable's value and, by a variable reference, to * retrieve it. */struct hist_var { char *name; struct hist_trigger_data *hist_data; unsigned int idx;}; struct hist_field { struct ftrace_event_field *field; unsigned long flags; hist_field_fn_t fn; unsigned int size; unsigned int offset; unsigned int is_signed; const char *type; struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; struct hist_trigger_data *hist_data; /* * Variable fields contain variable-specific info in var. */ struct hist_var var; enum field_op_id operator; char *system; char *event_name; /* * The name field is used for EXPR and VAR_REF fields. VAR * fields contain the variable name in var.name. */ char *name; /* * When a histogram trigger is hit, if it has any references * to variables, the values of those variables are collected * into a var_ref_vals array by resolve_var_refs(). The * current value of each variable is read from the tracing_map * using the hist field's hist_var.idx and entered into the * var_ref_idx entry i.e. var_ref_vals[var_ref_idx]. */ unsigned int var_ref_idx; bool read_once;}; static u64 hist_field_none(struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ return 0;} static u64 hist_field_counter(struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ return 1;} static u64 hist_field_string(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ char *addr = (char *)(event + hist_field->field->offset); return (u64)(unsigned long)addr;} static u64 hist_field_dynstring(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ u32 str_item = *(u32 *)(event + hist_field->field->offset); int str_loc = str_item & 0xffff; char *addr = (char *)(event + str_loc); return (u64)(unsigned long)addr;} static u64 hist_field_pstring(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ char **addr = (char **)(event + hist_field->field->offset); return (u64)(unsigned long)*addr;} static u64 hist_field_log2(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ struct hist_field *operand = hist_field->operands[0]; u64 val = operand->fn(operand, elt, rbe, event); return (u64) ilog2(roundup_pow_of_two(val));} static u64 hist_field_plus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ struct hist_field *operand1 = hist_field->operands[0]; struct hist_field *operand2 = hist_field->operands[1]; u64 val1 = operand1->fn(operand1, elt, rbe, event); u64 val2 = operand2->fn(operand2, elt, rbe, event); return val1 + val2;} static u64 hist_field_minus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ struct hist_field *operand1 = hist_field->operands[0]; struct hist_field *operand2 = hist_field->operands[1]; u64 val1 = operand1->fn(operand1, elt, rbe, event); u64 val2 = operand2->fn(operand2, elt, rbe, event); return val1 - val2;} static u64 hist_field_unary_minus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event){ struct hist_field *operand = hist_field->operands[0]; s64 sval = (s64)operand->fn(operand, elt, rbe, event); u64 val = (u64)-sval; return val;} #define DEFINE_HIST_FIELD_FN(type) \ static u64 hist_field_##type(struct hist_field *hist_field, \ struct tracing_map_elt *elt, \ struct ring_buffer_event *rbe, \ void *event) \{ \ type *addr = (type *)(event + hist_field->field->offset); \ \ return (u64)(unsigned long)*addr; \} DEFINE_HIST_FIELD_FN(s64);DEFINE_HIST_FIELD_FN(u64);DEFINE_HIST_FIELD_FN(s32);DEFINE_HIST_FIELD_FN(u32);DEFINE_HIST_FIELD_FN(s16);DEFINE_HIST_FIELD_FN(u16);DEFINE_HIST_FIELD_FN(s8);DEFINE_HIST_FIELD_FN(u8); #define for_each_hist_field(i, hist_data) \ for ((i) = 0; (i) < (hist_data)->n_fields; (i)++) #define for_each_hist_val_field(i, hist_data) \ for ((i) = 0; (i) < (hist_data)->n_vals; (i)++) #define for_each_hist_key_field(i, hist_data) \ for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) #define HIST_STACKTRACE_DEPTH 16#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))#define HIST_STACKTRACE_SKIP 5 #define HITCOUNT_IDX 0#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) enum hist_field_flags { HIST_FIELD_FL_HITCOUNT = 1 << 0, HIST_FIELD_FL_KEY = 1 << 1, HIST_FIELD_FL_STRING = 1 << 2, HIST_FIELD_FL_HEX = 1 << 3, HIST_FIELD_FL_SYM = 1 << 4, HIST_FIELD_FL_SYM_OFFSET = 1 << 5, HIST_FIELD_FL_EXECNAME = 1 << 6, HIST_FIELD_FL_SYSCALL = 1 << 7, HIST_FIELD_FL_STACKTRACE = 1 << 8, HIST_FIELD_FL_LOG2 = 1 << 9, HIST_FIELD_FL_TIMESTAMP = 1 << 10, HIST_FIELD_FL_TIMESTAMP_USECS = 1 << 11, HIST_FIELD_FL_VAR = 1 << 12, HIST_FIELD_FL_EXPR = 1 << 13, HIST_FIELD_FL_VAR_REF = 1 << 14, HIST_FIELD_FL_CPU = 1 << 15, HIST_FIELD_FL_ALIAS = 1 << 16,}; struct var_defs { unsigned int n_vars; char *name[TRACING_MAP_VARS_MAX]; char *expr[TRACING_MAP_VARS_MAX];}; struct hist_trigger_attrs { char *keys_str; char *vals_str; char *sort_key_str; char *name; char *clock; bool pause; bool cont; bool clear; bool ts_in_usecs; unsigned int map_bits; char *assignment_str[TRACING_MAP_VARS_MAX]; unsigned int n_assignments; char *action_str[HIST_ACTIONS_MAX]; unsigned int n_actions; struct var_defs var_defs;}; struct field_var { struct hist_field *var; struct hist_field *val;}; struct field_var_hist { struct hist_trigger_data *hist_data; char *cmd;}; struct hist_trigger_data { struct hist_field *fields[HIST_FIELDS_MAX]; unsigned int n_vals; unsigned int n_keys; unsigned int n_fields; unsigned int n_vars; unsigned int key_size; struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX]; unsigned int n_sort_keys; struct trace_event_file *event_file; struct hist_trigger_attrs *attrs; struct tracing_map *map; bool enable_timestamps; bool remove; struct hist_field *var_refs[TRACING_MAP_VARS_MAX]; unsigned int n_var_refs; struct action_data *actions[HIST_ACTIONS_MAX]; unsigned int n_actions; struct field_var *field_vars[SYNTH_FIELDS_MAX]; unsigned int n_field_vars; unsigned int n_field_var_str; struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX]; unsigned int n_field_var_hists; struct field_var *max_vars[SYNTH_FIELDS_MAX]; unsigned int n_max_vars; unsigned int n_max_var_str;}; static int synth_event_create(int argc, const char **argv);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, struct dyn_event *ev); static struct dyn_event_operations synth_event_ops = { .create = synth_event_create, .show = synth_event_show, .is_busy = synth_event_is_busy, .free = synth_event_release, .match = synth_event_match,}; struct synth_field { char *type; char *name; size_t size; bool is_signed; bool is_string;}; struct synth_event { struct dyn_event devent; int ref; char *name; struct synth_field **fields; unsigned int n_fields; unsigned int n_u64; struct trace_event_class class; struct trace_event_call call; struct tracepoint *tp;}; static bool is_synth_event(struct dyn_event *ev){ return ev->ops == &synth_event_ops;} static struct synth_event *to_synth_event(struct dyn_event *ev){ return container_of(ev, struct synth_event, devent);} static bool synth_event_is_busy(struct dyn_event *ev){ struct synth_event *event = to_synth_event(ev); return event->ref != 0;} static bool synth_event_match(const char *system, const char *event, struct dyn_event *ev){ struct synth_event *sev = to_synth_event(ev); return strcmp(sev->name, event) == 0 && (!system || strcmp(system, SYNTH_SYSTEM) == 0);} struct action_data; typedef void (*action_fn_t) (struct hist_trigger_data *hist_data, struct tracing_map_elt *elt, void *rec, struct ring_buffer_event *rbe, struct action_data *data, u64 *var_ref_vals); struct action_data { action_fn_t fn; unsigned int n_params; char *params[SYNTH_FIELDS_MAX]; union { struct { /* * When a histogram trigger is hit, the values of any * references to variables, including variables being passed * as parameters to synthetic events, are collected into a * var_ref_vals array. This var_ref_idx is the index of the * first param in the array to be passed to the synthetic * event invocation. */ unsigned int var_ref_idx; char *match_event; char *match_event_system; char *synth_event_name; struct synth_event *synth_event; } onmatch; struct { char *var_str; char *fn_name; unsigned int max_var_ref_idx; struct hist_field *max_var; struct hist_field *var; } onmax; };}; static char last_hist_cmd[MAX_FILTER_STR_VAL];static char hist_err_str[MAX_FILTER_STR_VAL]; static void last_cmd_set(char *str){ if (!str) return; strncpy(last_hist_cmd, str, MAX_FILTER_STR_VAL - 1);} static void hist_err(char *str, char *var){ int maxlen = MAX_FILTER_STR_VAL - 1; if (!str) return; if (strlen(hist_err_str)) return; if (!var) var = ""; if (strlen(hist_err_str) + strlen(str) + strlen(var) > maxlen) return; strcat(hist_err_str, str); strcat(hist_err_str, var);} static void hist_err_event(char *str, char *system, char *event, char *var){ char err[MAX_FILTER_STR_VAL]; if (system && var) snprintf(err, MAX_FILTER_STR_VAL, "%s.%s.%s", system, event, var); else if (system) snprintf(err, MAX_FILTER_STR_VAL, "%s.%s", system, event); else strscpy(err, var, MAX_FILTER_STR_VAL); hist_err(str, err);} static void hist_err_clear(void){ hist_err_str[0] = '\0';} static bool have_hist_err(void){ if (strlen(hist_err_str)) return true; return false;} struct synth_trace_event { struct trace_entry ent; u64 fields[];}; static int synth_event_define_fields(struct trace_event_call *call){ struct synth_trace_event trace; int offset = offsetof(typeof(trace), fields); struct synth_event *event = call->data; unsigned int i, size, n_u64; char *name, *type; bool is_signed; int ret = 0; for (i = 0, n_u64 = 0; i < event->n_fields; i++) { size = event->fields[i]->size; is_signed = event->fields[i]->is_signed; type = event->fields[i]->type; name = event->fields[i]->name; ret = trace_define_field(call, type, name, offset, size,Lines 1–500 of 5910. Load more
// SPDX-License-Identifier: GPL-2.0 /* * trace_events_hist - trace event hist triggers * * Copyright (C) 2015 Tom Zanussi <tom.zanussi@linux.intel.com> */ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/stacktrace.h> #include <linux/rculist.h> #include <linux/tracefs.h> #include "tracing_map.h" #include "trace.h" #include "trace_dynevent.h" #define SYNTH_SYSTEM "synthetic" #define SYNTH_FIELDS_MAX 16 #define STR_VAR_LEN_MAX 32 /* must be multiple of sizeof(u64) */ struct hist_field; typedef u64 (*hist_field_fn_t) (struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event); #define HIST_FIELD_OPERANDS_MAX 2 #define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX) #define HIST_ACTIONS_MAX 8 enum field_op_id { FIELD_OP_NONE, FIELD_OP_PLUS, FIELD_OP_MINUS, FIELD_OP_UNARY_MINUS, }; /* * A hist_var (histogram variable) contains variable information for * hist_fields having the HIST_FIELD_FL_VAR or HIST_FIELD_FL_VAR_REF * flag set. A hist_var has a variable name e.g. ts0, and is * associated with a given histogram trigger, as specified by * hist_data. The hist_var idx is the unique index assigned to the * variable by the hist trigger's tracing_map. The idx is what is * used to set a variable's value and, by a variable reference, to * retrieve it. */ struct hist_var { char *name; struct hist_trigger_data *hist_data; unsigned int idx; }; struct hist_field { struct ftrace_event_field *field; unsigned long flags; hist_field_fn_t fn; unsigned int size; unsigned int offset; unsigned int is_signed; const char *type; struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; struct hist_trigger_data *hist_data; /* * Variable fields contain variable-specific info in var. */ struct hist_var var; enum field_op_id operator; char *system; char *event_name; /* * The name field is used for EXPR and VAR_REF fields. VAR * fields contain the variable name in var.name. */ char *name; /* * When a histogram trigger is hit, if it has any references * to variables, the values of those variables are collected * into a var_ref_vals array by resolve_var_refs(). The * current value of each variable is read from the tracing_map * using the hist field's hist_var.idx and entered into the * var_ref_idx entry i.e. var_ref_vals[var_ref_idx]. */ unsigned int var_ref_idx; bool read_once; }; static u64 hist_field_none(struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { return 0; } static u64 hist_field_counter(struct hist_field *field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { return 1; } static u64 hist_field_string(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { char *addr = (char *)(event + hist_field->field->offset); return (u64)(unsigned long)addr; } static u64 hist_field_dynstring(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { u32 str_item = *(u32 *)(event + hist_field->field->offset); int str_loc = str_item & 0xffff; char *addr = (char *)(event + str_loc); return (u64)(unsigned long)addr; } static u64 hist_field_pstring(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { char **addr = (char **)(event + hist_field->field->offset); return (u64)(unsigned long)*addr; } static u64 hist_field_log2(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { struct hist_field *operand = hist_field->operands[0]; u64 val = operand->fn(operand, elt, rbe, event); return (u64) ilog2(roundup_pow_of_two(val)); } static u64 hist_field_plus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { struct hist_field *operand1 = hist_field->operands[0]; struct hist_field *operand2 = hist_field->operands[1]; u64 val1 = operand1->fn(operand1, elt, rbe, event); u64 val2 = operand2->fn(operand2, elt, rbe, event); return val1 + val2; } static u64 hist_field_minus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { struct hist_field *operand1 = hist_field->operands[0]; struct hist_field *operand2 = hist_field->operands[1]; u64 val1 = operand1->fn(operand1, elt, rbe, event); u64 val2 = operand2->fn(operand2, elt, rbe, event); return val1 - val2; } static u64 hist_field_unary_minus(struct hist_field *hist_field, struct tracing_map_elt *elt, struct ring_buffer_event *rbe, void *event) { struct hist_field *operand = hist_field->operands[0]; s64 sval = (s64)operand->fn(operand, elt, rbe, event); u64 val = (u64)-sval; return val; } #define DEFINE_HIST_FIELD_FN(type) \ static u64 hist_field_##type(struct hist_field *hist_field, \ struct tracing_map_elt *elt, \ struct ring_buffer_event *rbe, \ void *event) \ { \ type *addr = (type *)(event + hist_field->field->offset); \ \ return (u64)(unsigned long)*addr; \ } DEFINE_HIST_FIELD_FN(s64); DEFINE_HIST_FIELD_FN(u64); DEFINE_HIST_FIELD_FN(s32); DEFINE_HIST_FIELD_FN(u32); DEFINE_HIST_FIELD_FN(s16); DEFINE_HIST_FIELD_FN(u16); DEFINE_HIST_FIELD_FN(s8); DEFINE_HIST_FIELD_FN(u8); #define for_each_hist_field(i, hist_data) \ for ((i) = 0; (i) < (hist_data)->n_fields; (i)++) #define for_each_hist_val_field(i, hist_data) \ for ((i) = 0; (i) < (hist_data)->n_vals; (i)++) #define for_each_hist_key_field(i, hist_data) \ for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) #define HIST_STACKTRACE_DEPTH 16 #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) #define HIST_STACKTRACE_SKIP 5 #define HITCOUNT_IDX 0 #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) enum hist_field_flags { HIST_FIELD_FL_HITCOUNT = 1 << 0, HIST_FIELD_FL_KEY = 1 << 1, HIST_FIELD_FL_STRING = 1 << 2, HIST_FIELD_FL_HEX = 1 << 3, HIST_FIELD_FL_SYM = 1 << 4, HIST_FIELD_FL_SYM_OFFSET = 1 << 5, HIST_FIELD_FL_EXECNAME = 1 << 6, HIST_FIELD_FL_SYSCALL = 1 << 7, HIST_FIELD_FL_STACKTRACE = 1 << 8, HIST_FIELD_FL_LOG2 = 1 << 9, HIST_FIELD_FL_TIMESTAMP = 1 << 10, HIST_FIELD_FL_TIMESTAMP_USECS = 1 << 11, HIST_FIELD_FL_VAR = 1 << 12, HIST_FIELD_FL_EXPR = 1 << 13, HIST_FIELD_FL_VAR_REF = 1 << 14, HIST_FIELD_FL_CPU = 1 << 15, HIST_FIELD_FL_ALIAS = 1 << 16, }; struct var_defs { unsigned int n_vars; char *name[TRACING_MAP_VARS_MAX]; char *expr[TRACING_MAP_VARS_MAX]; }; struct hist_trigger_attrs { char *keys_str; char *vals_str; char *sort_key_str; char *name; char *clock; bool pause; bool cont; bool clear; bool ts_in_usecs; unsigned int map_bits; char *assignment_str[TRACING_MAP_VARS_MAX]; unsigned int n_assignments; char *action_str[HIST_ACTIONS_MAX]; unsigned int n_actions; struct var_defs var_defs; }; struct field_var { struct hist_field *var; struct hist_field *val; }; struct field_var_hist { struct hist_trigger_data *hist_data; char *cmd; }; struct hist_trigger_data { struct hist_field *fields[HIST_FIELDS_MAX]; unsigned int n_vals; unsigned int n_keys; unsigned int n_fields; unsigned int n_vars; unsigned int key_size; struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX]; unsigned int n_sort_keys; struct trace_event_file *event_file; struct hist_trigger_attrs *attrs; struct tracing_map *map; bool enable_timestamps; bool remove; struct hist_field *var_refs[TRACING_MAP_VARS_MAX]; unsigned int n_var_refs; struct action_data *actions[HIST_ACTIONS_MAX]; unsigned int n_actions; struct field_var *field_vars[SYNTH_FIELDS_MAX]; unsigned int n_field_vars; unsigned int n_field_var_str; struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX]; unsigned int n_field_var_hists; struct field_var *max_vars[SYNTH_FIELDS_MAX]; unsigned int n_max_vars; unsigned int n_max_var_str; }; static int synth_event_create(int argc, const char **argv); 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, struct dyn_event *ev); static struct dyn_event_operations synth_event_ops = { .create = synth_event_create, .show = synth_event_show, .is_busy = synth_event_is_busy, .free = synth_event_release, .match = synth_event_match, }; struct synth_field { char *type; char *name; size_t size; bool is_signed; bool is_string; }; struct synth_event { struct dyn_event devent; int ref; char *name; struct synth_field **fields; unsigned int n_fields; unsigned int n_u64; struct trace_event_class class; struct trace_event_call call; struct tracepoint *tp; }; static bool is_synth_event(struct dyn_event *ev) { return ev->ops == &synth_event_ops; } static struct synth_event *to_synth_event(struct dyn_event *ev) { return container_of(ev, struct synth_event, devent); } static bool synth_event_is_busy(struct dyn_event *ev) { struct synth_event *event = to_synth_event(ev); return event->ref != 0; } static bool synth_event_match(const char *system, const char *event, struct dyn_event *ev) { struct synth_event *sev = to_synth_event(ev); return strcmp(sev->name, event) == 0 && (!system || strcmp(system, SYNTH_SYSTEM) == 0); } struct action_data; typedef void (*action_fn_t) (struct hist_trigger_data *hist_data, struct tracing_map_elt *elt, void *rec, struct ring_buffer_event *rbe, struct action_data *data, u64 *var_ref_vals); struct action_data { action_fn_t fn; unsigned int n_params; char *params[SYNTH_FIELDS_MAX]; union { struct { /* * When a histogram trigger is hit, the values of any * references to variables, including variables being passed * as parameters to synthetic events, are collected into a * var_ref_vals array. This var_ref_idx is the index of the * first param in the array to be passed to the synthetic * event invocation. */ unsigned int var_ref_idx; char *match_event; char *match_event_system; char *synth_event_name; struct synth_event *synth_event; } onmatch; struct { char *var_str; char *fn_name; unsigned int max_var_ref_idx; struct hist_field *max_var; struct hist_field *var; } onmax; }; }; static char last_hist_cmd[MAX_FILTER_STR_VAL]; static char hist_err_str[MAX_FILTER_STR_VAL]; static void last_cmd_set(char *str) { if (!str) return; strncpy(last_hist_cmd, str, MAX_FILTER_STR_VAL - 1); } static void hist_err(char *str, char *var) { int maxlen = MAX_FILTER_STR_VAL - 1; if (!str) return; if (strlen(hist_err_str)) return; if (!var) var = ""; if (strlen(hist_err_str) + strlen(str) + strlen(var) > maxlen) return; strcat(hist_err_str, str); strcat(hist_err_str, var); } static void hist_err_event(char *str, char *system, char *event, char *var) { char err[MAX_FILTER_STR_VAL]; if (system && var) snprintf(err, MAX_FILTER_STR_VAL, "%s.%s.%s", system, event, var); else if (system) snprintf(err, MAX_FILTER_STR_VAL, "%s.%s", system, event); else strscpy(err, var, MAX_FILTER_STR_VAL); hist_err(str, err); } static void hist_err_clear(void) { hist_err_str[0] = '\0'; } static bool have_hist_err(void) { if (strlen(hist_err_str)) return true; return false; } struct synth_trace_event { struct trace_entry ent; u64 fields[]; }; static int synth_event_define_fields(struct trace_event_call *call) { struct synth_trace_event trace; int offset = offsetof(typeof(trace), fields); struct synth_event *event = call->data; unsigned int i, size, n_u64; char *name, *type; bool is_signed; int ret = 0; for (i = 0, n_u64 = 0; i < event->n_fields; i++) { size = event->fields[i]->size; is_signed = event->fields[i]->is_signed; type = event->fields[i]->type; name = event->fields[i]->name; ret = trace_define_field(call, type, name, offset, size,