aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Cromie <jim.cromie@gmail.com>2011-12-19 17:13:21 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-24 15:50:36 -0500
commit85f7f6c0edb8414053d788229c97d5ecff21efab (patch)
tree214ed1f1ed2d026280ca46728948f59c0cb5f528
parent574b3725e327531c70361d1a10b8dc8dd2b93590 (diff)
dynamic_debug: process multiple debug-queries on a line
Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/dynamic-debug-howto.txt23
-rw-r--r--lib/dynamic_debug.c73
2 files changed, 66 insertions, 30 deletions
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 378b5d1bf436..74e6c7782678 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -12,7 +12,7 @@ dynamically enabled per-callsite.
12Dynamic debug has even more useful features: 12Dynamic debug has even more useful features:
13 13
14 * Simple query language allows turning on and off debugging statements by 14 * Simple query language allows turning on and off debugging statements by
15 matching any combination of: 15 matching any combination of 0 or 1 of:
16 16
17 - source filename 17 - source filename
18 - function name 18 - function name
@@ -79,31 +79,24 @@ Command Language Reference
79========================== 79==========================
80 80
81At the lexical level, a command comprises a sequence of words separated 81At the lexical level, a command comprises a sequence of words separated
82by whitespace characters. Note that newlines are treated as word 82by spaces or tabs. So these are all equivalent:
83separators and do *not* end a command or allow multiple commands to
84be done together. So these are all equivalent:
85 83
86nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' > 84nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
87 <debugfs>/dynamic_debug/control 85 <debugfs>/dynamic_debug/control
88nullarbor:~ # echo -c ' file svcsock.c line 1603 +p ' > 86nullarbor:~ # echo -c ' file svcsock.c line 1603 +p ' >
89 <debugfs>/dynamic_debug/control 87 <debugfs>/dynamic_debug/control
90nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
91 <debugfs>/dynamic_debug/control
92nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > 88nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
93 <debugfs>/dynamic_debug/control 89 <debugfs>/dynamic_debug/control
94 90
95Commands are bounded by a write() system call. If you want to do 91Command submissions are bounded by a write() system call.
96multiple commands you need to do a separate "echo" for each, like: 92Multiple commands can be written together, separated by ';' or '\n'.
97 93
98nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\ 94 ~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
99> echo 'file svcsock.c line 1563 +p' > /proc/dprintk 95 > <debugfs>/dynamic_debug/control
100 96
101or even like: 97If your query set is big, you can batch them too:
102 98
103nullarbor:~ # ( 99 ~# cat query-batch-file > <debugfs>/dynamic_debug/control
104> echo 'file svcsock.c line 1603 +p' ;\
105> echo 'file svcsock.c line 1563 +p' ;\
106> ) > /proc/dprintk
107 100
108At the syntactical level, a command comprises a sequence of match 101At the syntactical level, a command comprises a sequence of match
109specifications, followed by a flags change specification. 102specifications, followed by a flags change specification.
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 93fc5d500cd5..310c753cf83e 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -124,13 +124,13 @@ do { \
124} while (0) 124} while (0)
125 125
126/* 126/*
127 * Search the tables for _ddebug's which match the given 127 * Search the tables for _ddebug's which match the given `query' and
128 * `query' and apply the `flags' and `mask' to them. Tells 128 * apply the `flags' and `mask' to them. Returns number of matching
129 * the user which ddebug's were changed, or whether none 129 * callsites, normally the same as number of changes. If verbose,
130 * were matched. 130 * logs the changes. Takes ddebug_lock.
131 */ 131 */
132static void ddebug_change(const struct ddebug_query *query, 132static int ddebug_change(const struct ddebug_query *query,
133 unsigned int flags, unsigned int mask) 133 unsigned int flags, unsigned int mask)
134{ 134{
135 int i; 135 int i;
136 struct ddebug_table *dt; 136 struct ddebug_table *dt;
@@ -192,6 +192,8 @@ static void ddebug_change(const struct ddebug_query *query,
192 192
193 if (!nfound && verbose) 193 if (!nfound && verbose)
194 pr_info("no matches for query\n"); 194 pr_info("no matches for query\n");
195
196 return nfound;
195} 197}
196 198
197/* 199/*
@@ -449,7 +451,7 @@ static int ddebug_exec_query(char *query_string)
449 unsigned int flags = 0, mask = 0; 451 unsigned int flags = 0, mask = 0;
450 struct ddebug_query query; 452 struct ddebug_query query;
451#define MAXWORDS 9 453#define MAXWORDS 9
452 int nwords; 454 int nwords, nfound;
453 char *words[MAXWORDS]; 455 char *words[MAXWORDS];
454 456
455 nwords = ddebug_tokenize(query_string, words, MAXWORDS); 457 nwords = ddebug_tokenize(query_string, words, MAXWORDS);
@@ -461,8 +463,47 @@ static int ddebug_exec_query(char *query_string)
461 return -EINVAL; 463 return -EINVAL;
462 464
463 /* actually go and implement the change */ 465 /* actually go and implement the change */
464 ddebug_change(&query, flags, mask); 466 nfound = ddebug_change(&query, flags, mask);
465 return 0; 467 vpr_info_dq((&query), (nfound) ? "applied" : "no-match");
468
469 return nfound;
470}
471
472/* handle multiple queries in query string, continue on error, return
473 last error or number of matching callsites. Module name is either
474 in param (for boot arg) or perhaps in query string.
475*/
476static int ddebug_exec_queries(char *query)
477{
478 char *split;
479 int i, errs = 0, exitcode = 0, rc, nfound = 0;
480
481 for (i = 0; query; query = split) {
482 split = strpbrk(query, ";\n");
483 if (split)
484 *split++ = '\0';
485
486 query = skip_spaces(query);
487 if (!query || !*query || *query == '#')
488 continue;
489
490 if (verbose)
491 pr_info("query %d: \"%s\"\n", i, query);
492
493 rc = ddebug_exec_query(query);
494 if (rc < 0) {
495 errs++;
496 exitcode = rc;
497 } else
498 nfound += rc;
499 i++;
500 }
501 pr_info("processed %d queries, with %d matches, %d errs\n",
502 i, nfound, errs);
503
504 if (exitcode)
505 return exitcode;
506 return nfound;
466} 507}
467 508
468#define PREFIX_SIZE 64 509#define PREFIX_SIZE 64
@@ -615,9 +656,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
615 if (verbose) 656 if (verbose)
616 pr_info("read %d bytes from userspace\n", (int)len); 657 pr_info("read %d bytes from userspace\n", (int)len);
617 658
618 ret = ddebug_exec_query(tmpbuf); 659 ret = ddebug_exec_queries(tmpbuf);
619 kfree(tmpbuf); 660 kfree(tmpbuf);
620 if (ret) 661 if (ret < 0)
621 return ret; 662 return ret;
622 663
623 *offp += len; 664 *offp += len;
@@ -927,13 +968,15 @@ static int __init dynamic_debug_init(void)
927 968
928 /* ddebug_query boot param got passed -> set it up */ 969 /* ddebug_query boot param got passed -> set it up */
929 if (ddebug_setup_string[0] != '\0') { 970 if (ddebug_setup_string[0] != '\0') {
930 ret = ddebug_exec_query(ddebug_setup_string); 971 ret = ddebug_exec_queries(ddebug_setup_string);
931 if (ret) 972 if (ret < 0)
932 pr_warn("Invalid ddebug boot param %s", 973 pr_warn("Invalid ddebug boot param %s",
933 ddebug_setup_string); 974 ddebug_setup_string);
934 else 975 else
935 pr_info("ddebug initialized with string %s", 976 pr_info("%d changes by ddebug_query\n", ret);
936 ddebug_setup_string); 977
978 /* keep tables even on ddebug_query parse error */
979 ret = 0;
937 } 980 }
938 981
939out_free: 982out_free: