Skip to content

Commit

Permalink
driver core: basic infrastructure for per-module dynamic debug messages
Browse files Browse the repository at this point in the history
Base infrastructure to enable per-module debug messages.

I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes
control of debugging statements on a per-module basis in one /proc file,
currently, <debugfs>/dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG,
is not set, debugging statements can still be enabled as before, often by
defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no
affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set.

The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That
is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls
can be dynamically enabled/disabled on a per-module basis.

Future plans include extending this functionality to subsystems, that define 
their own debug levels and flags.

Usage:

Dynamic debugging is controlled by the debugfs file, 
<debugfs>/dynamic_printk/modules. This file contains a list of the modules that
can be enabled. The format of the file is as follows:

	<module_name> <enabled=0/1>
		.
		.
		.

	<module_name> : Name of the module in which the debug call resides
	<enabled=0/1> : whether the messages are enabled or not

For example:

	snd_hda_intel enabled=0
	fixup enabled=1
	driver enabled=0

Enable a module:

	$echo "set enabled=1 <module_name>" > dynamic_printk/modules

Disable a module:

	$echo "set enabled=0 <module_name>" > dynamic_printk/modules

Enable all modules:

	$echo "set enabled=1 all" > dynamic_printk/modules

Disable all modules:

	$echo "set enabled=0 all" > dynamic_printk/modules

Finally, passing "dynamic_printk" at the command line enables
debugging for all modules. This mode can be turned off via the above
disable command.

[gkh: minor cleanups and tweaks to make the build work quietly]

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
jibaron authored and gregkh committed Oct 16, 2008
1 parent 33376c1 commit 346e15b
Show file tree
Hide file tree
Showing 14 changed files with 700 additions and 7 deletions.
5 changes: 5 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1713,6 +1713,11 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
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=
[KNL] debug: print fatal signals
print-fatal-signals=1: print segfault info to
Expand Down
10 changes: 9 additions & 1 deletion include/asm-generic/vmlinux.lds.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,15 @@
CPU_DISCARD(init.data) \
CPU_DISCARD(init.rodata) \
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 \
*(.init.text) \
Expand Down
6 changes: 5 additions & 1 deletion include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,11 @@ extern const char *dev_driver_string(const struct device *dev);
#define dev_info(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)

#ifdef DEBUG
#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
#define dev_dbg(dev, format, ...) do { \
dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...) \
dev_printk(KERN_DEBUG , dev , format , ## arg)
#else
Expand Down
93 changes: 93 additions & 0 deletions include/linux/dynamic_printk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#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
7 changes: 6 additions & 1 deletion include/linux/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/log2.h>
#include <linux/typecheck.h>
#include <linux/ratelimit.h>
#include <linux/dynamic_printk.h>
#include <asm/byteorder.h>
#include <asm/bug.h>

Expand Down Expand Up @@ -303,8 +304,12 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
#define pr_info(fmt, arg...) \
printk(KERN_INFO fmt, ##arg)

#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG)
#define pr_debug(fmt, ...) do { \
dynamic_pr_debug(fmt, ##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define pr_debug(fmt, arg...) \
printk(KERN_DEBUG fmt, ##arg)
#else
Expand Down
1 change: 0 additions & 1 deletion include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@ struct module
/* Reference counts */
struct module_ref ref[NR_CPUS];
#endif

};
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
Expand Down
31 changes: 31 additions & 0 deletions kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
mutex_lock(&module_mutex);
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
unregister_dynamic_debug_module(mod->name);
free_module(mod);

out:
Expand Down Expand Up @@ -1783,6 +1784,33 @@ static inline void add_kallsyms(struct module *mod,
}
#endif /* CONFIG_KALLSYMS */

#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG
static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex)
{
struct mod_debug *debug_info;
unsigned long pos, end;
unsigned int num_verbose;

pos = sechdrs[verboseindex].sh_addr;
num_verbose = sechdrs[verboseindex].sh_size /
sizeof(struct mod_debug);
end = pos + (num_verbose * sizeof(struct mod_debug));

for (; pos < end; pos += sizeof(struct mod_debug)) {
debug_info = (struct mod_debug *)pos;
register_dynamic_debug_module(debug_info->modname,
debug_info->type, debug_info->logical_modname,
debug_info->flag_names, debug_info->hash,
debug_info->hash2);
}
}
#else
static inline void dynamic_printk_setup(Elf_Shdr *sechdrs,
unsigned int verboseindex)
{
}
#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */

static void *module_alloc_update_bounds(unsigned long size)
{
void *ret = module_alloc(size);
Expand Down Expand Up @@ -1831,6 +1859,7 @@ static noinline struct module *load_module(void __user *umod,
#endif
unsigned int markersindex;
unsigned int markersstringsindex;
unsigned int verboseindex;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
Expand Down Expand Up @@ -2117,6 +2146,7 @@ static noinline struct module *load_module(void __user *umod,
markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");
verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");

/* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
Expand Down Expand Up @@ -2167,6 +2197,7 @@ static noinline struct module *load_module(void __user *umod,
marker_update_probe_range(mod->markers,
mod->markers + mod->num_markers);
#endif
dynamic_printk_setup(sechdrs, verboseindex);
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
Expand Down
55 changes: 55 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,61 @@ menuconfig BUILD_DOCSRC

Say N if you are unsure.

config DYNAMIC_PRINTK_DEBUG
bool "Enable dynamic printk() call support"
default n
depends on PRINTK
select PRINTK_DEBUG
help

Compiles debug level messages into the kernel, which would not
otherwise be available at runtime. These messages can then be
enabled/disabled on a per module basis. This mechanism implicitly
enables all pr_debug() and dev_dbg() calls. The impact of this
compile option is a larger kernel text size of about 2%.

Usage:

Dynamic debugging is controlled by the debugfs file,
dynamic_printk/modules. This file contains a list of the modules that
can be enabled. The format of the file is the module name, followed
by a set of flags that can be enabled. The first flag is always the
'enabled' flag. For example:

<module_name> <enabled=0/1>
.
.
.

<module_name> : Name of the module in which the debug call resides
<enabled=0/1> : whether the messages are enabled or not

From a live system:

snd_hda_intel enabled=0
fixup enabled=0
driver enabled=0

Enable a module:

$echo "set enabled=1 <module_name>" > dynamic_printk/modules

Disable a module:

$echo "set enabled=0 <module_name>" > dynamic_printk/modules

Enable all modules:

$echo "set enabled=1 all" > dynamic_printk/modules

Disable all modules:

$echo "set enabled=0 all" > dynamic_printk/modules

Finally, passing "dynamic_printk" at the command line enables
debugging for all modules. This mode can be turned off via the above
disable command.

source "samples/Kconfig"

source "lib/Kconfig.kgdb"
2 changes: 2 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o

obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o

obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o

hostprogs-y := gen_crc32table
clean-files := crc32table.h

Expand Down
Loading

0 comments on commit 346e15b

Please sign in to comment.