From: "Steven Rostedt (Red Hat)" <[email protected]>
Several tracepoints use the helper functions __print_symbolic() or
__print_flags() and pass in enums that do the mapping between the
binary data stored and the value to print. This works well for reading
the ASCII trace files, but when the data is read via userspace tools
such as perf and trace-cmd, the conversion of the binary value to a
human string format is lost if an enum is used, as userspace does not
have access to what the ENUM is.
For example, the tracepoint trace_tlb_flush() has:
__print_symbolic(REC->reason,
{ TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" },
{ TLB_REMOTE_SHOOTDOWN, "remote shootdown" },
{ TLB_LOCAL_SHOOTDOWN, "local shootdown" },
{ TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" })
Which maps the enum values to the strings they represent. But perf and
trace-cmd do no know what value TLB_LOCAL_MM_SHOOTDOWN is, and would
not be able to map it.
With TRACE_DEFINE_ENUM(), developers can place these in the event header
files and ftrace will convert the enums to their values:
By adding:
TRACE_DEFINE_ENUM(TLB_FLUSH_ON_TASK_SWITCH);
TRACE_DEFINE_ENUM(TLB_REMOTE_SHOOTDOWN);
TRACE_DEFINE_ENUM(TLB_LOCAL_SHOOTDOWN);
TRACE_DEFINE_ENUM(TLB_LOCAL_MM_SHOOTDOWN);
$ cat /sys/kernel/debug/tracing/events/tlb/tlb_flush/format
[...]
__print_symbolic(REC->reason,
{ 0, "flush on task switch" },
{ 1, "remote shootdown" },
{ 2, "local shootdown" },
{ 3, "local mm shootdown" })
The above is what userspace expects to see, and tools do not need to
be modified to parse them.
Cc: Guilherme Cox <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Xie XiuQi <[email protected]>
Signed-off-by: Steven Rostedt <[email protected]>
---
include/asm-generic/vmlinux.lds.h | 5 +-
include/linux/ftrace_event.h | 2 +-
include/linux/tracepoint.h | 8 +++
include/trace/ftrace.h | 22 ++++++-
kernel/trace/trace.c | 26 ++++++++-
kernel/trace/trace.h | 2 +
kernel/trace/trace_events.c | 119 ++++++++++++++++++++++++++++++++++++++
7 files changed, 178 insertions(+), 6 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ac78910d7416..f8e8b34dc427 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -124,7 +124,10 @@
#define FTRACE_EVENTS() . = ALIGN(8); \
VMLINUX_SYMBOL(__start_ftrace_events) = .; \
*(_ftrace_events) \
- VMLINUX_SYMBOL(__stop_ftrace_events) = .;
+ VMLINUX_SYMBOL(__stop_ftrace_events) = .; \
+ VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \
+ *(_ftrace_enum_map) \
+ VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
#else
#define FTRACE_EVENTS()
#endif
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 62b8fac7ded5..112cf49d9576 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -285,7 +285,7 @@ struct ftrace_event_call {
struct tracepoint *tp;
};
struct trace_event event;
- const char *print_fmt;
+ char *print_fmt;
struct event_filter *filter;
void *mod;
void *data;
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index c72851328ca9..a5f7f3ecafa3 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -36,6 +36,12 @@ struct tracepoint {
struct tracepoint_func __rcu *funcs;
};
+struct trace_enum_map {
+ const char *system;
+ const char *enum_string;
+ unsigned long enum_value;
+};
+
extern int
tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
extern int
@@ -87,6 +93,8 @@ extern void syscall_unregfunc(void);
#define PARAMS(args...) args
+#define TRACE_DEFINE_ENUM(x)
+
#endif /* _LINUX_TRACEPOINT_H */
/*
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 2f9b95b6d3fb..37d4b10b111d 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -33,6 +33,19 @@
TRACE_MAKE_SYSTEM_STR();
+#undef TRACE_DEFINE_ENUM
+#define TRACE_DEFINE_ENUM(a) \
+ static struct trace_enum_map __used __initdata \
+ __##TRACE_SYSTEM##_##a = \
+ { \
+ .system = TRACE_SYSTEM_STRING, \
+ .enum_string = #a, \
+ .enum_value = a \
+ }; \
+ static struct trace_enum_map __used \
+ __attribute__((section("_ftrace_enum_map"))) \
+ *TRACE_SYSTEM##_##a = &__##TRACE_SYSTEM##_##a
+
/*
* DECLARE_EVENT_CLASS can be used to add a generic function
* handlers for events. That is, if all events have the same
@@ -136,6 +149,9 @@ TRACE_MAKE_SYSTEM_STR();
* The size of an array is also encoded, in the higher 16 bits of <item>.
*/
+#undef TRACE_DEFINE_ENUM
+#define TRACE_DEFINE_ENUM(a)
+
#undef __field
#define __field(type, item)
@@ -553,7 +569,7 @@ static inline notrace int ftrace_get_offsets_##call( \
* .trace = ftrace_raw_output_<call>, <-- stage 2
* };
*
- * static const char print_fmt_<call>[] = <TP_printk>;
+ * static char print_fmt_<call>[] = <TP_printk>;
*
* static struct ftrace_event_class __used event_class_<template> = {
* .system = "<system>",
@@ -704,7 +720,7 @@ static inline void ftrace_test_probe_##call(void) \
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
_TRACE_PERF_PROTO(call, PARAMS(proto)); \
-static const char print_fmt_##call[] = print; \
+static char print_fmt_##call[] = print; \
static struct ftrace_event_class __used __refdata event_class_##call = { \
.system = TRACE_SYSTEM_STRING, \
.define_fields = ftrace_define_fields_##call, \
@@ -733,7 +749,7 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
#undef DEFINE_EVENT_PRINT
#define DEFINE_EVENT_PRINT(template, call, proto, args, print) \
\
-static const char print_fmt_##call[] = print; \
+static char print_fmt_##call[] = print; \
\
static struct ftrace_event_call __used event_##call = { \
.class = &event_class_##template, \
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 62c6506d663f..ebf49649534c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3908,6 +3908,20 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = {
.write = tracing_saved_cmdlines_size_write,
};
+static void
+trace_insert_enum_map(struct trace_enum_map **start, struct trace_enum_map **stop)
+{
+ struct trace_enum_map **map;
+ int len = stop - start;
+
+ if (len <= 0)
+ return;
+
+ map = start;
+
+ trace_event_enum_update(map, len);
+}
+
static ssize_t
tracing_set_trace_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -6542,6 +6556,14 @@ struct dentry *tracing_init_dentry(void)
return tr->dir;
}
+extern struct trace_enum_map *__start_ftrace_enum_maps[];
+extern struct trace_enum_map *__stop_ftrace_enum_maps[];
+
+static void __init trace_enum_init(void)
+{
+ trace_insert_enum_map(__start_ftrace_enum_maps, __stop_ftrace_enum_maps);
+}
+
static __init int tracer_init_debugfs(void)
{
struct dentry *d_tracer;
@@ -6566,6 +6588,8 @@ static __init int tracer_init_debugfs(void)
trace_create_file("saved_cmdlines_size", 0644, d_tracer,
NULL, &tracing_saved_cmdlines_size_fops);
+ trace_enum_init();
+
#ifdef CONFIG_DYNAMIC_FTRACE
trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
@@ -6888,7 +6912,7 @@ void __init trace_init(void)
tracepoint_printk = 0;
}
tracer_alloc_buffers();
- trace_event_init();
+ trace_event_init();
}
__init static int clear_boot_tracer(void)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index dd8205a35760..b48d4b08f691 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1309,8 +1309,10 @@ static inline void init_ftrace_syscalls(void) { }
#ifdef CONFIG_EVENT_TRACING
void trace_event_init(void);
+void trace_event_enum_update(struct trace_enum_map **map, int len);
#else
static inline void __init trace_event_init(void) { }
+static inlin void trace_event_enum_update(struct trace_enum_map **map, int len) { }
#endif
extern struct trace_iterator *tracepoint_print_iter;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index db54dda10ccc..fc58c50fbf01 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1704,6 +1704,125 @@ __register_event(struct ftrace_event_call *call, struct module *mod)
return 0;
}
+static char *enum_replace(char *ptr, struct trace_enum_map *map, int len)
+{
+ int rlen;
+ int elen;
+
+ /* Find the length of the enum value as a string */
+ elen = snprintf(ptr, 0, "%ld", map->enum_value);
+ /* Make sure there's enough room to replace the string with the value */
+ if (len < elen)
+ return NULL;
+
+ snprintf(ptr, elen + 1, "%ld", map->enum_value);
+
+ /* Get the rest of the string of ptr */
+ rlen = strlen(ptr + len);
+ memmove(ptr + elen, ptr + len, rlen);
+ /* Make sure we end the new string */
+ ptr[elen + rlen] = 0;
+
+ return ptr + elen;
+}
+
+static void update_event_printk(struct ftrace_event_call *call,
+ struct trace_enum_map *map)
+{
+ char *ptr;
+ int quote = 0;
+ int len = strlen(map->enum_string);
+
+ for (ptr = call->print_fmt; *ptr; ptr++) {
+ if (*ptr == '\\') {
+ ptr++;
+ /* paranoid */
+ if (!*ptr)
+ break;
+ continue;
+ }
+ if (*ptr == '"') {
+ quote ^= 1;
+ continue;
+ }
+ if (quote)
+ continue;
+ if (isdigit(*ptr)) {
+ /* skip numbers */
+ do {
+ ptr++;
+ /* Check for alpha chars like ULL */
+ } while (isalnum(*ptr));
+ /*
+ * A number must have some kind of delimiter after
+ * it, and we can ignore that too.
+ */
+ continue;
+ }
+ if (isalpha(*ptr) || *ptr == '_') {
+ if (strncmp(map->enum_string, ptr, len) == 0 &&
+ !isalnum(ptr[len]) && ptr[len] != '_') {
+ ptr = enum_replace(ptr, map, len);
+ /* Hmm, enum string smaller than value */
+ if (WARN_ON_ONCE(!ptr))
+ return;
+ /*
+ * No need to decrement here, as enum_replace()
+ * returns the pointer to the character passed
+ * the enum, and two enums can not be placed
+ * back to back without something in between.
+ * We can skip that something in between.
+ */
+ continue;
+ }
+ skip_more:
+ do {
+ ptr++;
+ } while (isalnum(*ptr) || *ptr == '_');
+ /*
+ * If what comes after this variable is a '.' or
+ * '->' then we can continue to ignore that string.
+ */
+ if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
+ ptr += *ptr == '.' ? 1 : 2;
+ goto skip_more;
+ }
+ /*
+ * Once again, we can skip the delimiter that came
+ * after the string.
+ */
+ continue;
+ }
+ }
+}
+
+void trace_event_enum_update(struct trace_enum_map **map, int len)
+{
+ struct ftrace_event_call *call, *p;
+ const char *last_system = NULL;
+ int last_i;
+ int i;
+
+ down_write(&trace_event_sem);
+ list_for_each_entry_safe(call, p, &ftrace_events, list) {
+ /* events are usually grouped together with systems */
+ if (!last_system || call->class->system != last_system) {
+ last_i = 0;
+ last_system = call->class->system;
+ }
+
+ for (i = last_i; i < len; i++) {
+ if (call->class->system == map[i]->system) {
+ /* Save the first system if need be */
+ if (!last_i)
+ last_i = i;
+ update_event_printk(call, map[i]);
+ }
+ }
+ }
+ up_write(&trace_event_sem);
+}
+
static struct ftrace_event_file *
trace_create_new_event(struct ftrace_event_call *call,
struct trace_array *tr)
--
2.1.4
Hi Steve,
On Thu, Apr 02, 2015 at 09:38:09PM -0400, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <[email protected]>
>
> Several tracepoints use the helper functions __print_symbolic() or
> __print_flags() and pass in enums that do the mapping between the
> binary data stored and the value to print. This works well for reading
> the ASCII trace files, but when the data is read via userspace tools
> such as perf and trace-cmd, the conversion of the binary value to a
> human string format is lost if an enum is used, as userspace does not
> have access to what the ENUM is.
>
> For example, the tracepoint trace_tlb_flush() has:
>
> __print_symbolic(REC->reason,
> { TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" },
> { TLB_REMOTE_SHOOTDOWN, "remote shootdown" },
> { TLB_LOCAL_SHOOTDOWN, "local shootdown" },
> { TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" })
>
> Which maps the enum values to the strings they represent. But perf and
> trace-cmd do no know what value TLB_LOCAL_MM_SHOOTDOWN is, and would
> not be able to map it.
>
> With TRACE_DEFINE_ENUM(), developers can place these in the event header
> files and ftrace will convert the enums to their values:
>
> By adding:
>
> TRACE_DEFINE_ENUM(TLB_FLUSH_ON_TASK_SWITCH);
> TRACE_DEFINE_ENUM(TLB_REMOTE_SHOOTDOWN);
> TRACE_DEFINE_ENUM(TLB_LOCAL_SHOOTDOWN);
> TRACE_DEFINE_ENUM(TLB_LOCAL_MM_SHOOTDOWN);
>
> $ cat /sys/kernel/debug/tracing/events/tlb/tlb_flush/format
> [...]
> __print_symbolic(REC->reason,
> { 0, "flush on task switch" },
> { 1, "remote shootdown" },
> { 2, "local shootdown" },
> { 3, "local mm shootdown" })
>
> The above is what userspace expects to see, and tools do not need to
> be modified to parse them.
>
> Cc: Guilherme Cox <[email protected]>
> Cc: Tony Luck <[email protected]>
> Cc: Xie XiuQi <[email protected]>
> Signed-off-by: Steven Rostedt <[email protected]>
> ---
[SNIP]
> +static void update_event_printk(struct ftrace_event_call *call,
> + struct trace_enum_map *map)
> +{
> + char *ptr;
> + int quote = 0;
> + int len = strlen(map->enum_string);
> +
> + for (ptr = call->print_fmt; *ptr; ptr++) {
> + if (*ptr == '\\') {
> + ptr++;
> + /* paranoid */
> + if (!*ptr)
> + break;
> + continue;
> + }
> + if (*ptr == '"') {
> + quote ^= 1;
> + continue;
> + }
> + if (quote)
> + continue;
> + if (isdigit(*ptr)) {
> + /* skip numbers */
> + do {
> + ptr++;
> + /* Check for alpha chars like ULL */
> + } while (isalnum(*ptr));
> + /*
> + * A number must have some kind of delimiter after
> + * it, and we can ignore that too.
> + */
> + continue;
> + }
> + if (isalpha(*ptr) || *ptr == '_') {
> + if (strncmp(map->enum_string, ptr, len) == 0 &&
> + !isalnum(ptr[len]) && ptr[len] != '_') {
> + ptr = enum_replace(ptr, map, len);
> + /* Hmm, enum string smaller than value */
> + if (WARN_ON_ONCE(!ptr))
> + return;
> + /*
> + * No need to decrement here, as enum_replace()
> + * returns the pointer to the character passed
> + * the enum, and two enums can not be placed
> + * back to back without something in between.
> + * We can skip that something in between.
> + */
> + continue;
Maybe I'm becoming a bit paranoid, what I worried was like this:
ENUM1\"ENUM2\"
In this case, it skips the backslash and makes quotation effective..
> + }
> + skip_more:
> + do {
> + ptr++;
> + } while (isalnum(*ptr) || *ptr == '_');
> + /*
> + * If what comes after this variable is a '.' or
> + * '->' then we can continue to ignore that string.
> + */
> + if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
> + ptr += *ptr == '.' ? 1 : 2;
> + goto skip_more;
> + }
> + /*
> + * Once again, we can skip the delimiter that came
> + * after the string.
> + */
> + continue;
> + }
> + }
> +}
> +
> +void trace_event_enum_update(struct trace_enum_map **map, int len)
> +{
> + struct ftrace_event_call *call, *p;
> + const char *last_system = NULL;
> + int last_i;
> + int i;
> +
> + down_write(&trace_event_sem);
> + list_for_each_entry_safe(call, p, &ftrace_events, list) {
> + /* events are usually grouped together with systems */
> + if (!last_system || call->class->system != last_system) {
I think simply checking "call->class->system != last_system" would work.
Thanks,
Namhyung
> + last_i = 0;
> + last_system = call->class->system;
> + }
> +
> + for (i = last_i; i < len; i++) {
> + if (call->class->system == map[i]->system) {
> + /* Save the first system if need be */
> + if (!last_i)
> + last_i = i;
> + update_event_printk(call, map[i]);
> + }
> + }
> + }
> + up_write(&trace_event_sem);
> +}
> +
> static struct ftrace_event_file *
> trace_create_new_event(struct ftrace_event_call *call,
> struct trace_array *tr)
> --
> 2.1.4
>
>
On Mon, 6 Apr 2015 13:54:33 +0900
Namhyung Kim <[email protected]> wrote:
> > + if (isalpha(*ptr) || *ptr == '_') {
> > + if (strncmp(map->enum_string, ptr, len) == 0 &&
> > + !isalnum(ptr[len]) && ptr[len] != '_') {
> > + ptr = enum_replace(ptr, map, len);
> > + /* Hmm, enum string smaller than value */
> > + if (WARN_ON_ONCE(!ptr))
> > + return;
> > + /*
> > + * No need to decrement here, as enum_replace()
> > + * returns the pointer to the character passed
> > + * the enum, and two enums can not be placed
> > + * back to back without something in between.
> > + * We can skip that something in between.
> > + */
> > + continue;
>
> Maybe I'm becoming a bit paranoid, what I worried was like this:
>
> ENUM1\"ENUM2\"
>
> In this case, it skips the backslash and makes quotation effective..
The only time a backslash is OK is if it's in a quote, where we do not
process enums there anyway.
The above isn't valid C outside of quotes, so I'm still not worried.
>
>
> > + }
> > + skip_more:
> > + do {
> > + ptr++;
> > + } while (isalnum(*ptr) || *ptr == '_');
> > + /*
> > + * If what comes after this variable is a '.' or
> > + * '->' then we can continue to ignore that string.
> > + */
> > + if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
> > + ptr += *ptr == '.' ? 1 : 2;
> > + goto skip_more;
> > + }
> > + /*
> > + * Once again, we can skip the delimiter that came
> > + * after the string.
> > + */
> > + continue;
> > + }
> > + }
> > +}
> > +
> > +void trace_event_enum_update(struct trace_enum_map **map, int len)
> > +{
> > + struct ftrace_event_call *call, *p;
> > + const char *last_system = NULL;
> > + int last_i;
> > + int i;
> > +
> > + down_write(&trace_event_sem);
> > + list_for_each_entry_safe(call, p, &ftrace_events, list) {
> > + /* events are usually grouped together with systems */
> > + if (!last_system || call->class->system != last_system) {
>
> I think simply checking "call->class->system != last_system" would work.
I think you are correct, but I'm not sure I want to change it. Mainly
because it's more readable that way. The !last_system is basically the
"this is first time". Leaving it out may cause people to think it's
wrong.
But I may change my mind and remove it anyway ;-)
If there's other things wrong with this patch, I may update this too.
Thanks for reviewing.
-- Steve
Hi Steve,
On Mon, Apr 06, 2015 at 07:52:37AM -0400, Steven Rostedt wrote:
> On Mon, 6 Apr 2015 13:54:33 +0900
> Namhyung Kim <[email protected]> wrote:
>
>
> > > + if (isalpha(*ptr) || *ptr == '_') {
> > > + if (strncmp(map->enum_string, ptr, len) == 0 &&
> > > + !isalnum(ptr[len]) && ptr[len] != '_') {
> > > + ptr = enum_replace(ptr, map, len);
> > > + /* Hmm, enum string smaller than value */
> > > + if (WARN_ON_ONCE(!ptr))
> > > + return;
> > > + /*
> > > + * No need to decrement here, as enum_replace()
> > > + * returns the pointer to the character passed
> > > + * the enum, and two enums can not be placed
> > > + * back to back without something in between.
> > > + * We can skip that something in between.
> > > + */
> > > + continue;
> >
> > Maybe I'm becoming a bit paranoid, what I worried was like this:
> >
> > ENUM1\"ENUM2\"
> >
> > In this case, it skips the backslash and makes quotation effective..
>
> The only time a backslash is OK is if it's in a quote, where we do not
> process enums there anyway.
>
> The above isn't valid C outside of quotes, so I'm still not worried.
OK
>
> >
> >
> > > + }
> > > + skip_more:
> > > + do {
> > > + ptr++;
> > > + } while (isalnum(*ptr) || *ptr == '_');
> > > + /*
> > > + * If what comes after this variable is a '.' or
> > > + * '->' then we can continue to ignore that string.
> > > + */
> > > + if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
> > > + ptr += *ptr == '.' ? 1 : 2;
> > > + goto skip_more;
> > > + }
> > > + /*
> > > + * Once again, we can skip the delimiter that came
> > > + * after the string.
> > > + */
> > > + continue;
> > > + }
> > > + }
> > > +}
> > > +
> > > +void trace_event_enum_update(struct trace_enum_map **map, int len)
> > > +{
> > > + struct ftrace_event_call *call, *p;
> > > + const char *last_system = NULL;
> > > + int last_i;
> > > + int i;
> > > +
> > > + down_write(&trace_event_sem);
> > > + list_for_each_entry_safe(call, p, &ftrace_events, list) {
> > > + /* events are usually grouped together with systems */
> > > + if (!last_system || call->class->system != last_system) {
> >
> > I think simply checking "call->class->system != last_system" would work.
>
> I think you are correct, but I'm not sure I want to change it. Mainly
> because it's more readable that way. The !last_system is basically the
> "this is first time". Leaving it out may cause people to think it's
> wrong.
>
> But I may change my mind and remove it anyway ;-)
>
> If there's other things wrong with this patch, I may update this too.
>
> Thanks for reviewing.
OK. You can add my Acked-by if you like..
Thanks,
Namhyung
On Tue, 7 Apr 2015 23:16:02 +0900
Namhyung Kim <[email protected]> wrote:
> > Thanks for reviewing.
>
> OK. You can add my Acked-by if you like..
Cool, I will.
Thanks!
-- Steve
On 04/02/2015 09:38 PM, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <[email protected]>
>
> Several tracepoints use the helper functions __print_symbolic() or
> __print_flags() and pass in enums that do the mapping between the
> binary data stored and the value to print. This works well for reading
> the ASCII trace files, but when the data is read via userspace tools
> such as perf and trace-cmd, the conversion of the binary value to a
> human string format is lost if an enum is used, as userspace does not
> have access to what the ENUM is.
>
> For example, the tracepoint trace_tlb_flush() has:
>
> __print_symbolic(REC->reason,
> { TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" },
> { TLB_REMOTE_SHOOTDOWN, "remote shootdown" },
> { TLB_LOCAL_SHOOTDOWN, "local shootdown" },
> { TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" })
>
> Which maps the enum values to the strings they represent. But perf and
> trace-cmd do no know what value TLB_LOCAL_MM_SHOOTDOWN is, and would
> not be able to map it.
>
> With TRACE_DEFINE_ENUM(), developers can place these in the event header
> files and ftrace will convert the enums to their values:
>
> By adding:
>
> TRACE_DEFINE_ENUM(TLB_FLUSH_ON_TASK_SWITCH);
> TRACE_DEFINE_ENUM(TLB_REMOTE_SHOOTDOWN);
> TRACE_DEFINE_ENUM(TLB_LOCAL_SHOOTDOWN);
> TRACE_DEFINE_ENUM(TLB_LOCAL_MM_SHOOTDOWN);
>
> $ cat /sys/kernel/debug/tracing/events/tlb/tlb_flush/format
> [...]
> __print_symbolic(REC->reason,
> { 0, "flush on task switch" },
> { 1, "remote shootdown" },
> { 2, "local shootdown" },
> { 3, "local mm shootdown" })
>
> The above is what userspace expects to see, and tools do not need to
> be modified to parse them.
>
> Cc: Guilherme Cox <[email protected]>
> Cc: Tony Luck <[email protected]>
> Cc: Xie XiuQi <[email protected]>
> Signed-off-by: Steven Rostedt <[email protected]>
> ---
Hey Steven,
I'm seeing the following when booting:
[ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
[ 10.680222] Read of size 1 by task swapper/0/1
[ 10.680222] Address belongs to variable print_fmt_9p_client_req+0x848/0x880
[ 10.680222] CPU: 19 PID: 1 Comm: swapper/0 Not tainted 4.0.0-next-20150415-sasha-00064-g7858a62 #2147
[ 10.680222] ffffffffa6c4dc68 00000000915e69dc ffff88004e8efb18 ffffffffa1b4f7a6
[ 10.680222] 0000000000000000 ffff88004e8efba8 ffff88004e8efb98 ffffffff976544b1
[ 10.680222] ffff88004e8efbd8 ffffffff990134a4 0000000000000282 ffffffffa444e381
[ 10.680222] Call Trace:
[ 10.680222] dump_stack (lib/dump_stack.c:52)
[ 10.680222] kasan_report_error (mm/kasan/report.c:132 mm/kasan/report.c:193)
[ 10.680222] ? snprintf (lib/vsprintf.c:2069)
[ 10.680222] ? vsprintf (lib/vsprintf.c:2069)
[ 10.680222] ? trace_event_enum_update (kernel/trace/trace_events.c:1807)
[ 10.680222] __asan_report_load1_noabort (mm/kasan/report.c:230 mm/kasan/report.c:248)
[ 10.680222] ? trace_event_enum_update (kernel/trace/trace_events.c:1807)
[ 10.680222] trace_event_enum_update (kernel/trace/trace_events.c:1807)
[ 10.680222] tracer_init_tracefs (kernel/trace/trace.c:4122 kernel/trace/trace.c:6750 kernel/trace/trace.c:6848)
[ 10.680222] ? clear_boot_tracer (kernel/trace/trace.c:6825)
[ 10.680222] ? clear_boot_tracer (kernel/trace/trace.c:6825)
[ 10.680222] do_one_initcall (init/main.c:788)
[ 10.680222] ? try_to_run_init_process (init/main.c:777)
[ 10.680222] ? parse_args (kernel/params.c:131 kernel/params.c:216)
[ 10.680222] ? trace_hardirqs_on (kernel/locking/lockdep.c:2630)
[ 10.680222] kernel_init_freeable (init/main.c:853 init/main.c:861 init/main.c:880 init/main.c:1001)
[ 10.680222] ? local_clock (kernel/sched/clock.c:392)
[ 10.680222] ? start_kernel (init/main.c:973)
[ 10.680222] ? finish_task_switch (kernel/sched/core.c:2249)
[ 10.680222] ? finish_task_switch (include/linux/tick.h:186 kernel/sched/core.c:2263)
[ 10.680222] ? finish_task_switch (kernel/sched/sched.h:1077 kernel/sched/core.c:2245)
[ 10.680222] ? rest_init (init/main.c:928)
[ 10.680222] kernel_init (init/main.c:933)
[ 10.680222] ? rest_init (init/main.c:928)
[ 10.680222] ret_from_fork (arch/x86/kernel/entry_64.S:631)
[ 10.680222] ? rest_init (init/main.c:928)
[ 10.680222] Memory state around the buggy address:
[ 10.680222] ffffffffa6c4db00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 10.680222] ffffffffa6c4db80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 10.680222] >ffffffffa6c4dc00: 00 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa
[ 10.680222] ^
[ 10.680222] ffffffffa6c4dc80: fa fa fa fa 00 00 00 00 fa fa fa fa 00 00 00 00
[ 10.680222] ffffffffa6c4dd00: fa fa fa fa 00 00 00 00 fa fa fa fa 00 00 00 00
Thanks,
Sasha
On Wed, 15 Apr 2015 09:22:37 -0400
Sasha Levin <[email protected]> wrote:
> Hey Steven,
>
> I'm seeing the following when booting:
>
> [ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
Thanks for the report. Mind sending me over your config, and which git
commit was your HEAD. I can't seem to find 7858a62 from your output.
-- Steve
On 04/15/2015 10:05 AM, Steven Rostedt wrote:
> On Wed, 15 Apr 2015 09:22:37 -0400
> Sasha Levin <[email protected]> wrote:
>
>> Hey Steven,
>>
>> I'm seeing the following when booting:
>>
>> [ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
>
> Thanks for the report. Mind sending me over your config, and which git
> commit was your HEAD. I can't seem to find 7858a62 from your output.
It reproduces on the latest -next kernel. I've attached my config.
Thanks,
Sasha
On Wed, 15 Apr 2015 20:58:31 -0400
Sasha Levin <[email protected]> wrote:
> On 04/15/2015 10:05 AM, Steven Rostedt wrote:
> > On Wed, 15 Apr 2015 09:22:37 -0400
> > Sasha Levin <[email protected]> wrote:
> >
> >> Hey Steven,
> >>
> >> I'm seeing the following when booting:
> >>
> >> [ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
> >
> > Thanks for the report. Mind sending me over your config, and which git
> > commit was your HEAD. I can't seem to find 7858a62 from your output.
>
> It reproduces on the latest -next kernel. I've attached my config.
>
What version of gcc is required to run KASan, the highest version I
have to build kernels with is 4.9.0
I have no idea what event caused the issue :-/
-- Steve
On 04/16/2015 11:21 PM, Steven Rostedt wrote:
> On Wed, 15 Apr 2015 20:58:31 -0400
> Sasha Levin <[email protected]> wrote:
>
>> > On 04/15/2015 10:05 AM, Steven Rostedt wrote:
>>> > > On Wed, 15 Apr 2015 09:22:37 -0400
>>> > > Sasha Levin <[email protected]> wrote:
>>> > >
>>>> > >> Hey Steven,
>>>> > >>
>>>> > >> I'm seeing the following when booting:
>>>> > >>
>>>> > >> [ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
>>> > >
>>> > > Thanks for the report. Mind sending me over your config, and which git
>>> > > commit was your HEAD. I can't seem to find 7858a62 from your output.
>> >
>> > It reproduces on the latest -next kernel. I've attached my config.
>> >
> What version of gcc is required to run KASan, the highest version I
> have to build kernels with is 4.9.0
>
> I have no idea what event caused the issue :-/
4.9.2+ is needed for KASan.
Thanks,
Sasha
The documentation shows a need for gcc > 4.9.2, but it's
really >=. The Kconfig entries don't show require versions
so add them. Correct a latter/later typo too.
Signed-off-by: Joe Perches <[email protected]>
---
(dropping Ingo from cc's)
On Thu, 2015-04-16 at 23:59 -0400, Sasha Levin wrote:
> On 04/16/2015 11:21 PM, Steven Rostedt wrote:
> > I have no idea what event caused the issue :-/
> 4.9.2+ is needed for KASan.
Perhaps the documentation and Kconfig entries could
describe that a bit better.
Documentation/kasan.txt | 6 +++---
lib/Kconfig.kasan | 6 ++++--
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt
index 092fc10..3038b4b 100644
--- a/Documentation/kasan.txt
+++ b/Documentation/kasan.txt
@@ -9,7 +9,7 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
bugs.
KASan uses compile-time instrumentation for checking every memory access,
-therefore you will need a certain version of GCC > 4.9.2
+therefore you will need a gcc version of 4.9.2 or later.
Currently KASan is supported only for x86_64 architecture and requires that the
kernel be built with the SLUB allocator.
@@ -23,8 +23,8 @@ To enable KASAN configure kernel with:
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
is compiler instrumentation types. The former produces smaller binary the
-latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
-latter.
+latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
+of 5.0 or later.
Currently KASAN works only with the SLUB memory allocator.
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index 4fecaedc..1e1c23e 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -10,8 +10,9 @@ config KASAN
help
Enables kernel address sanitizer - runtime memory debugger,
designed to find out-of-bounds accesses and use-after-free bugs.
- This is strictly debugging feature. It consumes about 1/8
- of available memory and brings about ~x3 performance slowdown.
+ This is strictly a debugging feature and it requires a gcc version
+ of 4.9.2 or later. It consumes about 1/8 of available memory and
+ brings about ~x3 performance slowdown.
For better error detection enable CONFIG_STACKTRACE,
and add slub_debug=U to boot cmdline.
@@ -40,6 +41,7 @@ config KASAN_INLINE
memory accesses. This is faster than outline (in some workloads
it gives about x2 boost over outline instrumentation), but
make kernel's .text size much bigger.
+ This requires a gcc version of 5.0 or later.
endchoice
On 04/17/2015 06:59 AM, Sasha Levin wrote:
> On 04/16/2015 11:21 PM, Steven Rostedt wrote:
>> On Wed, 15 Apr 2015 20:58:31 -0400
>> Sasha Levin <[email protected]> wrote:
>>
>>>> On 04/15/2015 10:05 AM, Steven Rostedt wrote:
>>>>>> On Wed, 15 Apr 2015 09:22:37 -0400
>>>>>> Sasha Levin <[email protected]> wrote:
>>>>>>
>>>>>>>> Hey Steven,
>>>>>>>>
>>>>>>>> I'm seeing the following when booting:
>>>>>>>>
>>>>>>>> [ 10.678876] BUG: KASan: out of bounds access in trace_event_enum_update+0xb1d/0xb70 at addr ffffffffa6c4dc68
>>>>>>
>>>>>> Thanks for the report. Mind sending me over your config, and which git
>>>>>> commit was your HEAD. I can't seem to find 7858a62 from your output.
>>>>
>>>> It reproduces on the latest -next kernel. I've attached my config.
>>>>
>> What version of gcc is required to run KASan, the highest version I
>> have to build kernels with is 4.9.0
>>
>> I have no idea what event caused the issue :-/
>
> 4.9.2+ is needed for KASan.
>
Actually, detection of out of bounds accesses to stack and global variables works
only with gcc 5+
And this is out-of-bounds access to global variable print_fmt_9p_client_req.
Line numbers in report is ambiguous, so I did following change to reduce compiler's optimization
and get more clear line numbers.
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 7da1dfe..40c31b6 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1726,7 +1726,7 @@ static char *enum_replace(char *ptr, struct trace_enum_map *map, int len)
return ptr + elen;
}
-static void update_event_printk(struct ftrace_event_call *call,
+__attribute__((optimize("O0"))) static noinline void update_event_printk(struct ftrace_event_call *call,
struct trace_enum_map *map)
{
char *ptr
This ended up in this splat (which has more sane line numbers):
[ 0.123688] ==================================================================
[ 0.123688] BUG: KASan: out of bounds access in update_event_printk+0x6fe/0x720 at addr ffffffff821654a8
[ 0.123688] Read of size 1 by task swapper/0/1
[ 0.123688] Address belongs to variable print_fmt_9p_client_req+0x848/0x880
[ 0.124000] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.0.0+ #269
[ 0.124000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5.1-0-g8936dbb-20141113_115728-nilsson.home.kraxel.org 04/01/2014
[ 0.124000] ffffffff82165720 ffff8801f4d17be8 ffffffff81cc0d35 000000000000003f
[ 0.124000] ffff8801f4d17c80 ffff8801f4d17c68 ffffffff8139cafc ffff8801f4d17c28
[ 0.124000] ffffffff8139c39d 0000000000000292 ffffffff81397c5c ffff8801f4d17c38
[ 0.124000] Call Trace:
[ 0.124000] dump_stack (lib/dump_stack.c:52)
[ 0.124000] kasan_report_error (mm/kasan/report.c:132 mm/kasan/report.c:193)
[ 0.124000] ? kasan_slab_alloc (mm/kasan/kasan.c:325)
[ 0.124000] ? kmem_cache_alloc (mm/slub.c:2522)
[ 0.124000] __asan_report_load1_noabort (mm/kasan/report.c:248)
[ 0.124000] ? update_event_printk (kernel/trace/trace_events.c:1736 (discriminator 1))
[ 0.124000] update_event_printk (kernel/trace/trace_events.c:1736 (discriminator 1))
[ 0.124000] trace_event_enum_update (kernel/trace/trace_events.c:1819)
[ 0.124000] ? tracefs_create_file (fs/tracefs/inode.c:413)
[ 0.124000] tracer_init_tracefs (kernel/trace/trace.c:4122 kernel/trace/trace.c:6750 kernel/trace/trace.c:6848)
[ 0.124000] ? set_tracepoint_printk (kernel/trace/trace.c:6825)
[ 0.124000] do_one_initcall (init/main.c:788)
[ 0.124000] ? try_to_run_init_process (init/main.c:777)
[ 0.124000] ? parse_args (kernel/params.c:218)
[ 0.124000] kernel_init_freeable (init/main.c:853 init/main.c:861 init/main.c:880 init/main.c:1001)
[ 0.124000] ? __switch_to (arch/x86/include/asm/paravirt.h:25 arch/x86/kernel/process_64.c:410)
[ 0.124000] ? rest_init (init/main.c:928)
[ 0.124000] kernel_init (init/main.c:933)
[ 0.124000] ? rest_init (init/main.c:928)
[ 0.124000] ret_from_fork (arch/x86/kernel/entry_64.S:631)
[ 0.124000] ? rest_init (init/main.c:928)
[ 0.124000] Memory state around the buggy address:
[ 0.124000] ffffffff82165380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 0.124000] ffffffff82165400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 0.124000] >ffffffff82165480: 00 00 00 00 00 fa fa fa fa fa fa fa 00 00 00 00
[ 0.124000] ^
[ 0.124000] ffffffff82165500: fa fa fa fa 00 00 00 00 fa fa fa fa 00 00 00 00
[ 0.124000] ffffffff82165580: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
[ 0.124000] ==================================================================
And kasan is not needed to debug this further.
Just stick WARN_ON(ptr > call->print_fmt + strlen(call->print_fmt)) into the 'for' loop in update_event_printk().
>
> Thanks,
> Sasha
>
On 04/17/2015 07:44 AM, Joe Perches wrote:
> The documentation shows a need for gcc > 4.9.2, but it's
> really >=. The Kconfig entries don't show require versions
> so add them. Correct a latter/later typo too.
>
> Signed-off-by: Joe Perches <[email protected]>
> ---
>
> (dropping Ingo from cc's)
>
> On Thu, 2015-04-16 at 23:59 -0400, Sasha Levin wrote:
>> On 04/16/2015 11:21 PM, Steven Rostedt wrote:
>>> I have no idea what event caused the issue :-/
>> 4.9.2+ is needed for KASan.
>
> Perhaps the documentation and Kconfig entries could
> describe that a bit better.
>
Could you also please mention that gcc 5+ is required to detect out of bounds accesses
to global and stack variables?
On Fri, 2015-04-17 at 10:54 +0300, Andrey Ryabinin wrote:
> On 04/17/2015 07:44 AM, Joe Perches wrote:
> > The documentation shows a need for gcc > 4.9.2, but it's
> > really >=. The Kconfig entries don't show require versions
> > so add them. Correct a latter/later typo too.
[]
> > On Thu, 2015-04-16 at 23:59 -0400, Sasha Levin wrote:
> >> On 04/16/2015 11:21 PM, Steven Rostedt wrote:
> >>> I have no idea what event caused the issue :-/
> >> 4.9.2+ is needed for KASan.
> >
> > Perhaps the documentation and Kconfig entries could
> > describe that a bit better.
> >
>
> Could you also please mention that gcc 5+ is required to detect out of bounds accesses
> to global and stack variables?
You know better than I where and how to describe that.
On Fri, 17 Apr 2015 10:44:42 +0300
Andrey Ryabinin <[email protected]> wrote:
> And kasan is not needed to debug this further.
> Just stick WARN_ON(ptr > call->print_fmt + strlen(call->print_fmt)) into the 'for' loop in update_event_printk().
Thanks, although I think I found the bug with just inspection. I put in
WARN_ON(*ptr) at various locations to see if it triggers.
-- Steve
On Fri, 17 Apr 2015 09:29:02 -0400
Steven Rostedt <[email protected]> wrote:
> On Fri, 17 Apr 2015 10:44:42 +0300
> Andrey Ryabinin <[email protected]> wrote:
>
>
> > And kasan is not needed to debug this further.
> > Just stick WARN_ON(ptr > call->print_fmt + strlen(call->print_fmt)) into the 'for' loop in update_event_printk().
>
> Thanks, although I think I found the bug with just inspection. I put in
> WARN_ON(*ptr) at various locations to see if it triggers.
Yep, that's the issue.
Can you guys test this patch please:
-- Steve
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 39bcfc3f071d..97d454a4dbfb 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1753,6 +1753,8 @@ static void update_event_printk(struct ftrace_event_call *call,
ptr++;
/* Check for alpha chars like ULL */
} while (isalnum(*ptr));
+ if (!*ptr)
+ break;
/*
* A number must have some kind of delimiter after
* it, and we can ignore that too.
@@ -1779,12 +1781,16 @@ static void update_event_printk(struct ftrace_event_call *call,
do {
ptr++;
} while (isalnum(*ptr) || *ptr == '_');
+ if (!*ptr)
+ break;
/*
* If what comes after this variable is a '.' or
* '->' then we can continue to ignore that string.
*/
if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
ptr += *ptr == '.' ? 1 : 2;
+ if (!*ptr)
+ break;
goto skip_more;
}
/*
On 04/17/2015 04:51 PM, Steven Rostedt wrote:
> On Fri, 17 Apr 2015 09:29:02 -0400
> Steven Rostedt <[email protected]> wrote:
>
>> On Fri, 17 Apr 2015 10:44:42 +0300
>> Andrey Ryabinin <[email protected]> wrote:
>>
>>
>>> And kasan is not needed to debug this further.
>>> Just stick WARN_ON(ptr > call->print_fmt + strlen(call->print_fmt)) into the 'for' loop in update_event_printk().
>>
>> Thanks, although I think I found the bug with just inspection. I put in
>> WARN_ON(*ptr) at various locations to see if it triggers.
>
> Yep, that's the issue.
>
> Can you guys test this patch please:
>
Tested-by: Andrey Ryabinin <[email protected]>
> -- Steve
>
> diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
> index 39bcfc3f071d..97d454a4dbfb 100644
> --- a/kernel/trace/trace_events.c
> +++ b/kernel/trace/trace_events.c
> @@ -1753,6 +1753,8 @@ static void update_event_printk(struct ftrace_event_call *call,
> ptr++;
> /* Check for alpha chars like ULL */
> } while (isalnum(*ptr));
> + if (!*ptr)
> + break;
> /*
> * A number must have some kind of delimiter after
> * it, and we can ignore that too.
> @@ -1779,12 +1781,16 @@ static void update_event_printk(struct ftrace_event_call *call,
> do {
> ptr++;
> } while (isalnum(*ptr) || *ptr == '_');
> + if (!*ptr)
> + break;
> /*
> * If what comes after this variable is a '.' or
> * '->' then we can continue to ignore that string.
> */
> if (*ptr == '.' || (ptr[0] == '-' && ptr[1] == '>')) {
> ptr += *ptr == '.' ? 1 : 2;
> + if (!*ptr)
> + break;
> goto skip_more;
> }
> /*
>
From: Joe Perches <[email protected]>
The documentation shows a need for gcc > 4.9.2, but it's
really >=. The Kconfig entries don't show require versions
so add them. Correct a latter/later typo too.
Also mention that gcc 5 required to catch out of bounds accesses
to global and stack variables.
Signed-off-by: Joe Perches <[email protected]>
Signed-off-by: Andrey Ryabinin <[email protected]>
---
Documentation/kasan.txt | 8 +++++---
lib/Kconfig.kasan | 8 ++++++--
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt
index 092fc10..4692241 100644
--- a/Documentation/kasan.txt
+++ b/Documentation/kasan.txt
@@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
bugs.
KASan uses compile-time instrumentation for checking every memory access,
-therefore you will need a certain version of GCC > 4.9.2
+therefore you will need a gcc version of 4.9.2 or later. KASan could detect out
+of bounds accesses to stack or global variables, but only if gcc 5.0 or later was
+used to built the kernel.
Currently KASan is supported only for x86_64 architecture and requires that the
kernel be built with the SLUB allocator.
@@ -23,8 +25,8 @@ To enable KASAN configure kernel with:
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
is compiler instrumentation types. The former produces smaller binary the
-latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
-latter.
+latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
+of 5.0 or later.
Currently KASAN works only with the SLUB memory allocator.
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index 4fecaedc..777eda7 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -10,8 +10,11 @@ config KASAN
help
Enables kernel address sanitizer - runtime memory debugger,
designed to find out-of-bounds accesses and use-after-free bugs.
- This is strictly debugging feature. It consumes about 1/8
- of available memory and brings about ~x3 performance slowdown.
+ This is strictly a debugging feature and it requires a gcc version
+ of 4.9.2 or later. Detection of out of bounds accesses to stack or
+ global variables requires gcc 5.0 or later.
+ This feature consumes about 1/8 of available memory and brings about
+ ~x3 performance slowdown.
For better error detection enable CONFIG_STACKTRACE,
and add slub_debug=U to boot cmdline.
@@ -40,6 +43,7 @@ config KASAN_INLINE
memory accesses. This is faster than outline (in some workloads
it gives about x2 boost over outline instrumentation), but
make kernel's .text size much bigger.
+ This requires a gcc version of 5.0 or later.
endchoice
--
2.3.5
On Fri, 17 Apr 2015 19:10:57 +0300
Andrey Ryabinin <[email protected]> wrote:
> From: Joe Perches <[email protected]>
>
> The documentation shows a need for gcc > 4.9.2, but it's
> really >=. The Kconfig entries don't show require versions
> so add them. Correct a latter/later typo too.
> Also mention that gcc 5 required to catch out of bounds accesses
> to global and stack variables.
Applied to the docs tree, thanks.
jon
2015-05-07 18:51 GMT+03:00 Jonathan Corbet <[email protected]>:
> On Fri, 17 Apr 2015 19:10:57 +0300
> Andrey Ryabinin <[email protected]> wrote:
>
>> From: Joe Perches <[email protected]>
>>
>> The documentation shows a need for gcc > 4.9.2, but it's
>> really >=. The Kconfig entries don't show require versions
>> so add them. Correct a latter/later typo too.
>> Also mention that gcc 5 required to catch out of bounds accesses
>> to global and stack variables.
>
> Applied to the docs tree, thanks.
>
This patch already merged in -rc3 via Andrew's tree.
> jon