Commit 8256e47c authored by Mathieu Desnoyers's avatar Mathieu Desnoyers Committed by Linus Torvalds

Linux Kernel Markers

The marker activation functions sits in kernel/marker.c.  A hash table is used
to keep track of the registered probes and armed markers, so the markers
within a newly loaded module that should be active can be activated at module
load time.

marker_query has been removed. marker_get_first, marker_get_next and
marker_release should be used as iterators on the markers.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Acked-by: default avatar"Frank Ch. Eigler" <fche@redhat.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Mike Mason <mmlnx@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 09cadedb
...@@ -12,7 +12,11 @@ ...@@ -12,7 +12,11 @@
/* .data section */ /* .data section */
#define DATA_DATA \ #define DATA_DATA \
*(.data) \ *(.data) \
*(.data.init.refok) *(.data.init.refok) \
. = ALIGN(8); \
VMLINUX_SYMBOL(__start___markers) = .; \
*(__markers) \
VMLINUX_SYMBOL(__stop___markers) = .;
#define RO_DATA(align) \ #define RO_DATA(align) \
. = ALIGN((align)); \ . = ALIGN((align)); \
...@@ -20,6 +24,7 @@ ...@@ -20,6 +24,7 @@
VMLINUX_SYMBOL(__start_rodata) = .; \ VMLINUX_SYMBOL(__start_rodata) = .; \
*(.rodata) *(.rodata.*) \ *(.rodata) *(.rodata.*) \
*(__vermagic) /* Kernel version magic */ \ *(__vermagic) /* Kernel version magic */ \
*(__markers_strings) /* Markers: strings */ \
} \ } \
\ \
.rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \
......
#ifndef _LINUX_MARKER_H
#define _LINUX_MARKER_H
/*
* Code markup for dynamic and static tracing.
*
* See Documentation/marker.txt.
*
* (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
*
* This file is released under the GPLv2.
* See the file COPYING for more details.
*/
#include <linux/types.h>
struct module;
struct marker;
/**
* marker_probe_func - Type of a marker probe function
* @mdata: pointer of type struct marker
* @private_data: caller site private data
* @fmt: format string
* @...: variable argument list
*
* Type of marker probe functions. They receive the mdata and need to parse the
* format string to recover the variable argument list.
*/
typedef void marker_probe_func(const struct marker *mdata,
void *private_data, const char *fmt, ...);
struct marker {
const char *name; /* Marker name */
const char *format; /* Marker format string, describing the
* variable argument list.
*/
char state; /* Marker state. */
marker_probe_func *call;/* Probe handler function pointer */
void *private; /* Private probe data */
} __attribute__((aligned(8)));
#ifdef CONFIG_MARKERS
/*
* Note : the empty asm volatile with read constraint is used here instead of a
* "used" attribute to fix a gcc 4.1.x bug.
* Make sure the alignment of the structure in the __markers section will
* not add unwanted padding between the beginning of the section and the
* structure. Force alignment to the same alignment as the section start.
*/
#define __trace_mark(name, call_data, format, args...) \
do { \
static const char __mstrtab_name_##name[] \
__attribute__((section("__markers_strings"))) \
= #name; \
static const char __mstrtab_format_##name[] \
__attribute__((section("__markers_strings"))) \
= format; \
static struct marker __mark_##name \
__attribute__((section("__markers"), aligned(8))) = \
{ __mstrtab_name_##name, __mstrtab_format_##name, \
0, __mark_empty_function, NULL }; \
asm volatile("" : : "i" (&__mark_##name)); \
__mark_check_format(format, ## args); \
if (unlikely(__mark_##name.state)) { \
preempt_disable(); \
(*__mark_##name.call) \
(&__mark_##name, call_data, \
format, ## args); \
preempt_enable(); \
} \
} while (0)
extern void marker_update_probe_range(struct marker *begin,
struct marker *end, struct module *probe_module, int *refcount);
#else /* !CONFIG_MARKERS */
#define __trace_mark(name, call_data, format, args...) \
__mark_check_format(format, ## args)
static inline void marker_update_probe_range(struct marker *begin,
struct marker *end, struct module *probe_module, int *refcount)
{ }
#endif /* CONFIG_MARKERS */
/**
* trace_mark - Marker
* @name: marker name, not quoted.
* @format: format string
* @args...: variable argument list
*
* Places a marker.
*/
#define trace_mark(name, format, args...) \
__trace_mark(name, NULL, format, ## args)
#define MARK_MAX_FORMAT_LEN 1024
/**
* MARK_NOARGS - Format string for a marker with no argument.
*/
#define MARK_NOARGS " "
/* To be used for string format validity checking with gcc */
static inline void __printf(1, 2) __mark_check_format(const char *fmt, ...)
{
}
extern marker_probe_func __mark_empty_function;
/*
* Connect a probe to a marker.
* private data pointer must be a valid allocated memory address, or NULL.
*/
extern int marker_probe_register(const char *name, const char *format,
marker_probe_func *probe, void *private);
/*
* Returns the private data given to marker_probe_register.
*/
extern void *marker_probe_unregister(const char *name);
/*
* Unregister a marker by providing the registered private data.
*/
extern void *marker_probe_unregister_private_data(void *private);
extern int marker_arm(const char *name);
extern int marker_disarm(const char *name);
extern void *marker_get_private_data(const char *name);
#endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/marker.h>
#include <asm/local.h> #include <asm/local.h>
#include <asm/module.h> #include <asm/module.h>
...@@ -354,6 +355,10 @@ struct module ...@@ -354,6 +355,10 @@ struct module
/* The command line arguments (may be mangled). People like /* The command line arguments (may be mangled). People like
keeping pointers to this stuff */ keeping pointers to this stuff */
char *args; char *args;
#ifdef CONFIG_MARKERS
struct marker *markers;
unsigned int num_markers;
#endif
}; };
#ifndef MODULE_ARCH_INIT #ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {} #define MODULE_ARCH_INIT {}
...@@ -457,6 +462,8 @@ int unregister_module_notifier(struct notifier_block * nb); ...@@ -457,6 +462,8 @@ int unregister_module_notifier(struct notifier_block * nb);
extern void print_modules(void); extern void print_modules(void);
extern void module_update_markers(struct module *probe_module, int *refcount);
#else /* !CONFIG_MODULES... */ #else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym) #define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym) #define EXPORT_SYMBOL_GPL(sym)
...@@ -556,6 +563,11 @@ static inline void print_modules(void) ...@@ -556,6 +563,11 @@ static inline void print_modules(void)
{ {
} }
static inline void module_update_markers(struct module *probe_module,
int *refcount)
{
}
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
struct device_driver; struct device_driver;
......
...@@ -40,4 +40,10 @@ config KPROBES ...@@ -40,4 +40,10 @@ config KPROBES
for kernel debugging, non-intrusive instrumentation and testing. for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N". If in doubt, say "N".
config MARKERS
bool "Activate markers"
help
Place an empty function call at each marker site. Can be
dynamically changed for a probe function.
endif # INSTRUMENTATION endif # INSTRUMENTATION
...@@ -55,6 +55,7 @@ obj-$(CONFIG_RELAY) += relay.o ...@@ -55,6 +55,7 @@ obj-$(CONFIG_RELAY) += relay.o
obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
obj-$(CONFIG_MARKERS) += marker.o
ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
......
This diff is collapsed.
...@@ -1673,6 +1673,8 @@ static struct module *load_module(void __user *umod, ...@@ -1673,6 +1673,8 @@ static struct module *load_module(void __user *umod,
unsigned int unusedcrcindex; unsigned int unusedcrcindex;
unsigned int unusedgplindex; unsigned int unusedgplindex;
unsigned int unusedgplcrcindex; unsigned int unusedgplcrcindex;
unsigned int markersindex;
unsigned int markersstringsindex;
struct module *mod; struct module *mod;
long err = 0; long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
...@@ -1939,6 +1941,9 @@ static struct module *load_module(void __user *umod, ...@@ -1939,6 +1941,9 @@ static struct module *load_module(void __user *umod,
add_taint_module(mod, TAINT_FORCED_MODULE); add_taint_module(mod, TAINT_FORCED_MODULE);
} }
#endif #endif
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
/* Now do relocations. */ /* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) { for (i = 1; i < hdr->e_shnum; i++) {
...@@ -1961,6 +1966,11 @@ static struct module *load_module(void __user *umod, ...@@ -1961,6 +1966,11 @@ static struct module *load_module(void __user *umod,
if (err < 0) if (err < 0)
goto cleanup; goto cleanup;
} }
#ifdef CONFIG_MARKERS
mod->markers = (void *)sechdrs[markersindex].sh_addr;
mod->num_markers =
sechdrs[markersindex].sh_size / sizeof(*mod->markers);
#endif
/* Find duplicate symbols */ /* Find duplicate symbols */
err = verify_export_symbols(mod); err = verify_export_symbols(mod);
...@@ -1979,6 +1989,11 @@ static struct module *load_module(void __user *umod, ...@@ -1979,6 +1989,11 @@ static struct module *load_module(void __user *umod,
add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
#ifdef CONFIG_MARKERS
if (!mod->taints)
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers, NULL, NULL);
#endif
err = module_finalize(hdr, sechdrs, mod); err = module_finalize(hdr, sechdrs, mod);
if (err < 0) if (err < 0)
goto cleanup; goto cleanup;
...@@ -2570,3 +2585,18 @@ EXPORT_SYMBOL(module_remove_driver); ...@@ -2570,3 +2585,18 @@ EXPORT_SYMBOL(module_remove_driver);
void struct_module(struct module *mod) { return; } void struct_module(struct module *mod) { return; }
EXPORT_SYMBOL(struct_module); EXPORT_SYMBOL(struct_module);
#endif #endif
#ifdef CONFIG_MARKERS
void module_update_markers(struct module *probe_module, int *refcount)
{
struct module *mod;
mutex_lock(&module_mutex);
list_for_each_entry(mod, &modules, list)
if (!mod->taints)
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers,
probe_module, refcount);
mutex_unlock(&module_mutex);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment