Commit e9d376f0 authored by Jason Baron's avatar Jason Baron Committed by Greg Kroah-Hartman

dynamic debug: combine dprintk and dynamic printk

This patch combines Greg Bank's dprintk() work with the existing dynamic
printk patchset, we are now calling it 'dynamic debug'.

The new feature of this patchset is a richer /debugfs control file interface,
(an example output from my system is at the bottom), which allows fined grained
control over the the debug output. The output can be controlled by function,
file, module, format string, and line number.

for example, enabled all debug messages in module 'nf_conntrack':

echo -n 'module nf_conntrack +p' > /mnt/debugfs/dynamic_debug/control

to disable them:

echo -n 'module nf_conntrack -p' > /mnt/debugfs/dynamic_debug/control

A further explanation can be found in the documentation patch.
Signed-off-by: default avatarGreg Banks <gnb@sgi.com>
Signed-off-by: default avatarJason Baron <jbaron@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 095160ae
...@@ -1816,11 +1816,6 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1816,11 +1816,6 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration. autoconfiguration.
Ranges are in pairs (memory base and size). Ranges are in pairs (memory base and size).
dynamic_printk Enables pr_debug()/dev_dbg() calls if
CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled.
These can also be switched on/off via
<debugfs>/dynamic_printk/modules
print-fatal-signals= print-fatal-signals=
[KNL] debug: print fatal signals [KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to print-fatal-signals=1: print segfault info to
......
...@@ -80,6 +80,11 @@ ...@@ -80,6 +80,11 @@
VMLINUX_SYMBOL(__start___tracepoints) = .; \ VMLINUX_SYMBOL(__start___tracepoints) = .; \
*(__tracepoints) \ *(__tracepoints) \
VMLINUX_SYMBOL(__stop___tracepoints) = .; \ VMLINUX_SYMBOL(__stop___tracepoints) = .; \
/* implement dynamic printk debug */ \
. = ALIGN(8); \
VMLINUX_SYMBOL(__start___verbose) = .; \
*(__verbose) \
VMLINUX_SYMBOL(__stop___verbose) = .; \
LIKELY_PROFILE() \ LIKELY_PROFILE() \
BRANCH_PROFILE() BRANCH_PROFILE()
...@@ -309,15 +314,7 @@ ...@@ -309,15 +314,7 @@
CPU_DISCARD(init.data) \ CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \ CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.data) \ MEM_DISCARD(init.data) \
MEM_DISCARD(init.rodata) \ MEM_DISCARD(init.rodata)
/* implement dynamic printk debug */ \
VMLINUX_SYMBOL(__start___verbose_strings) = .; \
*(__verbose_strings) \
VMLINUX_SYMBOL(__stop___verbose_strings) = .; \
. = ALIGN(8); \
VMLINUX_SYMBOL(__start___verbose) = .; \
*(__verbose) \
VMLINUX_SYMBOL(__stop___verbose) = .;
#define INIT_TEXT \ #define INIT_TEXT \
*(.init.text) \ *(.init.text) \
......
...@@ -582,7 +582,7 @@ extern const char *dev_driver_string(const struct device *dev); ...@@ -582,7 +582,7 @@ extern const char *dev_driver_string(const struct device *dev);
#if defined(DEBUG) #if defined(DEBUG)
#define dev_dbg(dev, format, arg...) \ #define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg) dev_printk(KERN_DEBUG , dev , format , ## arg)
#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG) #elif defined(CONFIG_DYNAMIC_DEBUG)
#define dev_dbg(dev, format, ...) do { \ #define dev_dbg(dev, format, ...) do { \
dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
} while (0) } while (0)
......
#ifndef _DYNAMIC_DEBUG_H
#define _DYNAMIC_DEBUG_H
/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
* use independent hash functions, to reduce the chance of false positives.
*/
extern long long dynamic_debug_enabled;
extern long long dynamic_debug_enabled2;
/*
* An instance of this structure is created in a special
* ELF section at every dynamic debug callsite. At runtime,
* the special section is treated as an array of these.
*/
struct _ddebug {
/*
* These fields are used to drive the user interface
* for selecting and displaying debug callsites.
*/
const char *modname;
const char *function;
const char *filename;
const char *format;
char primary_hash;
char secondary_hash;
unsigned int lineno:24;
/*
* The flags field controls the behaviour at the callsite.
* The bits here are changed dynamically when the user
* writes commands to <debugfs>/dynamic_debug/ddebug
*/
#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */
#define _DPRINTK_FLAGS_DEFAULT 0
unsigned int flags:8;
} __attribute__((aligned(8)));
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
const char *modname);
#if defined(CONFIG_DYNAMIC_DEBUG)
extern int ddebug_remove_module(char *mod_name);
#define __dynamic_dbg_enabled(dd) ({ \
int __ret = 0; \
if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) && \
(dynamic_debug_enabled2 & (1LL << DEBUG_HASH2)))) \
if (unlikely(dd.flags)) \
__ret = 1; \
__ret; })
#define dynamic_pr_debug(fmt, ...) do { \
static struct _ddebug descriptor \
__used \
__attribute__((section("__verbose"), aligned(8))) = \
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \
printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
##__VA_ARGS__); \
} while (0)
#define dynamic_dev_dbg(dev, fmt, ...) do { \
static struct _ddebug descriptor \
__used \
__attribute__((section("__verbose"), aligned(8))) = \
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
if (__dynamic_dbg_enabled(descriptor)) \
dev_printk(KERN_DEBUG, dev, \
KBUILD_MODNAME ": " fmt, \
##__VA_ARGS__); \
} while (0)
#else
static inline int ddebug_remove_module(char *mod)
{
return 0;
}
#define dynamic_pr_debug(fmt, ...) do { } while (0)
#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
#endif
#endif
#ifndef _DYNAMIC_PRINTK_H
#define _DYNAMIC_PRINTK_H
#define DYNAMIC_DEBUG_HASH_BITS 6
#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS)
#define TYPE_BOOLEAN 1
#define DYNAMIC_ENABLED_ALL 0
#define DYNAMIC_ENABLED_NONE 1
#define DYNAMIC_ENABLED_SOME 2
extern int dynamic_enabled;
/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
* use independent hash functions, to reduce the chance of false positives.
*/
extern long long dynamic_printk_enabled;
extern long long dynamic_printk_enabled2;
struct mod_debug {
char *modname;
char *logical_modname;
char *flag_names;
int type;
int hash;
int hash2;
} __attribute__((aligned(8)));
int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
char *flags, int hash, int hash2);
#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
extern int unregister_dynamic_debug_module(char *mod_name);
extern int __dynamic_dbg_enabled_helper(char *modname, int type,
int value, int hash);
#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \
int __ret = 0; \
if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \
(dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \
__ret = __dynamic_dbg_enabled_helper(module, type, \
value, hash);\
__ret; })
#define dynamic_pr_debug(fmt, ...) do { \
static char mod_name[] \
__attribute__((section("__verbose_strings"))) \
= KBUILD_MODNAME; \
static struct mod_debug descriptor \
__used \
__attribute__((section("__verbose"), aligned(8))) = \
{ mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
0, 0, DEBUG_HASH)) \
printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \
##__VA_ARGS__); \
} while (0)
#define dynamic_dev_dbg(dev, format, ...) do { \
static char mod_name[] \
__attribute__((section("__verbose_strings"))) \
= KBUILD_MODNAME; \
static struct mod_debug descriptor \
__used \
__attribute__((section("__verbose"), aligned(8))) = \
{ mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\
if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \
0, 0, DEBUG_HASH)) \
dev_printk(KERN_DEBUG, dev, \
KBUILD_MODNAME ": " format, \
##__VA_ARGS__); \
} while (0)
#else
static inline int unregister_dynamic_debug_module(const char *mod_name)
{
return 0;
}
static inline int __dynamic_dbg_enabled_helper(char *modname, int type,
int value, int hash)
{
return 0;
}
#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; })
#define dynamic_pr_debug(fmt, ...) do { } while (0)
#define dynamic_dev_dbg(dev, format, ...) do { } while (0)
#endif
#endif
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/typecheck.h> #include <linux/typecheck.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/dynamic_printk.h> #include <linux/dynamic_debug.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/bug.h> #include <asm/bug.h>
...@@ -358,7 +358,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte) ...@@ -358,7 +358,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
#if defined(DEBUG) #if defined(DEBUG)
#define pr_debug(fmt, ...) \ #define pr_debug(fmt, ...) \
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#elif defined(CONFIG_DYNAMIC_PRINTK_DEBUG) #elif defined(CONFIG_DYNAMIC_DEBUG)
#define pr_debug(fmt, ...) do { \ #define pr_debug(fmt, ...) do { \
dynamic_pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ dynamic_pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \
} while (0) } while (0)
......
...@@ -822,7 +822,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, ...@@ -822,7 +822,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
/* Store the name of the last unloaded module for diagnostic purposes */ /* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
unregister_dynamic_debug_module(mod->name); ddebug_remove_module(mod->name);
free_module(mod); free_module(mod);
out: out:
...@@ -1827,19 +1827,13 @@ static inline void add_kallsyms(struct module *mod, ...@@ -1827,19 +1827,13 @@ static inline void add_kallsyms(struct module *mod,
} }
#endif /* CONFIG_KALLSYMS */ #endif /* CONFIG_KALLSYMS */
static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num) static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)
{ {
#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG #ifdef CONFIG_DYNAMIC_DEBUG
unsigned int i; if (ddebug_add_module(debug, num, debug->modname))
printk(KERN_ERR "dynamic debug error adding module: %s\n",
for (i = 0; i < num; i++) { debug->modname);
register_dynamic_debug_module(debug[i].modname, #endif
debug[i].type,
debug[i].logical_modname,
debug[i].flag_names,
debug[i].hash, debug[i].hash2);
}
#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */
} }
static void *module_alloc_update_bounds(unsigned long size) static void *module_alloc_update_bounds(unsigned long size)
...@@ -2213,12 +2207,13 @@ static noinline struct module *load_module(void __user *umod, ...@@ -2213,12 +2207,13 @@ static noinline struct module *load_module(void __user *umod,
add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
if (!mod->taints) { if (!mod->taints) {
struct mod_debug *debug; struct _ddebug *debug;
unsigned int num_debug; unsigned int num_debug;
debug = section_objs(hdr, sechdrs, secstrings, "__verbose", debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
sizeof(*debug), &num_debug); sizeof(*debug), &num_debug);
dynamic_printk_setup(debug, num_debug); if (debug)
dynamic_debug_setup(debug, num_debug);
} }
/* sechdrs[0].sh_size is always zero */ /* sechdrs[0].sh_size is always zero */
......
...@@ -847,7 +847,7 @@ config BUILD_DOCSRC ...@@ -847,7 +847,7 @@ config BUILD_DOCSRC
Say N if you are unsure. Say N if you are unsure.
config DYNAMIC_PRINTK_DEBUG config DYNAMIC_DEBUG
bool "Enable dynamic printk() call support" bool "Enable dynamic printk() call support"
default n default n
depends on PRINTK depends on PRINTK
......
...@@ -82,7 +82,7 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o ...@@ -82,7 +82,7 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o
obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o
obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
hostprogs-y := gen_crc32table hostprogs-y := gen_crc32table
clean-files := crc32table.h clean-files := crc32table.h
......
This diff is collapsed.
/*
* lib/dynamic_printk.c
*
* make pr_debug()/dev_dbg() calls runtime configurable based upon their
* their source module.
*
* Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
extern struct mod_debug __start___verbose[];
extern struct mod_debug __stop___verbose[];
struct debug_name {
struct hlist_node hlist;
struct hlist_node hlist2;
int hash1;
int hash2;
char *name;
int enable;
int type;
};
static int nr_entries;
static int num_enabled;
int dynamic_enabled = DYNAMIC_ENABLED_NONE;
static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] =
{ [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] =
{ [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT };
static DECLARE_MUTEX(debug_list_mutex);
/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
* use independent hash functions, to reduce the chance of false positives.
*/
long long dynamic_printk_enabled;
EXPORT_SYMBOL_GPL(dynamic_printk_enabled);
long long dynamic_printk_enabled2;
EXPORT_SYMBOL_GPL(dynamic_printk_enabled2);
/* returns the debug module pointer. */
static struct debug_name *find_debug_module(char *module_name)
{
int i;
struct hlist_head *head;
struct hlist_node *node;
struct debug_name *element;
element = NULL;
for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
head = &module_table[i];
hlist_for_each_entry_rcu(element, node, head, hlist)
if (!strcmp(element->name, module_name))
return element;
}
return NULL;
}
/* returns the debug module pointer. */
static struct debug_name *find_debug_module_hash(char *module_name, int hash)
{
struct hlist_head *head;
struct hlist_node *node;
struct debug_name *element;
element = NULL;
head = &module_table[hash];
hlist_for_each_entry_rcu(element, node, head, hlist)
if (!strcmp(element->name, module_name))
return element;
return NULL;
}
/* caller must hold mutex*/
static int __add_debug_module(char *mod_name, int hash, int hash2)
{
struct debug_name *new;
char *module_name;
int ret = 0;
if (find_debug_module(mod_name)) {
ret = -EINVAL;
goto out;
}
module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL);
if (!module_name) {
ret = -ENOMEM;
goto out;
}
module_name = strcpy(module_name, mod_name);
module_name[strlen(mod_name)] = '\0';
new = kzalloc(sizeof(struct debug_name), GFP_KERNEL);
if (!new) {
kfree(module_name);
ret = -ENOMEM;
goto out;
}
INIT_HLIST_NODE(&new->hlist);
INIT_HLIST_NODE(&new->hlist2);
new->name = module_name;
new->hash1 = hash;
new->hash2 = hash2;
hlist_add_head_rcu(&new->hlist, &module_table[hash]);
hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]);
nr_entries++;
out:
return ret;
}
int unregister_dynamic_debug_module(char *mod_name)
{
struct debug_name *element;
int ret = 0;
down(&debug_list_mutex);
element = find_debug_module(mod_name);
if (!element) {
ret = -EINVAL;
goto out;
}
hlist_del_rcu(&element->hlist);
hlist_del_rcu(&element->hlist2);
synchronize_rcu();
kfree(element->name);
if (element->enable)
num_enabled--;
kfree(element);
nr_entries--;
out:
up(&debug_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module);
int register_dynamic_debug_module(char *mod_name, int type, char *share_name,
char *flags, int hash, int hash2)
{
struct debug_name *elem;
int ret = 0;
down(&debug_list_mutex);
elem = find_debug_module(mod_name);
if (!elem) {
if (__add_debug_module(mod_name, hash, hash2))
goto out;
elem = find_debug_module(mod_name);
if (dynamic_enabled == DYNAMIC_ENABLED_ALL &&
!strcmp(mod_name, share_name)) {
elem->enable = true;
num_enabled++;
}
}
elem->type |= type;
out:
up(&debug_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(register_dynamic_debug_module);
int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash)
{
struct debug_name *elem;
int ret = 0;
if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
return 1;
rcu_read_lock();
elem = find_debug_module_hash(mod_name, hash);
if (elem && elem->enable)
ret = 1;
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper);
static void set_all(bool enable)
{
struct debug_name *e;
struct hlist_node *node;
int i;
long long enable_mask;
for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) {
if (module_table[i].first != NULL) {
hlist_for_each_entry(e, node, &module_table[i], hlist) {
e->enable = enable;
}
}
}
if (enable)
enable_mask = ULLONG_MAX;
else
enable_mask = 0;
dynamic_printk_enabled = enable_mask;
dynamic_printk_enabled2 = enable_mask;
}
static int disabled_hash(int i, bool first_table)
{
struct debug_name *e;
struct hlist_node *node;
if (first_table) {
hlist_for_each_entry(e, node, &module_table[i], hlist) {
if (e->enable)
return 0;
}
} else {
hlist_for_each_entry(e, node, &module_table2[i], hlist2) {
if (e->enable)
return 0;
}
}
return 1;
}
static ssize_t pr_debug_write(struct file *file, const char __user *buf,
size_t length, loff_t *ppos)
{
char *buffer, *s, *value_str, *setting_str;
int err, value;
struct debug_name *elem = NULL;
int all = 0;
if (length > PAGE_SIZE || length < 0)
return -EINVAL;
buffer = (char *)__get_free_page(GFP_KERNEL);
if (!buffer)
return -ENOMEM;
err = -EFAULT;
if (copy_from_user(buffer, buf, length))
goto out;
err = -EINVAL;
if (length < PAGE_SIZE)
buffer[length] = '\0';
else if (buffer[PAGE_SIZE-1])
goto out;
err = -EINVAL;
down(&debug_list_mutex);
if (strncmp("set", buffer, 3))
goto out_up;
s = buffer + 3;
setting_str = strsep(&s, "=");
if (s == NULL)
goto out_up;
setting_str = strstrip(setting_str);
value_str = strsep(&s, " ");
if (s == NULL)
goto out_up;
s = strstrip(s);
if (!strncmp(s, "all", 3))
all = 1;
else
elem = find_debug_module(s);
if (!strncmp(setting_str, "enable", 6)) {
value = !!simple_strtol(value_str, NULL, 10);
if (all) {
if (value) {
set_all(true);
num_enabled = nr_entries;
dynamic_enabled = DYNAMIC_ENABLED_ALL;
} else {
set_all(false);
num_enabled = 0;
dynamic_enabled = DYNAMIC_ENABLED_NONE;
}
err = 0;
} else if (elem) {
if (value && (elem->enable == 0)) {
dynamic_printk_enabled |= (1LL << elem->hash1);
dynamic_printk_enabled2 |= (1LL << elem->hash2);
elem->enable = 1;
num_enabled++;
dynamic_enabled = DYNAMIC_ENABLED_SOME;
err = 0;
printk(KERN_DEBUG
"debugging enabled for module %s\n",
elem->name);
} else if (!value && (elem->enable == 1)) {
elem->enable = 0;
num_enabled--;
if (disabled_hash(elem->hash1, true))
dynamic_printk_enabled &=
~(1LL << elem->hash1);
if (disabled_hash(elem->hash2, false))
dynamic_printk_enabled2 &=
~(1LL << elem->hash2);
if (num_enabled)
dynamic_enabled = DYNAMIC_ENABLED_SOME;
else
dynamic_enabled = DYNAMIC_ENABLED_NONE;
err = 0;
printk(KERN_DEBUG
"debugging disabled for module %s\n",
elem->name);
}
}
}
if (!err)
err = length;
out_up:
up(&debug_list_mutex);
out:
free_page((unsigned long)buffer);
return err;
}
static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos)
{
return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL;
}
static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (*pos >= DEBUG_HASH_TABLE_SIZE)
return NULL;
return pos;
}
static void pr_debug_seq_stop(struct seq_file *s, void *v)
{
/* Nothing to do */
}
static int pr_debug_seq_show(struct seq_file *s, void *v)
{
struct hlist_head *head;
struct hlist_node *node;
struct debug_name *elem;
unsigned int i = *(loff_t *) v;
rcu_read_lock();
head = &module_table[i];
hlist_for_each_entry_rcu(elem, node, head, hlist) {
seq_printf(s, "%s enabled=%d", elem->name, elem->enable);
seq_printf(s, "\n");
}
rcu_read_unlock();
return 0;
}
static struct seq_operations pr_debug_seq_ops = {
.start = pr_debug_seq_start,
.next = pr_debug_seq_next,
.stop = pr_debug_seq_stop,
.show = pr_debug_seq_show
};
static int pr_debug_open(struct inode *inode, struct file *filp)
{
return seq_open(filp, &pr_debug_seq_ops);
}
static const struct file_operations pr_debug_operations = {
.open = pr_debug_open,
.read = seq_read,
.write = pr_debug_write,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init dynamic_printk_init(void)
{
struct dentry *dir, *file;
struct mod_debug *iter;
unsigned long value;
dir = debugfs_create_dir("dynamic_printk", NULL);
if (!dir)
return -ENOMEM;
file = debugfs_create_file("modules", 0644, dir, NULL,
&pr_debug_operations);
if (!file) {
debugfs_remove(dir);
return -ENOMEM;
}
for (value = (unsigned long)__start___verbose;
value < (unsigned long)__stop___verbose;
value += sizeof(struct mod_debug)) {
iter = (struct mod_debug *)value;
register_dynamic_debug_module(iter->modname,
iter->type,
iter->logical_modname,
iter->flag_names, iter->hash, iter->hash2);
}
if (dynamic_enabled == DYNAMIC_ENABLED_ALL)
set_all(true);
return 0;
}
module_init(dynamic_printk_init);
/* may want to move this earlier so we can get traces as early as possible */
static int __init dynamic_printk_setup(char *str)
{
if (str)
return -ENOENT;
dynamic_enabled = DYNAMIC_ENABLED_ALL;
return 0;
}
/* Use early_param(), so we can get debug output as early as possible */
early_param("dynamic_printk", dynamic_printk_setup);
...@@ -66,7 +66,7 @@ void ...@@ -66,7 +66,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly; struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG) #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
/* PptpControlMessageType names */ /* PptpControlMessageType names */
const char *const pptp_msg_name[] = { const char *const pptp_msg_name[] = {
"UNKNOWN_MESSAGE", "UNKNOWN_MESSAGE",
......
...@@ -97,7 +97,7 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\ ...@@ -97,7 +97,7 @@ modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
#hash values #hash values
ifdef CONFIG_DYNAMIC_PRINTK_DEBUG ifdef CONFIG_DYNAMIC_DEBUG
debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
-D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
else else
......
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