13 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
15 #include <linux/kernel.h>
16 #include <linux/module.h>
19 #include <linux/types.h>
23 #include <linux/list.h>
24 #include <linux/sysctl.h>
25 #include <linux/ctype.h>
26 #include <linux/string.h>
30 #include <linux/slab.h>
33 #include <linux/sched.h>
34 #include <linux/device.h>
35 #include <linux/netdevice.h>
66 static inline const char *basename(
const char *
path)
69 return tail ? tail+1 :
path;
73 static inline const char *trim_prefix(
const char *
path)
77 if (
strncmp(path, __FILE__, skip))
93 static char *ddebug_describe_flags(
struct _ddebug *
dp,
char *
buf,
101 if (dp->
flags & opt_array[i].flag)
102 *p++ = opt_array[
i].opt_char;
110 #define vpr_info(fmt, ...) \
111 if (verbose) do { pr_info(fmt, ##__VA_ARGS__); } while (0)
113 #define vpr_info_dq(q, msg) \
116 vpr_info("%s: func=\"%s\" file=\"%s\" " \
117 "module=\"%s\" format=\"%.*s\" " \
120 q->function ? q->function : "", \
121 q->filename ? q->filename : "", \
122 q->module ? q->module : "", \
123 (int)(q->format ? strlen(q->format) - 1 : 0), \
124 q->format ? q->format : "", \
125 q->first_lineno, q->last_lineno); \
139 unsigned int newflags;
140 unsigned int nfound = 0;
182 if (newflags == dp->
flags)
184 dp->
flags = newflags;
185 vpr_info(
"changed %s:%d [%s]%s =%s\n",
188 ddebug_describe_flags(dp, flagbuf,
195 pr_info(
"no matches for query\n");
206 static int ddebug_tokenize(
char *buf,
char *words[],
int maxwords)
221 if (*buf ==
'"' || *buf ==
'\'') {
223 for (end = buf ; *end && *end != quote ; end++)
228 for (end = buf ; *end && !
isspace(*end) ; end++)
234 if (nwords == maxwords)
238 words[nwords++] =
buf;
245 for (i = 0 ; i < nwords ; i++)
258 static inline int parse_lineno(
const char *
str,
unsigned int *
val)
267 return end ==
NULL || end == str || *end !=
'\0' ? -
EINVAL : 0;
275 #define isodigit(c) ((c) >= '0' && (c) <= '7')
276 static char *unescape(
char *str)
287 }
else if (in[1] ==
't') {
291 }
else if (in[1] ==
'n') {
298 *out++ = ((in[1] -
'0')<<6) |
312 static int check_set(
const char **
dest,
char *
src,
char *
name)
318 pr_err(
"match-spec:%s val:%s overridden by %s",
340 static int ddebug_parse_query(
char *words[],
int nwords,
349 memset(query, 0,
sizeof(*query));
355 for (i = 0 ; i < nwords ; i += 2) {
356 if (!
strcmp(words[i],
"func"))
357 rc = check_set(&query->
function, words[i+1],
"func");
358 else if (!
strcmp(words[i],
"file"))
359 rc = check_set(&query->
filename, words[i+1],
"file");
360 else if (!
strcmp(words[i],
"module"))
361 rc = check_set(&query->
module, words[i+1],
"module");
362 else if (!
strcmp(words[i],
"format"))
363 rc = check_set(&query->
format, unescape(words[i+1]),
365 else if (!
strcmp(words[i],
"line")) {
366 char *
first = words[i+1];
369 pr_err(
"match-spec:line given 2 times\n");
380 pr_err(
"last-line < 1st-line\n");
387 pr_err(
"unknown keyword \"%s\"\n", words[i]);
403 static int ddebug_parse_flags(
const char *str,
unsigned int *flagsp,
421 for (i =
ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
422 if (*str == opt_array[i].
opt_char) {
423 flags |= opt_array[
i].flag;
447 vpr_info(
"*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
451 static int ddebug_exec_query(
char *query_string,
const char *modname)
453 unsigned int flags = 0,
mask = 0;
459 nwords = ddebug_tokenize(query_string, words, MAXWORDS);
462 if (ddebug_parse_query(words, nwords-1, &query, modname))
464 if (ddebug_parse_flags(words[nwords-1], &flags, &
mask))
468 nfound = ddebug_change(&query, flags,
mask);
469 vpr_info_dq((&query), (nfound) ?
"applied" :
"no-match");
478 static int ddebug_exec_queries(
char *query,
const char *modname)
481 int i, errs = 0, exitcode = 0,
rc, nfound = 0;
489 if (!query || !*query || *query ==
'#')
492 vpr_info(
"query %d: \"%s\"\n", i, query);
494 rc = ddebug_exec_query(query, modname);
502 vpr_info(
"processed %d queries, with %d matches, %d errs\n",
510 #define PREFIX_SIZE 64
512 static int remaining(
int wrote)
519 static char *dynamic_emit_prefix(
const struct _ddebug *
desc,
char *buf)
528 pos +=
snprintf(buf + pos, remaining(pos),
"<intr> ");
530 pos +=
snprintf(buf + pos, remaining(pos),
"[%d] ",
535 pos +=
snprintf(buf + pos, remaining(pos),
"%s:",
538 pos +=
snprintf(buf + pos, remaining(pos),
"%s:",
541 pos +=
snprintf(buf + pos, remaining(pos),
"%d:",
543 if (pos - pos_after_tid)
544 pos +=
snprintf(buf + pos, remaining(pos),
" ");
567 dynamic_emit_prefix(descriptor, buf), &vaf);
595 res = dev_printk_emit(7, dev,
"%s%s %s: %pV",
596 dynamic_emit_prefix(descriptor, buf),
624 if (dev && dev->
dev.parent) {
627 res = dev_printk_emit(7, dev->
dev.parent,
629 dynamic_emit_prefix(descriptor, buf),
631 dev_name(dev->
dev.parent),
632 netdev_name(dev), &vaf);
647 #define DDEBUG_STRING_SIZE 1024
650 static __init int ddebug_setup_query(
char *str)
653 pr_warn(
"ddebug boot param string too large\n");
660 __setup(
"ddebug_query=", ddebug_setup_query);
666 #define USER_BUF_PAGE 4096
667 static ssize_t ddebug_proc_write(
struct file *
file,
const char __user *ubuf,
668 size_t len, loff_t *offp)
687 vpr_info(
"read %d bytes from userspace\n", (
int)len);
689 ret = ddebug_exec_queries(tmpbuf,
NULL);
705 if (list_empty(&ddebug_tables)) {
713 return &iter->
table->ddebugs[iter->
idx];
726 if (++iter->
idx == iter->
table->num_ddebugs) {
729 if (list_is_last(&iter->
table->link, &ddebug_tables)) {
736 return &iter->
table->ddebugs[iter->
idx];
744 static void *ddebug_proc_start(
struct seq_file *
m, loff_t *pos)
750 vpr_info(
"called m=%p *pos=%lld\n", m, (
unsigned long long)*pos);
758 dp = ddebug_iter_first(iter);
759 while (dp !=
NULL && --n > 0)
760 dp = ddebug_iter_next(iter);
769 static void *ddebug_proc_next(
struct seq_file *m,
void *p, loff_t *pos)
774 vpr_info(
"called m=%p p=%p *pos=%lld\n",
775 m, p, (
unsigned long long)*pos);
778 dp = ddebug_iter_first(iter);
780 dp = ddebug_iter_next(iter);
791 static int ddebug_proc_show(
struct seq_file *m,
void *p)
797 vpr_info(
"called m=%p p=%p\n", m, p);
801 "# filename:lineno [module]function flags format\n");
808 ddebug_describe_flags(dp, flagsbuf,
sizeof(flagsbuf)));
819 static void ddebug_proc_stop(
struct seq_file *m,
void *p)
821 vpr_info(
"called m=%p p=%p\n", m, p);
826 .start = ddebug_proc_start,
827 .next = ddebug_proc_next,
828 .show = ddebug_proc_show,
829 .stop = ddebug_proc_stop
850 err =
seq_open(file, &ddebug_proc_seqops);
861 .open = ddebug_proc_open,
865 .write = ddebug_proc_write
882 if (new_name ==
NULL) {
900 static int ddebug_dyndbg_param_cb(
char *
param,
char *val,
901 const char *modname,
int on_err)
912 if (
strcmp(param,
"dyndbg"))
915 ddebug_exec_queries((val ? val :
"+p"), modname);
921 static int ddebug_dyndbg_boot_param_cb(
char *param,
char *val,
924 vpr_info(
"%s=\"%s\"\n", param, val);
925 return ddebug_dyndbg_param_cb(param, val,
NULL, 0);
935 vpr_info(
"module: %s %s=\"%s\"\n", module, param, val);
936 return ddebug_dyndbg_param_cb(param, val, module, -
ENOENT);
941 list_del_init(&dt->
link);
955 vpr_info(
"removing module \"%s\"\n", mod_name);
960 ddebug_table_free(dt);
969 static void ddebug_remove_all_tables(
void)
972 while (!list_empty(&ddebug_tables)) {
976 ddebug_table_free(dt);
983 static int __init dynamic_debug_init_debugfs(
void)
987 if (!ddebug_init_success)
1002 static int __init dynamic_debug_init(
void)
1004 struct _ddebug *iter, *iter_start;
1005 const char *modname =
NULL;
1008 int n = 0,
entries = 0, modct = 0;
1009 int verbose_bytes = 0;
1011 if (__start___verbose == __stop___verbose) {
1012 pr_warn(
"_ddebug table is empty in a "
1013 "CONFIG_DYNAMIC_DEBUG build");
1039 ddebug_init_success = 1;
1040 vpr_info(
"%d modules, %d entries and %d bytes in ddebug tables,"
1041 " %d bytes in (readonly) verbose section\n",
1043 verbose_bytes + (
int)(__stop___verbose - __start___verbose));
1046 if (ddebug_setup_string[0] !=
'\0') {
1047 pr_warn(
"ddebug_query param name is deprecated,"
1048 " change it to dyndbg\n");
1049 ret = ddebug_exec_queries(ddebug_setup_string,
NULL);
1051 pr_warn(
"Invalid ddebug boot param %s",
1052 ddebug_setup_string);
1054 pr_info(
"%d changes by ddebug_query\n", ret);
1066 0, 0, 0, &ddebug_dyndbg_boot_param_cb);
1071 ddebug_remove_all_tables();