diff options
-rw-r--r-- | include/linux/dynamic_debug.h | 17 | ||||
-rw-r--r-- | kernel/module.c | 2 | ||||
-rw-r--r-- | lib/dynamic_debug.c | 49 |
3 files changed, 67 insertions, 1 deletions
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index bf1b0fc..4697e4b 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -44,6 +44,9 @@ extern int ddebug_remove_module(const char *mod_name); extern __printf(2, 3) int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...); +extern int ddebug_dyndbg_module_param_cb(char *param, char *val, + const char *modname); + struct device; extern __printf(3, 4) @@ -94,11 +97,25 @@ do { \ #else +#include <linux/string.h> +#include <linux/errno.h> + static inline int ddebug_remove_module(const char *mod) { return 0; } +static inline int ddebug_dyndbg_module_param_cb(char *param, char *val, + const char *modname) +{ + if (strstr(param, "dyndbg")) { + pr_warn("dyndbg supported only in " + "CONFIG_DYNAMIC_DEBUG builds\n"); + return 0; /* allow and ignore */ + } + return -EINVAL; +} + #define dynamic_pr_debug(fmt, ...) \ do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0) #define dynamic_dev_dbg(dev, fmt, ...) \ diff --git a/kernel/module.c b/kernel/module.c index 78ac6ec..a4e6097 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2953,7 +2953,7 @@ static struct module *load_module(void __user *umod, /* Module is ready to execute: parsing args may do that. */ err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, - -32768, 32767, NULL); + -32768, 32767, &ddebug_dyndbg_module_param_cb); if (err < 0) goto unlink; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8675717..8fba401 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -862,6 +862,41 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n, } EXPORT_SYMBOL_GPL(ddebug_add_module); +/* handle both dyndbg=".." and $module.dyndbg=".." params at boot */ +static int ddebug_dyndbg_boot_param_cb(char *param, char *val, + const char *unused) +{ + const char *modname = NULL; + char *sep; + + sep = strchr(param, '.'); + if (sep) { + *sep = '\0'; + modname = param; + param = sep + 1; + } + if (strcmp(param, "dyndbg")) + return 0; /* skip all other params w/o error */ + + vpr_info("module: %s %s=\"%s\"\n", modname, param, val); + + ddebug_exec_queries(val ? val : "+p"); + return 0; /* query failure shouldnt stop module load */ +} + +/* handle dyndbg args to modprobe */ +int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *doing) +{ + if (strcmp(param, "dyndbg")) + return -ENOENT; + + vpr_info("module: %s %s=\"%s\"\n", doing, param, val); + + ddebug_exec_queries((val ? val : "+p")); + + return 0; /* query failure shouldnt stop module load */ +} + static void ddebug_table_free(struct ddebug_table *dt) { list_del_init(&dt->link); @@ -929,6 +964,7 @@ static int __init dynamic_debug_init(void) { struct _ddebug *iter, *iter_start; const char *modname = NULL; + char *cmdline; int ret = 0; int n = 0; @@ -967,6 +1003,18 @@ static int __init dynamic_debug_init(void) /* keep tables even on ddebug_query parse error */ ret = 0; } + /* now that ddebug tables are loaded, process all boot args + * again to find and activate queries given in dyndbg params. + * While this has already been done for known boot params, it + * ignored the unknown ones (dyndbg in particular). Reusing + * parse_args avoids ad-hoc parsing. This will also attempt + * to activate queries for not-yet-loaded modules, which is + * slightly noisy if verbose, but harmless. + */ + cmdline = kstrdup(saved_command_line, GFP_KERNEL); + parse_args("dyndbg params", cmdline, NULL, + 0, 0, 0, &ddebug_dyndbg_boot_param_cb); + kfree(cmdline); out_free: if (ret) @@ -977,5 +1025,6 @@ out_free: } /* Allow early initialization for boot messages via boot param */ arch_initcall(dynamic_debug_init); + /* Debugfs setup must be done later */ module_init(dynamic_debug_init_debugfs); |