mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
tracing updates for v6.15:
- Add option traceoff_after_boot In order to debug kernel boot, it sometimes is helpful to enable tracing via the kernel command line. Unfortunately, by the time the login prompt appears, the trace is overwritten by the init process and other user space start up applications. Adding a "traceoff_after_boot" will disable tracing when the kernel passes control to init which will allow developers to be able to see the traces that occurred during boot. - Clean up the mmflags macros that display the GFP flags in trace events The macros to print the GFP flags for trace events had a bit of duplication. The code was restructured to remove duplication and in the process it also adds some flags that were missed before. - Removed some dead code and scripts/draw_functrace.py draw_functrace.py hasn't worked in years and as nobody complained about it, remove it. - Constify struct event_trigger_ops The event_trigger_ops is just a structure that has function pointers that are assigned when the variables are created. These variables should all be constants. - Other minor clean ups and fixes -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCZ+V9IhQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qr4RAP9JhE3n69pGuOVaJTN/LGLr2Axl59n4 KqZSZS1nUM76/gD6AxYpR7nxyxgJ7VjNkLptS9tSjJVdPDxGAl0v3eO04w4= =SU30 -----END PGP SIGNATURE----- Merge tag 'trace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace Pull tracing updates from Steven Rostedt: - Add option traceoff_after_boot In order to debug kernel boot, it sometimes is helpful to enable tracing via the kernel command line. Unfortunately, by the time the login prompt appears, the trace is overwritten by the init process and other user space start up applications. Adding a "traceoff_after_boot" will disable tracing when the kernel passes control to init which will allow developers to be able to see the traces that occurred during boot. - Clean up the mmflags macros that display the GFP flags in trace events The macros to print the GFP flags for trace events had a bit of duplication. The code was restructured to remove duplication and in the process it also adds some flags that were missed before. - Removed some dead code and scripts/draw_functrace.py draw_functrace.py hasn't worked in years and as nobody complained about it, remove it. - Constify struct event_trigger_ops The event_trigger_ops is just a structure that has function pointers that are assigned when the variables are created. These variables should all be constants. - Other minor clean ups and fixes * tag 'trace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: tracing: Replace strncpy with memcpy for fixed-length substring copy tracing: Fix synth event printk format for str fields tracing: Do not use PERF enums when perf is not defined tracing: Ensure module defining synth event cannot be unloaded while tracing tracing: fix return value in __ftrace_event_enable_disable for TRACE_REG_UNREGISTER tracing/osnoise: Fix possible recursive locking for cpus_read_lock() tracing: Align synth event print fmt tracing: gfp: vsprintf: Do not print "none" when using %pGg printf format tracepoint: Print the function symbol when tracepoint_debug is set tracing: Constify struct event_trigger_ops scripts/tracing: Remove scripts/tracing/draw_functrace.py tracing: Update MAINTAINERS file to include tracepoint.c tracing/user_events: Slightly simplify user_seq_show() tracing/user_events: Don't use %pK through printk tracing: gfp: Remove duplication of recording GFP flags tracing: Remove orphaned event_trace_printk ring-buffer: Fix typo in comment about header page pointer tracing: Add traceoff_after_boot option
This commit is contained in:
commit
744fab2d9f
@ -7289,6 +7289,15 @@
|
||||
See also "Event triggers" in Documentation/trace/events.rst
|
||||
|
||||
|
||||
traceoff_after_boot
|
||||
[FTRACE] Sometimes tracing is used to debug issues
|
||||
during the boot process. Since the trace buffer has a
|
||||
limited amount of storage, it may be prudent to
|
||||
disable tracing after the boot is finished, otherwise
|
||||
the critical information may be overwritten. With this
|
||||
option, the main tracing buffer will be turned off at
|
||||
the end of the boot process.
|
||||
|
||||
traceoff_on_warning
|
||||
[FTRACE] enable this option to disable tracing when a
|
||||
warning is hit. This turns off "tracing_on". Tracing can
|
||||
|
@ -24233,6 +24233,7 @@ F: fs/tracefs/
|
||||
F: include/linux/trace*.h
|
||||
F: include/trace/
|
||||
F: kernel/trace/
|
||||
F: kernel/tracepoint.c
|
||||
F: scripts/tracing/
|
||||
F: tools/testing/selftests/ftrace/
|
||||
|
||||
|
@ -859,24 +859,6 @@ int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set);
|
||||
int trace_set_clr_event(const char *system, const char *event, int set);
|
||||
int trace_array_set_clr_event(struct trace_array *tr, const char *system,
|
||||
const char *event, bool enable);
|
||||
/*
|
||||
* The double __builtin_constant_p is because gcc will give us an error
|
||||
* if we try to allocate the static variable to fmt if it is not a
|
||||
* constant. Even with the outer if statement optimizing out.
|
||||
*/
|
||||
#define event_trace_printk(ip, fmt, args...) \
|
||||
do { \
|
||||
__trace_printk_check_format(fmt, ##args); \
|
||||
tracing_record_cmdline(current); \
|
||||
if (__builtin_constant_p(fmt)) { \
|
||||
static const char *trace_printk_fmt \
|
||||
__section("__trace_printk_fmt") = \
|
||||
__builtin_constant_p(fmt) ? fmt : NULL; \
|
||||
\
|
||||
__trace_bprintk(ip, trace_printk_fmt, ##args); \
|
||||
} else \
|
||||
__trace_printk(ip, fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
struct perf_event;
|
||||
|
@ -78,6 +78,13 @@ TRACE_DEFINE_ENUM(___GFP_LAST_BIT);
|
||||
|
||||
#define gfpflag_string(flag) {(__force unsigned long)flag, #flag}
|
||||
|
||||
/*
|
||||
* For the values that match the bits, use the TRACE_GFP_FLAGS
|
||||
* which will allow any updates to be included automatically.
|
||||
*/
|
||||
#undef TRACE_GFP_EM
|
||||
#define TRACE_GFP_EM(a) gfpflag_string(__GFP_##a),
|
||||
|
||||
#define __def_gfpflag_names \
|
||||
gfpflag_string(GFP_TRANSHUGE), \
|
||||
gfpflag_string(GFP_TRANSHUGE_LIGHT), \
|
||||
@ -91,41 +98,13 @@ TRACE_DEFINE_ENUM(___GFP_LAST_BIT);
|
||||
gfpflag_string(GFP_NOIO), \
|
||||
gfpflag_string(GFP_NOWAIT), \
|
||||
gfpflag_string(GFP_DMA), \
|
||||
gfpflag_string(__GFP_HIGHMEM), \
|
||||
gfpflag_string(GFP_DMA32), \
|
||||
gfpflag_string(__GFP_HIGH), \
|
||||
gfpflag_string(__GFP_IO), \
|
||||
gfpflag_string(__GFP_FS), \
|
||||
gfpflag_string(__GFP_NOWARN), \
|
||||
gfpflag_string(__GFP_RETRY_MAYFAIL), \
|
||||
gfpflag_string(__GFP_NOFAIL), \
|
||||
gfpflag_string(__GFP_NORETRY), \
|
||||
gfpflag_string(__GFP_COMP), \
|
||||
gfpflag_string(__GFP_ZERO), \
|
||||
gfpflag_string(__GFP_NOMEMALLOC), \
|
||||
gfpflag_string(__GFP_MEMALLOC), \
|
||||
gfpflag_string(__GFP_HARDWALL), \
|
||||
gfpflag_string(__GFP_THISNODE), \
|
||||
gfpflag_string(__GFP_RECLAIMABLE), \
|
||||
gfpflag_string(__GFP_MOVABLE), \
|
||||
gfpflag_string(__GFP_ACCOUNT), \
|
||||
gfpflag_string(__GFP_WRITE), \
|
||||
gfpflag_string(__GFP_RECLAIM), \
|
||||
gfpflag_string(__GFP_DIRECT_RECLAIM), \
|
||||
gfpflag_string(__GFP_KSWAPD_RECLAIM), \
|
||||
gfpflag_string(__GFP_ZEROTAGS)
|
||||
|
||||
#ifdef CONFIG_KASAN_HW_TAGS
|
||||
#define __def_gfpflag_names_kasan , \
|
||||
gfpflag_string(__GFP_SKIP_ZERO), \
|
||||
gfpflag_string(__GFP_SKIP_KASAN)
|
||||
#else
|
||||
#define __def_gfpflag_names_kasan
|
||||
#endif
|
||||
TRACE_GFP_FLAGS \
|
||||
{ 0, NULL }
|
||||
|
||||
#define show_gfp_flags(flags) \
|
||||
(flags) ? __print_flags(flags, "|", \
|
||||
__def_gfpflag_names __def_gfpflag_names_kasan \
|
||||
(flags) ? __print_flags(flags, "|", __def_gfpflag_names \
|
||||
) : "none"
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
@ -5318,7 +5318,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
|
||||
* moving it. The page before the header page has the
|
||||
* flag bit '1' set if it is pointing to the page we want.
|
||||
* but if the writer is in the process of moving it
|
||||
* than it will be '2' or already moved '0'.
|
||||
* then it will be '2' or already moved '0'.
|
||||
*/
|
||||
|
||||
ret = rb_head_page_replace(reader, cpu_buffer->reader_page);
|
||||
|
@ -87,6 +87,7 @@ void __init disable_tracing_selftest(const char *reason)
|
||||
static struct trace_iterator *tracepoint_print_iter;
|
||||
int tracepoint_printk;
|
||||
static bool tracepoint_printk_stop_on_boot __initdata;
|
||||
static bool traceoff_after_boot __initdata;
|
||||
static DEFINE_STATIC_KEY_FALSE(tracepoint_printk_key);
|
||||
|
||||
/* For tracers that don't implement custom flags */
|
||||
@ -330,6 +331,13 @@ static int __init set_tracepoint_printk_stop(char *str)
|
||||
}
|
||||
__setup("tp_printk_stop_on_boot", set_tracepoint_printk_stop);
|
||||
|
||||
static int __init set_traceoff_after_boot(char *str)
|
||||
{
|
||||
traceoff_after_boot = true;
|
||||
return 1;
|
||||
}
|
||||
__setup("traceoff_after_boot", set_traceoff_after_boot);
|
||||
|
||||
unsigned long long ns2usecs(u64 nsec)
|
||||
{
|
||||
nsec += 500;
|
||||
@ -10709,6 +10717,9 @@ __init static int late_trace_init(void)
|
||||
tracepoint_printk = 0;
|
||||
}
|
||||
|
||||
if (traceoff_after_boot)
|
||||
tracing_off();
|
||||
|
||||
tracing_set_default_clock();
|
||||
clear_boot_tracer();
|
||||
return 0;
|
||||
|
@ -1717,7 +1717,7 @@ struct event_trigger_data {
|
||||
unsigned long count;
|
||||
int ref;
|
||||
int flags;
|
||||
struct event_trigger_ops *ops;
|
||||
const struct event_trigger_ops *ops;
|
||||
struct event_command *cmd_ops;
|
||||
struct event_filter __rcu *filter;
|
||||
char *filter_str;
|
||||
@ -1962,7 +1962,7 @@ struct event_command {
|
||||
int (*set_filter)(char *filter_str,
|
||||
struct event_trigger_data *data,
|
||||
struct trace_event_file *file);
|
||||
struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param);
|
||||
const struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -478,7 +478,7 @@ static void eprobe_trigger_func(struct event_trigger_data *data,
|
||||
__eprobe_trace_func(edata, rec);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops eprobe_trigger_ops = {
|
||||
static const struct event_trigger_ops eprobe_trigger_ops = {
|
||||
.trigger = eprobe_trigger_func,
|
||||
.print = eprobe_trigger_print,
|
||||
.init = eprobe_trigger_init,
|
||||
@ -507,8 +507,8 @@ static void eprobe_trigger_unreg_func(char *glob,
|
||||
|
||||
}
|
||||
|
||||
static struct event_trigger_ops *eprobe_trigger_get_ops(char *cmd,
|
||||
char *param)
|
||||
static const struct event_trigger_ops *eprobe_trigger_get_ops(char *cmd,
|
||||
char *param)
|
||||
{
|
||||
return &eprobe_trigger_ops;
|
||||
}
|
||||
|
@ -790,7 +790,9 @@ static int __ftrace_event_enable_disable(struct trace_event_file *file,
|
||||
clear_bit(EVENT_FILE_FL_RECORDED_TGID_BIT, &file->flags);
|
||||
}
|
||||
|
||||
call->class->reg(call, TRACE_REG_UNREGISTER, file);
|
||||
ret = call->class->reg(call, TRACE_REG_UNREGISTER, file);
|
||||
|
||||
WARN_ON_ONCE(ret);
|
||||
}
|
||||
/* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */
|
||||
if (file->flags & EVENT_FILE_FL_SOFT_MODE)
|
||||
|
@ -6203,7 +6203,7 @@ static void event_hist_trigger_free(struct event_trigger_data *data)
|
||||
}
|
||||
}
|
||||
|
||||
static struct event_trigger_ops event_hist_trigger_ops = {
|
||||
static const struct event_trigger_ops event_hist_trigger_ops = {
|
||||
.trigger = event_hist_trigger,
|
||||
.print = event_hist_trigger_print,
|
||||
.init = event_hist_trigger_init,
|
||||
@ -6235,15 +6235,15 @@ static void event_hist_trigger_named_free(struct event_trigger_data *data)
|
||||
}
|
||||
}
|
||||
|
||||
static struct event_trigger_ops event_hist_trigger_named_ops = {
|
||||
static const struct event_trigger_ops event_hist_trigger_named_ops = {
|
||||
.trigger = event_hist_trigger,
|
||||
.print = event_hist_trigger_print,
|
||||
.init = event_hist_trigger_named_init,
|
||||
.free = event_hist_trigger_named_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
|
||||
char *param)
|
||||
static const struct event_trigger_ops *event_hist_get_trigger_ops(char *cmd,
|
||||
char *param)
|
||||
{
|
||||
return &event_hist_trigger_ops;
|
||||
}
|
||||
@ -6838,38 +6838,38 @@ hist_enable_count_trigger(struct event_trigger_data *data,
|
||||
hist_enable_trigger(data, buffer, rec, event);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops hist_enable_trigger_ops = {
|
||||
static const struct event_trigger_ops hist_enable_trigger_ops = {
|
||||
.trigger = hist_enable_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops hist_enable_count_trigger_ops = {
|
||||
static const struct event_trigger_ops hist_enable_count_trigger_ops = {
|
||||
.trigger = hist_enable_count_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops hist_disable_trigger_ops = {
|
||||
static const struct event_trigger_ops hist_disable_trigger_ops = {
|
||||
.trigger = hist_enable_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops hist_disable_count_trigger_ops = {
|
||||
static const struct event_trigger_ops hist_disable_count_trigger_ops = {
|
||||
.trigger = hist_enable_count_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops *
|
||||
static const struct event_trigger_ops *
|
||||
hist_enable_get_trigger_ops(char *cmd, char *param)
|
||||
{
|
||||
struct event_trigger_ops *ops;
|
||||
const struct event_trigger_ops *ops;
|
||||
bool enable;
|
||||
|
||||
enable = (strcmp(cmd, ENABLE_HIST_STR) == 0);
|
||||
|
@ -207,7 +207,7 @@ static int synth_field_string_size(char *type)
|
||||
if (len == 0)
|
||||
return 0; /* variable-length string */
|
||||
|
||||
strncpy(buf, start, len);
|
||||
memcpy(buf, start, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
err = kstrtouint(buf, 0, &size);
|
||||
@ -305,7 +305,7 @@ static const char *synth_field_fmt(char *type)
|
||||
else if (strcmp(type, "gfp_t") == 0)
|
||||
fmt = "%x";
|
||||
else if (synth_field_is_string(type))
|
||||
fmt = "%.*s";
|
||||
fmt = "%s";
|
||||
else if (synth_field_is_stack(type))
|
||||
fmt = "%s";
|
||||
|
||||
@ -612,7 +612,7 @@ static int __set_synth_event_print_fmt(struct synth_event *event,
|
||||
fmt = synth_field_fmt(event->fields[i]->type);
|
||||
pos += snprintf(buf + pos, LEN_OR_ZERO, "%s=%s%s",
|
||||
event->fields[i]->name, fmt,
|
||||
i == event->n_fields - 1 ? "" : ", ");
|
||||
i == event->n_fields - 1 ? "" : " ");
|
||||
}
|
||||
pos += snprintf(buf + pos, LEN_OR_ZERO, "\"");
|
||||
|
||||
@ -852,6 +852,38 @@ static struct trace_event_fields synth_event_fields_array[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static int synth_event_reg(struct trace_event_call *call,
|
||||
enum trace_reg type, void *data)
|
||||
{
|
||||
struct synth_event *event = container_of(call, struct synth_event, call);
|
||||
|
||||
switch (type) {
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
case TRACE_REG_PERF_REGISTER:
|
||||
#endif
|
||||
case TRACE_REG_REGISTER:
|
||||
if (!try_module_get(event->mod))
|
||||
return -EBUSY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = trace_event_reg(call, type, data);
|
||||
|
||||
switch (type) {
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
case TRACE_REG_PERF_UNREGISTER:
|
||||
#endif
|
||||
case TRACE_REG_UNREGISTER:
|
||||
module_put(event->mod);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int register_synth_event(struct synth_event *event)
|
||||
{
|
||||
struct trace_event_call *call = &event->call;
|
||||
@ -881,7 +913,7 @@ static int register_synth_event(struct synth_event *event)
|
||||
goto out;
|
||||
}
|
||||
call->flags = TRACE_EVENT_FL_TRACEPOINT;
|
||||
call->class->reg = trace_event_reg;
|
||||
call->class->reg = synth_event_reg;
|
||||
call->class->probe = trace_event_raw_event_synth;
|
||||
call->data = event;
|
||||
call->tp = event->tp;
|
||||
|
@ -825,7 +825,7 @@ struct event_trigger_data *event_trigger_alloc(struct event_command *cmd_ops,
|
||||
void *private_data)
|
||||
{
|
||||
struct event_trigger_data *trigger_data;
|
||||
struct event_trigger_ops *trigger_ops;
|
||||
const struct event_trigger_ops *trigger_ops;
|
||||
|
||||
trigger_ops = cmd_ops->get_trigger_ops(cmd, param);
|
||||
|
||||
@ -1367,38 +1367,38 @@ traceoff_trigger_print(struct seq_file *m, struct event_trigger_data *data)
|
||||
data->filter_str);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops traceon_trigger_ops = {
|
||||
static const struct event_trigger_ops traceon_trigger_ops = {
|
||||
.trigger = traceon_trigger,
|
||||
.print = traceon_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops traceon_count_trigger_ops = {
|
||||
static const struct event_trigger_ops traceon_count_trigger_ops = {
|
||||
.trigger = traceon_count_trigger,
|
||||
.print = traceon_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops traceoff_trigger_ops = {
|
||||
static const struct event_trigger_ops traceoff_trigger_ops = {
|
||||
.trigger = traceoff_trigger,
|
||||
.print = traceoff_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops traceoff_count_trigger_ops = {
|
||||
static const struct event_trigger_ops traceoff_count_trigger_ops = {
|
||||
.trigger = traceoff_count_trigger,
|
||||
.print = traceoff_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops *
|
||||
static const struct event_trigger_ops *
|
||||
onoff_get_trigger_ops(char *cmd, char *param)
|
||||
{
|
||||
struct event_trigger_ops *ops;
|
||||
const struct event_trigger_ops *ops;
|
||||
|
||||
/* we register both traceon and traceoff to this callback */
|
||||
if (strcmp(cmd, "traceon") == 0)
|
||||
@ -1491,21 +1491,21 @@ snapshot_trigger_print(struct seq_file *m, struct event_trigger_data *data)
|
||||
data->filter_str);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops snapshot_trigger_ops = {
|
||||
static const struct event_trigger_ops snapshot_trigger_ops = {
|
||||
.trigger = snapshot_trigger,
|
||||
.print = snapshot_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops snapshot_count_trigger_ops = {
|
||||
static const struct event_trigger_ops snapshot_count_trigger_ops = {
|
||||
.trigger = snapshot_count_trigger,
|
||||
.print = snapshot_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops *
|
||||
static const struct event_trigger_ops *
|
||||
snapshot_get_trigger_ops(char *cmd, char *param)
|
||||
{
|
||||
return param ? &snapshot_count_trigger_ops : &snapshot_trigger_ops;
|
||||
@ -1586,21 +1586,21 @@ stacktrace_trigger_print(struct seq_file *m, struct event_trigger_data *data)
|
||||
data->filter_str);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops stacktrace_trigger_ops = {
|
||||
static const struct event_trigger_ops stacktrace_trigger_ops = {
|
||||
.trigger = stacktrace_trigger,
|
||||
.print = stacktrace_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops stacktrace_count_trigger_ops = {
|
||||
static const struct event_trigger_ops stacktrace_count_trigger_ops = {
|
||||
.trigger = stacktrace_count_trigger,
|
||||
.print = stacktrace_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops *
|
||||
static const struct event_trigger_ops *
|
||||
stacktrace_get_trigger_ops(char *cmd, char *param)
|
||||
{
|
||||
return param ? &stacktrace_count_trigger_ops : &stacktrace_trigger_ops;
|
||||
@ -1711,28 +1711,28 @@ void event_enable_trigger_free(struct event_trigger_data *data)
|
||||
}
|
||||
}
|
||||
|
||||
static struct event_trigger_ops event_enable_trigger_ops = {
|
||||
static const struct event_trigger_ops event_enable_trigger_ops = {
|
||||
.trigger = event_enable_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops event_enable_count_trigger_ops = {
|
||||
static const struct event_trigger_ops event_enable_count_trigger_ops = {
|
||||
.trigger = event_enable_count_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops event_disable_trigger_ops = {
|
||||
static const struct event_trigger_ops event_disable_trigger_ops = {
|
||||
.trigger = event_enable_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
.free = event_enable_trigger_free,
|
||||
};
|
||||
|
||||
static struct event_trigger_ops event_disable_count_trigger_ops = {
|
||||
static const struct event_trigger_ops event_disable_count_trigger_ops = {
|
||||
.trigger = event_enable_count_trigger,
|
||||
.print = event_enable_trigger_print,
|
||||
.init = event_trigger_init,
|
||||
@ -1916,10 +1916,10 @@ void event_enable_unregister_trigger(char *glob,
|
||||
data->ops->free(data);
|
||||
}
|
||||
|
||||
static struct event_trigger_ops *
|
||||
static const struct event_trigger_ops *
|
||||
event_enable_get_trigger_ops(char *cmd, char *param)
|
||||
{
|
||||
struct event_trigger_ops *ops;
|
||||
const struct event_trigger_ops *ops;
|
||||
bool enable;
|
||||
|
||||
#ifdef CONFIG_HIST_TRIGGERS
|
||||
|
@ -455,7 +455,7 @@ static void user_event_enabler_fault_fixup(struct work_struct *work)
|
||||
if (ret && ret != -ENOENT) {
|
||||
struct user_event *user = enabler->event;
|
||||
|
||||
pr_warn("user_events: Fault for mm: 0x%pK @ 0x%llx event: %s\n",
|
||||
pr_warn("user_events: Fault for mm: 0x%p @ 0x%llx event: %s\n",
|
||||
mm->mm, (unsigned long long)uaddr, EVENT_NAME(user));
|
||||
}
|
||||
|
||||
@ -2793,11 +2793,8 @@ static int user_seq_show(struct seq_file *m, void *p)
|
||||
|
||||
seq_printf(m, "%s", EVENT_TP_NAME(user));
|
||||
|
||||
if (status != 0)
|
||||
seq_puts(m, " #");
|
||||
|
||||
if (status != 0) {
|
||||
seq_puts(m, " Used by");
|
||||
seq_puts(m, " # Used by");
|
||||
if (status & EVENT_STATUS_FTRACE)
|
||||
seq_puts(m, " ftrace");
|
||||
if (status & EVENT_STATUS_PERF)
|
||||
|
@ -2006,7 +2006,6 @@ static int start_kthread(unsigned int cpu)
|
||||
|
||||
if (IS_ERR(kthread)) {
|
||||
pr_err(BANNER "could not start sampling thread\n");
|
||||
stop_per_cpu_kthreads();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ static void debug_print_probes(struct tracepoint_func *funcs)
|
||||
return;
|
||||
|
||||
for (i = 0; funcs[i].func; i++)
|
||||
printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func);
|
||||
printk(KERN_DEBUG "Probe %d : %pSb\n", i, funcs[i].func);
|
||||
}
|
||||
|
||||
static struct tracepoint_func *
|
||||
|
@ -1,129 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
"""
|
||||
Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
|
||||
|
||||
This script parses a trace provided by the function tracer in
|
||||
kernel/trace/trace_functions.c
|
||||
The resulted trace is processed into a tree to produce a more human
|
||||
view of the call stack by drawing textual but hierarchical tree of
|
||||
calls. Only the functions's names and the call time are provided.
|
||||
|
||||
Usage:
|
||||
Be sure that you have CONFIG_FUNCTION_TRACER
|
||||
# mount -t tracefs nodev /sys/kernel/tracing
|
||||
# echo function > /sys/kernel/tracing/current_tracer
|
||||
$ cat /sys/kernel/tracing/trace_pipe > ~/raw_trace_func
|
||||
Wait some times but not too much, the script is a bit slow.
|
||||
Break the pipe (Ctrl + Z)
|
||||
$ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
|
||||
Then you have your drawn trace in draw_functrace
|
||||
"""
|
||||
|
||||
|
||||
import sys, re
|
||||
|
||||
class CallTree:
|
||||
""" This class provides a tree representation of the functions
|
||||
call stack. If a function has no parent in the kernel (interrupt,
|
||||
syscall, kernel thread...) then it is attached to a virtual parent
|
||||
called ROOT.
|
||||
"""
|
||||
ROOT = None
|
||||
|
||||
def __init__(self, func, time = None, parent = None):
|
||||
self._func = func
|
||||
self._time = time
|
||||
if parent is None:
|
||||
self._parent = CallTree.ROOT
|
||||
else:
|
||||
self._parent = parent
|
||||
self._children = []
|
||||
|
||||
def calls(self, func, calltime):
|
||||
""" If a function calls another one, call this method to insert it
|
||||
into the tree at the appropriate place.
|
||||
@return: A reference to the newly created child node.
|
||||
"""
|
||||
child = CallTree(func, calltime, self)
|
||||
self._children.append(child)
|
||||
return child
|
||||
|
||||
def getParent(self, func):
|
||||
""" Retrieve the last parent of the current node that
|
||||
has the name given by func. If this function is not
|
||||
on a parent, then create it as new child of root
|
||||
@return: A reference to the parent.
|
||||
"""
|
||||
tree = self
|
||||
while tree != CallTree.ROOT and tree._func != func:
|
||||
tree = tree._parent
|
||||
if tree == CallTree.ROOT:
|
||||
child = CallTree.ROOT.calls(func, None)
|
||||
return child
|
||||
return tree
|
||||
|
||||
def __repr__(self):
|
||||
return self.__toString("", True)
|
||||
|
||||
def __toString(self, branch, lastChild):
|
||||
if self._time is not None:
|
||||
s = "%s----%s (%s)\n" % (branch, self._func, self._time)
|
||||
else:
|
||||
s = "%s----%s\n" % (branch, self._func)
|
||||
|
||||
i = 0
|
||||
if lastChild:
|
||||
branch = branch[:-1] + " "
|
||||
while i < len(self._children):
|
||||
if i != len(self._children) - 1:
|
||||
s += "%s" % self._children[i].__toString(branch +\
|
||||
" |", False)
|
||||
else:
|
||||
s += "%s" % self._children[i].__toString(branch +\
|
||||
" |", True)
|
||||
i += 1
|
||||
return s
|
||||
|
||||
class BrokenLineException(Exception):
|
||||
"""If the last line is not complete because of the pipe breakage,
|
||||
we want to stop the processing and ignore this line.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CommentLineException(Exception):
|
||||
""" If the line is a comment (as in the beginning of the trace file),
|
||||
just ignore it.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def parseLine(line):
|
||||
line = line.strip()
|
||||
if line.startswith("#"):
|
||||
raise CommentLineException
|
||||
m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
|
||||
if m is None:
|
||||
raise BrokenLineException
|
||||
return (m.group(2), m.group(3), m.group(4))
|
||||
|
||||
|
||||
def main():
|
||||
CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
|
||||
tree = CallTree.ROOT
|
||||
|
||||
for line in sys.stdin:
|
||||
try:
|
||||
calltime, callee, caller = parseLine(line)
|
||||
except BrokenLineException:
|
||||
break
|
||||
except CommentLineException:
|
||||
continue
|
||||
tree = tree.getParent(caller)
|
||||
tree = tree.calls(callee, calltime)
|
||||
|
||||
print(CallTree.ROOT)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user