diff --git a/Makefile b/Makefile index c7b8a417..1f804fb8 100644 --- a/Makefile +++ b/Makefile @@ -83,6 +83,10 @@ ifneq ($(KERNELRELEASE),) -o \( $(VERSION) -eq 3 -a $(PATCHLEVEL) -ge 15 \) ] ; then \ echo "lttng-tracepoint.o" ; fi;) + ifneq ($(CONFIG_KALLSYMS),) + obj-$(CONFIG_LTTNG) += lttng-kallsyms.o + endif + obj-$(CONFIG_LTTNG) += lttng-statedump.o lttng-statedump-objs := lttng-statedump-impl.o wrapper/irqdesc.o \ wrapper/fdtable.o diff --git a/instrumentation/events/lttng-module/lttng-kallsyms.h b/instrumentation/events/lttng-module/lttng-kallsyms.h new file mode 100644 index 00000000..0597e8e3 --- /dev/null +++ b/instrumentation/events/lttng-module/lttng-kallsyms.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM lttng_kallsyms + +#if !defined(LTTNG_TRACE_LTTNG_KALLSYMS_H) || defined(TRACE_HEADER_MULTI_READ) +#define LTTNG_TRACE_LTTNG_KALLSYMS_H + +#include + +LTTNG_TRACEPOINT_EVENT(lttng_kallsyms_kernel_symbol, + + TP_PROTO(struct lttng_session *session, + unsigned long addr, const char *symbol, const char *module), + + TP_ARGS(session, addr, symbol, module), + + TP_FIELDS( + ctf_integer_hex(unsigned long, addr, addr) + ctf_string(symbol, symbol) + ctf_string(module, module) + ) +) + +LTTNG_TRACEPOINT_EVENT(lttng_kallsyms_new_module_symbol, + + TP_PROTO(unsigned long addr, const char *symbol, const char *module), + + TP_ARGS(addr, symbol, module), + + TP_FIELDS( + ctf_integer_hex(unsigned long, addr, addr) + ctf_string(symbol, symbol) + ctf_string(module, module) + ) +) + +LTTNG_TRACEPOINT_EVENT(lttng_kallsyms_module_unloaded, + + TP_PROTO(const char *module), + + TP_ARGS(module), + + TP_FIELDS( + ctf_string(module, module) + ) +) + +#endif /* LTTNG_TRACE_LTTNG_KALLSYMS_H */ + +/* This part must be outside protection */ +#include diff --git a/lttng-kallsyms.c b/lttng-kallsyms.c new file mode 100644 index 00000000..29643d78 --- /dev/null +++ b/lttng-kallsyms.c @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * + * lttng-kallsyms.c + * + * Copyright (C) 2019 Geneviève Bastien + */ + +#include +#include +#include +#include + +/* Define the tracepoints, but do not build the probes */ +#define CREATE_TRACE_POINTS +#define TRACE_INCLUDE_PATH instrumentation/events/lttng-module +#define TRACE_INCLUDE_FILE lttng-kallsyms +#define LTTNG_INSTRUMENTATION +#include + +DEFINE_TRACE(lttng_kallsyms_kernel_symbol); +DEFINE_TRACE(lttng_kallsyms_new_module_symbol); +DEFINE_TRACE(lttng_kallsyms_module_unloaded); + +/* + * Trace the kernel symbols from a given module + * + * data: The lttng_session instance + * symbol_name: The function name this symbol resolves to + * module: The module containing this symbol. Can be NULL + * symbol_addr: The symbol address + */ +static +int _lttng_one_symbol_received(void * data, const char * symbol_name, + struct module * module, unsigned long symbol_addr) +{ + struct lttng_session *session = data; + + if (module) { + trace_lttng_kallsyms_kernel_symbol(session, symbol_addr, + symbol_name, module->name); + } else { + trace_lttng_kallsyms_kernel_symbol(session, symbol_addr, + symbol_name, ""); + } + + return 0; +} + +int lttng_enumerate_kernel_symbols(struct lttng_session *session) +{ + int ret = 0; + + ret = kallsyms_on_each_symbol(_lttng_one_symbol_received, (void *) session); + + return ret; +} +EXPORT_SYMBOL_GPL(lttng_enumerate_kernel_symbols); + +#ifdef CONFIG_MODULES + +/* + * Trace the symbols coming from a specific module + * + * data: The new module for which we want the symbols + * symbol_name: The function name this symbol resolves to + * module: The module containing this symbol. Can be NULL + * symbol_addr: The symbol address + */ +static +int _lttng_trace_module_symbol(void * data, const char * symbol_name, + struct module * module, unsigned long symbol_addr) +{ + struct module *mod = data; + + // Trace the symbols from the new module + if (mod == module) { + trace_lttng_kallsyms_new_module_symbol(symbol_addr, symbol_name, mod->name); + } + return 0; +} + +static +int lttng_kallsyms_module_coming(struct module *mod) +{ + int ret = 0; + + ret = kallsyms_on_each_symbol(_lttng_trace_module_symbol, (void *) mod); + + return ret; +} + +static +int lttng_kallsyms_module_going(struct module *mod) +{ + trace_lttng_kallsyms_module_unloaded(mod->name); + return 0; +} + +static +int lttng_kallsyms_module_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct module *mod = data; + int ret = 0; + + switch (val) { + case MODULE_STATE_COMING: + ret = lttng_kallsyms_module_coming(mod); + break; + case MODULE_STATE_GOING: + ret = lttng_kallsyms_module_going(mod); + break; + default: + break; + } + return ret; +} + +static +struct notifier_block lttng_kallsyms_module_notifier = { + .notifier_call = lttng_kallsyms_module_notify, + .priority = 0, +}; + +static +int lttng_kallsyms_module_init(void) +{ + return register_module_notifier(<tng_kallsyms_module_notifier); +} + +static +void lttng_kallsyms_module_exit(void) +{ + WARN_ON(unregister_module_notifier(<tng_kallsyms_module_notifier)); +} + +#else /* #ifdef CONFIG_MODULES */ + +static +int lttng_kallsyms_module_init(void) +{ + return 0; +} + +static +void lttng_kallsyms_module_exit(void) +{ + +} + +#endif /* #else #ifdef CONFIG_MODULES */ + +module_init(lttng_kallsyms_module_init); + +module_exit(lttng_kallsyms_module_exit); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Geneviève Bastien + */ + +#ifndef _LTTNG_KALLSYMS_H +#define _LTTNG_KALLSYMS_H + +#include + +#ifdef CONFIG_KALLSYMS + +int lttng_enumerate_kernel_symbols(struct lttng_session *session); + +#else /* !CONFIG_KALLSYMS */ + +static inline int lttng_enumerate_kernel_symbols(struct lttng_session *session) +{ + return 0; +} + +#endif /* !CONFIG_KALLSYMS */ + +#endif /* _LTTNG_KALLSYMS_H */ diff --git a/lttng-statedump-impl.c b/lttng-statedump-impl.c index dc037508..f4c20770 100644 --- a/lttng-statedump-impl.c +++ b/lttng-statedump-impl.c @@ -54,6 +54,7 @@ #define TRACE_INCLUDE_FILE lttng-statedump #define LTTNG_INSTRUMENTATION #include +#include DEFINE_TRACE(lttng_statedump_block_device); DEFINE_TRACE(lttng_statedump_end); @@ -510,6 +511,9 @@ int do_lttng_statedump(struct lttng_session *session) return ret; } ret = lttng_enumerate_cpu_topology(session); + if (ret) + return ret; + ret = lttng_enumerate_kernel_symbols(session); if (ret) return ret; diff --git a/probes/Kbuild b/probes/Kbuild index b43dd497..69a9be52 100644 --- a/probes/Kbuild +++ b/probes/Kbuild @@ -214,6 +214,14 @@ endif # CONFIG_VIDEO_V4L2 obj-$(CONFIG_LTTNG) += lttng-probe-workqueue.o +ifneq ($(CONFIG_KALLSYMS),) + obj-$(CONFIG_LTTNG) += lttng-probe-kallsyms.o +else + ifdef CONFIG_LOCALVERSION # Check if dot-config is included. + $(warning CONFIG_KALLSYMS is disabled, therefore probe "kallsyms" is disabled. Rebuild your kernel with this configuration option enabled in order to trace this subsystem.) + endif +endif # CONFIG_KALLSYMS + ifneq ($(CONFIG_KALLSYMS_ALL),) obj-$(CONFIG_LTTNG) += lttng-probe-writeback.o else diff --git a/probes/lttng-probe-kallsyms.c b/probes/lttng-probe-kallsyms.c new file mode 100644 index 00000000..c3ed6b84 --- /dev/null +++ b/probes/lttng-probe-kallsyms.c @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * + * probes/lttng-probe-kallsyms.c + * + * LTTng kallsyms probes. + * + * Copyright (C) 2019 Geneviève Bastien + */ + +#include +#include +#include +#include + +/* + * Create LTTng tracepoint probes. + */ +#define LTTNG_PACKAGE_BUILD +#define CREATE_TRACE_POINTS +#define TRACE_INCLUDE_PATH instrumentation/events/lttng-module +#define TRACE_INCLUDE_FILE lttng-kallsyms + +#include + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Geneviève Bastien