forked from Minki/linux
tracing: add trace_bprintk()
Impact: add a generic printk() for tracing, like trace_printk() trace_bprintk() uses the infrastructure to record events on ring_buffer. [ fweisbec@gmail.com: ported to latest -tip, made it work if !CONFIG_MODULES, never free the format strings from modules because we can't keep track of them and conditionnaly create the ftrace format strings section (reported by Steven Rostedt) ] Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1236356510-8381-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
1427cdf059
commit
1ba28e02a1
@ -69,6 +69,14 @@
|
||||
#define FTRACE_EVENTS()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACING
|
||||
#define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \
|
||||
*(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
|
||||
VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
|
||||
#else
|
||||
#define TRACE_PRINTKS()
|
||||
#endif
|
||||
|
||||
/* .data section */
|
||||
#define DATA_DATA \
|
||||
*(.data) \
|
||||
@ -100,6 +108,7 @@
|
||||
*(__vermagic) /* Kernel version magic */ \
|
||||
*(__markers_strings) /* Markers: strings */ \
|
||||
*(__tracepoints_strings)/* Tracepoints: strings */ \
|
||||
TRACE_PRINTKS() \
|
||||
} \
|
||||
\
|
||||
.rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \
|
||||
|
@ -225,6 +225,27 @@ extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
|
||||
|
||||
#ifdef CONFIG_TRACE_BPRINTK
|
||||
extern int trace_vbprintk(unsigned long ip, const char *fmt, va_list args);
|
||||
extern int __trace_bprintk(unsigned long ip, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
static inline void ____trace_bprintk_check_format(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
static inline void ____trace_bprintk_check_format(const char *fmt, ...) {}
|
||||
#define __trace_bprintk_check_format(fmt, args...) \
|
||||
do { \
|
||||
if (0) \
|
||||
____trace_bprintk_check_format(fmt, ##args); \
|
||||
} while (0)
|
||||
|
||||
#define trace_bprintk(fmt, args...) \
|
||||
do { \
|
||||
static char *__attribute__((section("__trace_bprintk_fmt"))) \
|
||||
trace_bprintk_fmt = fmt; \
|
||||
__trace_bprintk_check_format(fmt, ##args); \
|
||||
__trace_bprintk(_THIS_IP_, trace_bprintk_fmt, ##args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define trace_bprintk trace_printk
|
||||
#endif
|
||||
|
||||
/* May be defined in arch */
|
||||
|
@ -329,6 +329,11 @@ struct module
|
||||
unsigned int num_tracepoints;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACE_BPRINTK
|
||||
const char **trace_bprintk_fmt_start;
|
||||
unsigned int num_trace_bprintk_fmt;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_UNLOAD
|
||||
/* What modules depend on me? */
|
||||
struct list_head modules_which_use_me;
|
||||
|
@ -2158,6 +2158,12 @@ static noinline struct module *load_module(void __user *umod,
|
||||
&mod->num_tracepoints);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACE_BPRINTK
|
||||
mod->trace_bprintk_fmt_start = section_objs(hdr, sechdrs, secstrings,
|
||||
"__trace_bprintk_fmt", sizeof(char *),
|
||||
&mod->num_trace_bprintk_fmt);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
if ((mod->num_syms && !mod->crcs)
|
||||
|| (mod->num_gpl_syms && !mod->gpl_crcs)
|
||||
|
@ -3848,6 +3848,21 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(trace_vbprintk);
|
||||
|
||||
int __trace_bprintk(unsigned long ip, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
if (!fmt)
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = trace_vbprintk(ip, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__trace_bprintk);
|
||||
|
||||
static int trace_panic_handler(struct notifier_block *this,
|
||||
unsigned long event, void *unused)
|
||||
{
|
||||
|
@ -19,9 +19,21 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
/* binary printk basic */
|
||||
static DEFINE_MUTEX(btrace_mutex);
|
||||
static int btrace_metadata_count;
|
||||
/*
|
||||
* modules trace_bprintk()'s formats are autosaved in struct trace_bprintk_fmt
|
||||
* which are queued on trace_bprintk_fmt_list.
|
||||
*/
|
||||
static LIST_HEAD(trace_bprintk_fmt_list);
|
||||
|
||||
struct trace_bprintk_fmt {
|
||||
struct list_head list;
|
||||
char fmt[0];
|
||||
};
|
||||
|
||||
|
||||
static inline void lock_btrace(void)
|
||||
{
|
||||
@ -33,26 +45,75 @@ static inline void unlock_btrace(void)
|
||||
mutex_unlock(&btrace_mutex);
|
||||
}
|
||||
|
||||
static void get_btrace_metadata(void)
|
||||
|
||||
static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
|
||||
{
|
||||
struct trace_bprintk_fmt *pos;
|
||||
list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
|
||||
if (!strcmp(pos->fmt, fmt))
|
||||
return pos;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void hold_module_trace_bprintk_format(const char **start, const char **end)
|
||||
{
|
||||
const char **iter;
|
||||
lock_btrace();
|
||||
btrace_metadata_count++;
|
||||
for (iter = start; iter < end; iter++) {
|
||||
struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
|
||||
if (tb_fmt) {
|
||||
*iter = tb_fmt->fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt)
|
||||
+ strlen(*iter) + 1, GFP_KERNEL);
|
||||
if (tb_fmt) {
|
||||
list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
|
||||
strcpy(tb_fmt->fmt, *iter);
|
||||
*iter = tb_fmt->fmt;
|
||||
} else
|
||||
*iter = NULL;
|
||||
}
|
||||
unlock_btrace();
|
||||
}
|
||||
|
||||
static void put_btrace_metadata(void)
|
||||
static int module_trace_bprintk_format_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
lock_btrace();
|
||||
btrace_metadata_count--;
|
||||
unlock_btrace();
|
||||
struct module *mod = data;
|
||||
if (mod->num_trace_bprintk_fmt) {
|
||||
const char **start = mod->trace_bprintk_fmt_start;
|
||||
const char **end = start + mod->num_trace_bprintk_fmt;
|
||||
|
||||
if (val == MODULE_STATE_COMING)
|
||||
hold_module_trace_bprintk_format(start, end);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_MODULES */
|
||||
__init static int
|
||||
module_trace_bprintk_format_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
|
||||
__initdata_or_module static
|
||||
struct notifier_block module_trace_bprintk_format_nb = {
|
||||
.notifier_call = module_trace_bprintk_format_notify,
|
||||
};
|
||||
|
||||
/* events tracer */
|
||||
int trace_bprintk_enable;
|
||||
|
||||
static void start_bprintk_trace(struct trace_array *tr)
|
||||
{
|
||||
get_btrace_metadata();
|
||||
tracing_reset_online_cpus(tr);
|
||||
trace_bprintk_enable = 1;
|
||||
}
|
||||
@ -61,7 +122,6 @@ static void stop_bprintk_trace(struct trace_array *tr)
|
||||
{
|
||||
trace_bprintk_enable = 0;
|
||||
tracing_reset_online_cpus(tr);
|
||||
put_btrace_metadata();
|
||||
}
|
||||
|
||||
static int init_bprintk_trace(struct trace_array *tr)
|
||||
@ -81,7 +141,14 @@ static struct tracer bprintk_trace __read_mostly =
|
||||
|
||||
static __init int init_bprintk(void)
|
||||
{
|
||||
return register_tracer(&bprintk_trace);
|
||||
int ret = register_module_notifier(&module_trace_bprintk_format_nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = register_tracer(&bprintk_trace);
|
||||
if (ret)
|
||||
unregister_module_notifier(&module_trace_bprintk_format_nb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_initcall(init_bprintk);
|
||||
|
Loading…
Reference in New Issue
Block a user