lkml.org 
[lkml]   [2007]   [Feb]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 02/05] Linux Kernel Markers, architecture independant code.
    Date
    Linux Kernel Markers, architecture independant code.

    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

    --- a/include/asm-generic/vmlinux.lds.h
    +++ b/include/asm-generic/vmlinux.lds.h
    @@ -121,6 +121,19 @@
    __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
    *(__ksymtab_strings) \
    } \
    + /* Kernel markers : pointers */ \
    + .markers : AT(ADDR(.markers) - LOAD_OFFSET) { \
    + VMLINUX_SYMBOL(__start___markers) = .; \
    + *(.markers) \
    + VMLINUX_SYMBOL(__stop___markers) = .; \
    + } \
    + .markers.c : AT(ADDR(.markers.c) - LOAD_OFFSET) { \
    + VMLINUX_SYMBOL(__start___markers_c) = .; \
    + *(.markers.c) \
    + VMLINUX_SYMBOL(__stop___markers_c) = .; \
    + } \
    + __end_rodata = .; \
    + . = ALIGN(4096); \
    \
    /* Built-in module parameters. */ \
    __param : AT(ADDR(__param) - LOAD_OFFSET) { \
    --- a/include/linux/module.h
    +++ b/include/linux/module.h
    @@ -356,6 +356,9 @@ struct module
    /* The command line arguments (may be mangled). People like
    keeping pointers to this stuff */
    char *args;
    +
    + const struct __mark_marker *markers;
    + unsigned int num_markers;
    };

    /* FIXME: It'd be nice to isolate modules during init, too, so they
    @@ -469,6 +472,7 @@ extern void print_modules(void);
    struct device_driver;
    void module_add_driver(struct module *, struct device_driver *);
    void module_remove_driver(struct device_driver *);
    +extern void list_modules(void);

    #else /* !CONFIG_MODULES... */
    #define EXPORT_SYMBOL(sym)
    --- /dev/null
    +++ b/include/linux/marker.h
    @@ -0,0 +1,97 @@
    +#ifndef _LINUX_MARKER_H
    +#define _LINUX_MARKER_H
    +
    +/*
    + * marker.h
    + *
    + * Code markup for dynamic and static tracing.
    + *
    + * Example :
    + *
    + * MARK(subsystem_event, "%d %s %p[struct task_struct]",
    + * someint, somestring, current);
    + * Where :
    + * - Subsystem is the name of your subsystem.
    + * - event is the name of the event to mark.
    + * - "%d %s %p[struct task_struct]" is the formatted string for printk.
    + * - someint is an integer.
    + * - somestring is a char pointer.
    + * - current is a pointer to a struct task_struct.
    + *
    + * - Dynamically overridable function call based on marker mechanism
    + * from Frank Ch. Eigler <fche@redhat.com>.
    + * - Thanks to Jeremy Fitzhardinge <jeremy@goop.org> for his constructive
    + * criticism about gcc optimization related issues.
    + *
    + * The marker mechanism supports multiple instances of the same marker.
    + * Markers can be put in inline functions, inlined static functions and
    + * unrolled loops.
    + *
    + * Note : It is safe to put markers within preempt-safe code : preempt_enable()
    + * will not call the scheduler due to the tests in preempt_schedule().
    + *
    + * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    + *
    + * This file is released under the GPLv2.
    + * See the file COPYING for more details.
    + */
    +
    +#ifndef __ASSEMBLY__
    +
    +typedef void marker_probe_func(const char *fmt, ...);
    +
    +enum marker_type { MARKER_GENERIC, MARKER_OPTIMIZED };
    +
    +struct __mark_marker_c {
    + const char *name;
    + marker_probe_func **call;
    + const char *format;
    + enum marker_type type;
    +} __attribute__((packed));
    +
    +struct __mark_marker {
    + const struct __mark_marker_c *cmark;
    + void *enable;
    +} __attribute__((packed));
    +
    +#ifdef CONFIG_MARKERS_ENABLE_OPTIMIZATION
    +#include <asm/marker.h>
    +#endif
    +
    +#include <asm-generic/marker.h>
    +
    +#define MARK_NOARGS " "
    +#define MARK_MAX_FORMAT_LEN 1024
    +
    +#ifndef CONFIG_MARKERS
    +#define GEN_MARK(name, format, args...) \
    + __mark_check_format(format, ## args)
    +#endif
    +
    +#ifndef MARK
    +#define MARK GEN_MARK
    +#define MARK_ENABLE_TYPE GEN_MARK_ENABLE_TYPE
    +#define MARK_ENABLE_IMMEDIATE_OFFSET GEN_MARK_ENABLE_IMMEDIATE_OFFSET
    +#endif
    +
    +/* Dereference enable as lvalue from a pointer to its instruction */
    +#define MARK_ENABLE(a) \
    + *(MARK_ENABLE_TYPE*)((char*)a+MARK_ENABLE_IMMEDIATE_OFFSET)
    +
    +#define GEN_MARK_ENABLE(a) \
    + *(GEN_MARK_ENABLE_TYPE*)((char*)a+GEN_MARK_ENABLE_IMMEDIATE_OFFSET)
    +
    +static inline __attribute__ ((format (printf, 1, 2)))
    +void __mark_check_format(const char *fmt, ...)
    +{ }
    +
    +extern marker_probe_func __mark_empty_function;
    +
    +extern int marker_set_probe(const char *name, const char *format,
    + marker_probe_func *probe);
    +
    +extern int marker_remove_probe(marker_probe_func *probe);
    +extern int marker_list_probe(marker_probe_func *probe);
    +
    +#endif
    +#endif
    --- a/kernel/module.c
    +++ b/kernel/module.c
    @@ -138,6 +138,8 @@ extern const unsigned long __start___kcrctab_gpl[];
    extern const unsigned long __start___kcrctab_gpl_future[];
    extern const unsigned long __start___kcrctab_unused[];
    extern const unsigned long __start___kcrctab_unused_gpl[];
    +extern const struct __mark_marker __start___markers[];
    +extern const struct __mark_marker __stop___markers[];

    #ifndef CONFIG_MODVERSIONS
    #define symversion(base, idx) NULL
    @@ -298,6 +300,214 @@ static struct module *find_module(const char *name)
    return NULL;
    }

    +#ifdef CONFIG_MARKERS
    +void __mark_empty_function(const char *fmt, ...)
    +{
    +}
    +EXPORT_SYMBOL(__mark_empty_function);
    +
    +#ifdef MARK_POLYMORPHIC
    +static int marker_set_ins_enable(void *address, char enable)
    +{
    +#ifdef CONFIG_X86_32
    + return arch_marker_set_ins_enable(address, enable);
    +#else
    + char newi[MARK_ENABLE_IMMEDIATE_OFFSET+1];
    + int size = MARK_ENABLE_IMMEDIATE_OFFSET+sizeof(MARK_ENABLE_TYPE);
    +
    + memcpy(newi, address, size);
    + MARK_ENABLE(&newi[0]) = enable;
    + memcpy(address, newi, size);
    + flush_icache_range((unsigned long)address, size);
    + return 0;
    +#endif //CONFIG_X86_32
    +}
    +#else
    +static int marker_set_ins_enable(void *address, char enable)
    +{
    + return -EPERM;
    +}
    +#endif //MARK_POLYMORPHIC
    +
    +static int marker_set_gen_enable(void *address, char enable)
    +{
    + GEN_MARK_ENABLE(address) = enable;
    + return 0;
    +}
    +
    +static int marker_set_enable(void *address, char enable, enum marker_type type)
    +{
    + if (type == MARKER_OPTIMIZED)
    + return marker_set_ins_enable(address, enable);
    + else
    + return marker_set_gen_enable(address, enable);
    +}
    +
    +/* enable and function address are set out of order, and it's ok :
    + * the state is always coherent. */
    +static int marker_set_probe_range(const char *name,
    + const char *format,
    + marker_probe_func *probe,
    + const struct __mark_marker *begin,
    + const struct __mark_marker *end)
    +{
    + const struct __mark_marker *iter;
    + int found = 0;
    +
    + for (iter = begin; iter < end; iter++) {
    + if (strcmp(name, iter->cmark->name) == 0) {
    + if (format
    + && strcmp(format, iter->cmark->format) != 0) {
    + printk(KERN_NOTICE
    + "Format mismatch for probe %s "
    + "(%s), marker (%s)\n",
    + name,
    + format,
    + iter->cmark->format);
    + continue;
    + }
    + if (probe == __mark_empty_function) {
    + if (*iter->cmark->call
    + != __mark_empty_function) {
    + *iter->cmark->call =
    + __mark_empty_function;
    + }
    + marker_set_enable(iter->enable, 0,
    + iter->cmark->type);
    + } else {
    + if (*iter->cmark->call
    + != __mark_empty_function) {
    + if (*iter->cmark->call != probe) {
    + printk(KERN_NOTICE
    + "Marker %s busy, "
    + "probe %p already "
    + "installed\n",
    + name,
    + *iter->cmark->call);
    + continue;
    + }
    + } else {
    + found++;
    + *iter->cmark->call = probe;
    + }
    + /* Can have many enables for one function */
    + marker_set_enable(iter->enable, 1,
    + iter->cmark->type);
    + }
    + found++;
    + }
    + }
    + return found;
    +}
    +
    +static int marker_remove_probe_range(marker_probe_func *probe,
    + const struct __mark_marker *begin,
    + const struct __mark_marker *end)
    +{
    + const struct __mark_marker *iter;
    + int found = 0;
    +
    + for (iter = begin; iter < end; iter++) {
    + if (*iter->cmark->call == probe) {
    + marker_set_enable(iter->enable, 0,
    + iter->cmark->type);
    + *iter->cmark->call = __mark_empty_function;
    + found++;
    + }
    + }
    + return found;
    +}
    +
    +static int marker_list_probe_range(marker_probe_func *probe,
    + const struct __mark_marker *begin,
    + const struct __mark_marker *end)
    +{
    + const struct __mark_marker *iter;
    + int found = 0;
    +
    + for (iter = begin; iter < end; iter++) {
    + if (probe)
    + if (probe != *iter->cmark->call) continue;
    + printk("name %s \n", iter->cmark->name);
    + if (iter->cmark->type == MARKER_OPTIMIZED)
    + printk(" enable %u optimized ",
    + MARK_ENABLE(iter->enable));
    + else
    + printk(" enable %u generic ",
    + GEN_MARK_ENABLE(iter->enable));
    + printk(" func 0x%p format \"%s\"\n",
    + *iter->cmark->call, iter->cmark->format);
    + found++;
    + }
    + return found;
    +}
    +/* markers use the modlist_lock to to synchronise */
    +int marker_set_probe(const char *name, const char *format,
    + marker_probe_func *probe)
    +{
    + struct module *mod;
    + int found = 0;
    +
    + mutex_lock(&module_mutex);
    + /* Core kernel markers */
    + found += marker_set_probe_range(name, format, probe,
    + __start___markers, __stop___markers);
    + /* Markers in modules. */
    + list_for_each_entry(mod, &modules, list) {
    + if (!mod->taints)
    + found += marker_set_probe_range(name, format, probe,
    + mod->markers, mod->markers+mod->num_markers);
    + }
    + mutex_unlock(&module_mutex);
    + return found;
    +}
    +EXPORT_SYMBOL(marker_set_probe);
    +
    +int marker_remove_probe(marker_probe_func *probe)
    +{
    + struct module *mod;
    + int found = 0;
    +
    + mutex_lock(&module_mutex);
    + /* Core kernel markers */
    + found += marker_remove_probe_range(probe,
    + __start___markers, __stop___markers);
    + /* Markers in modules. */
    + list_for_each_entry(mod, &modules, list) {
    + if (!mod->taints)
    + found += marker_remove_probe_range(probe,
    + mod->markers, mod->markers+mod->num_markers);
    + }
    + mutex_unlock(&module_mutex);
    + return found;
    +}
    +EXPORT_SYMBOL(marker_remove_probe);
    +
    +int marker_list_probe(marker_probe_func *probe)
    +{
    + struct module *mod;
    + int found = 0;
    +
    + mutex_lock(&module_mutex);
    + /* Core kernel markers */
    + printk("Listing kernel markers\n");
    + found += marker_list_probe_range(probe,
    + __start___markers, __stop___markers);
    + /* Markers in modules. */
    + printk("Listing module markers\n");
    + list_for_each_entry(mod, &modules, list) {
    + if (!mod->taints) {
    + printk("Listing markers for module %s\n", mod->name);
    + found += marker_list_probe_range(probe,
    + mod->markers, mod->markers+mod->num_markers);
    + }
    + }
    + mutex_unlock(&module_mutex);
    + return found;
    +}
    +EXPORT_SYMBOL(marker_list_probe);
    +#endif
    +
    #ifdef CONFIG_SMP
    /* Number of blocks used and allocated. */
    static unsigned int pcpu_num_used, pcpu_num_allocated;
    @@ -1561,6 +1773,7 @@ static struct module *load_module(void __user *umod,
    unsigned int unusedcrcindex;
    unsigned int unusedgplindex;
    unsigned int unusedgplcrcindex;
    + unsigned int markersindex;
    struct module *mod;
    long err = 0;
    void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
    @@ -1657,6 +1870,7 @@ static struct module *load_module(void __user *umod,
    #ifdef ARCH_UNWIND_SECTION_NAME
    unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
    #endif
    + markersindex = find_sec(hdr, sechdrs, secstrings, ".markers");

    /* Don't keep modinfo section */
    sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
    @@ -1667,6 +1881,13 @@ static struct module *load_module(void __user *umod,
    #endif
    if (unwindex)
    sechdrs[unwindex].sh_flags |= SHF_ALLOC;
    +#ifdef CONFIG_MARKERS
    + if (markersindex)
    + sechdrs[markersindex].sh_flags |= SHF_ALLOC;
    +#else
    + if (markersindex)
    + sechdrs[markersindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
    +#endif

    /* Check module struct version now, before we try to use module. */
    if (!check_modstruct_version(sechdrs, versindex, mod)) {
    @@ -1803,6 +2024,11 @@ static struct module *load_module(void __user *umod,
    mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
    if (gplfuturecrcindex)
    mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
    + if (markersindex) {
    + mod->markers = (void *)sechdrs[markersindex].sh_addr;
    + mod->num_markers =
    + sechdrs[markersindex].sh_size / sizeof(*mod->markers);
    + }

    mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
    if (unusedcrcindex)
    @@ -2243,6 +2471,26 @@ const struct seq_operations modules_op = {
    .show = m_show
    };

    +void list_modules(void)
    +{
    + /* Enumerate loaded modules */
    + struct list_head *i;
    + struct module *mod;
    + unsigned long refcount = 0;
    +
    + mutex_lock(&module_mutex);
    + list_for_each(i, &modules) {
    + mod = list_entry(i, struct module, list);
    +#ifdef CONFIG_MODULE_UNLOAD
    + refcount = local_read(&mod->ref[0].count);
    +#endif //CONFIG_MODULE_UNLOAD
    + MARK(list_modules, "%s %d[enum module_state] %lu",
    + mod->name, mod->state, refcount);
    + }
    + mutex_unlock(&module_mutex);
    +}
    +EXPORT_SYMBOL(list_modules);
    +
    /* Given an address, look for it in the module exception tables. */
    const struct exception_table_entry *search_module_extables(unsigned long addr)
    {
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2007-02-11 21:11    [W:0.041 / U:1.072 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site