diff options
-rw-r--r-- | lib/dynamic_debug.c | 118 |
1 files changed, 62 insertions, 56 deletions
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 1db1fc660538..ac7d27737e42 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c | |||
@@ -59,7 +59,7 @@ struct ddebug_iter { | |||
59 | 59 | ||
60 | static DEFINE_MUTEX(ddebug_lock); | 60 | static DEFINE_MUTEX(ddebug_lock); |
61 | static LIST_HEAD(ddebug_tables); | 61 | static LIST_HEAD(ddebug_tables); |
62 | static int verbose = 0; | 62 | static int verbose; |
63 | module_param(verbose, int, 0644); | 63 | module_param(verbose, int, 0644); |
64 | 64 | ||
65 | /* Return the path relative to source root */ | 65 | /* Return the path relative to source root */ |
@@ -100,24 +100,32 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf, | |||
100 | return buf; | 100 | return buf; |
101 | } | 101 | } |
102 | 102 | ||
103 | #define vpr_info(fmt, ...) \ | 103 | #define vpr_info(fmt, ...) \ |
104 | if (verbose) do { pr_info(fmt, ##__VA_ARGS__); } while (0) | ||
105 | |||
106 | #define vpr_info_dq(q, msg) \ | ||
107 | do { \ | 104 | do { \ |
108 | /* trim last char off format print */ \ | 105 | if (verbose) \ |
109 | vpr_info("%s: func=\"%s\" file=\"%s\" " \ | 106 | pr_info(fmt, ##__VA_ARGS__); \ |
110 | "module=\"%s\" format=\"%.*s\" " \ | ||
111 | "lineno=%u-%u", \ | ||
112 | msg, \ | ||
113 | q->function ? q->function : "", \ | ||
114 | q->filename ? q->filename : "", \ | ||
115 | q->module ? q->module : "", \ | ||
116 | (int)(q->format ? strlen(q->format) - 1 : 0), \ | ||
117 | q->format ? q->format : "", \ | ||
118 | q->first_lineno, q->last_lineno); \ | ||
119 | } while (0) | 107 | } while (0) |
120 | 108 | ||
109 | static void vpr_info_dq(const struct ddebug_query *query, const char *msg) | ||
110 | { | ||
111 | /* trim any trailing newlines */ | ||
112 | int fmtlen = 0; | ||
113 | |||
114 | if (query->format) { | ||
115 | fmtlen = strlen(query->format); | ||
116 | while (fmtlen && query->format[fmtlen - 1] == '\n') | ||
117 | fmtlen--; | ||
118 | } | ||
119 | |||
120 | vpr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n", | ||
121 | msg, | ||
122 | query->function ? query->function : "", | ||
123 | query->filename ? query->filename : "", | ||
124 | query->module ? query->module : "", | ||
125 | fmtlen, query->format ? query->format : "", | ||
126 | query->first_lineno, query->last_lineno); | ||
127 | } | ||
128 | |||
121 | /* | 129 | /* |
122 | * Search the tables for _ddebug's which match the given `query' and | 130 | * Search the tables for _ddebug's which match the given `query' and |
123 | * apply the `flags' and `mask' to them. Returns number of matching | 131 | * apply the `flags' and `mask' to them. Returns number of matching |
@@ -141,7 +149,7 @@ static int ddebug_change(const struct ddebug_query *query, | |||
141 | if (query->module && strcmp(query->module, dt->mod_name)) | 149 | if (query->module && strcmp(query->module, dt->mod_name)) |
142 | continue; | 150 | continue; |
143 | 151 | ||
144 | for (i = 0 ; i < dt->num_ddebugs ; i++) { | 152 | for (i = 0; i < dt->num_ddebugs; i++) { |
145 | struct _ddebug *dp = &dt->ddebugs[i]; | 153 | struct _ddebug *dp = &dt->ddebugs[i]; |
146 | 154 | ||
147 | /* match against the source filename */ | 155 | /* match against the source filename */ |
@@ -176,10 +184,10 @@ static int ddebug_change(const struct ddebug_query *query, | |||
176 | continue; | 184 | continue; |
177 | dp->flags = newflags; | 185 | dp->flags = newflags; |
178 | vpr_info("changed %s:%d [%s]%s =%s\n", | 186 | vpr_info("changed %s:%d [%s]%s =%s\n", |
179 | trim_prefix(dp->filename), dp->lineno, | 187 | trim_prefix(dp->filename), dp->lineno, |
180 | dt->mod_name, dp->function, | 188 | dt->mod_name, dp->function, |
181 | ddebug_describe_flags(dp, flagbuf, | 189 | ddebug_describe_flags(dp, flagbuf, |
182 | sizeof(flagbuf))); | 190 | sizeof(flagbuf))); |
183 | } | 191 | } |
184 | } | 192 | } |
185 | mutex_unlock(&ddebug_lock); | 193 | mutex_unlock(&ddebug_lock); |
@@ -213,12 +221,12 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) | |||
213 | /* find `end' of word, whitespace separated or quoted */ | 221 | /* find `end' of word, whitespace separated or quoted */ |
214 | if (*buf == '"' || *buf == '\'') { | 222 | if (*buf == '"' || *buf == '\'') { |
215 | int quote = *buf++; | 223 | int quote = *buf++; |
216 | for (end = buf ; *end && *end != quote ; end++) | 224 | for (end = buf; *end && *end != quote; end++) |
217 | ; | 225 | ; |
218 | if (!*end) | 226 | if (!*end) |
219 | return -EINVAL; /* unclosed quote */ | 227 | return -EINVAL; /* unclosed quote */ |
220 | } else { | 228 | } else { |
221 | for (end = buf ; *end && !isspace(*end) ; end++) | 229 | for (end = buf; *end && !isspace(*end); end++) |
222 | ; | 230 | ; |
223 | BUG_ON(end == buf); | 231 | BUG_ON(end == buf); |
224 | } | 232 | } |
@@ -235,7 +243,7 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) | |||
235 | if (verbose) { | 243 | if (verbose) { |
236 | int i; | 244 | int i; |
237 | pr_info("split into words:"); | 245 | pr_info("split into words:"); |
238 | for (i = 0 ; i < nwords ; i++) | 246 | for (i = 0; i < nwords; i++) |
239 | pr_cont(" \"%s\"", words[i]); | 247 | pr_cont(" \"%s\"", words[i]); |
240 | pr_cont("\n"); | 248 | pr_cont("\n"); |
241 | } | 249 | } |
@@ -286,11 +294,11 @@ static char *unescape(char *str) | |||
286 | in += 2; | 294 | in += 2; |
287 | continue; | 295 | continue; |
288 | } else if (isodigit(in[1]) && | 296 | } else if (isodigit(in[1]) && |
289 | isodigit(in[2]) && | 297 | isodigit(in[2]) && |
290 | isodigit(in[3])) { | 298 | isodigit(in[3])) { |
291 | *out++ = ((in[1] - '0')<<6) | | 299 | *out++ = (((in[1] - '0') << 6) | |
292 | ((in[2] - '0')<<3) | | 300 | ((in[2] - '0') << 3) | |
293 | (in[3] - '0'); | 301 | (in[3] - '0')); |
294 | in += 4; | 302 | in += 4; |
295 | continue; | 303 | continue; |
296 | } | 304 | } |
@@ -308,8 +316,8 @@ static int check_set(const char **dest, char *src, char *name) | |||
308 | 316 | ||
309 | if (*dest) { | 317 | if (*dest) { |
310 | rc = -EINVAL; | 318 | rc = -EINVAL; |
311 | pr_err("match-spec:%s val:%s overridden by %s", | 319 | pr_err("match-spec:%s val:%s overridden by %s\n", |
312 | name, *dest, src); | 320 | name, *dest, src); |
313 | } | 321 | } |
314 | *dest = src; | 322 | *dest = src; |
315 | return rc; | 323 | return rc; |
@@ -345,17 +353,17 @@ static int ddebug_parse_query(char *words[], int nwords, | |||
345 | /* support $modname.dyndbg=<multiple queries> */ | 353 | /* support $modname.dyndbg=<multiple queries> */ |
346 | query->module = modname; | 354 | query->module = modname; |
347 | 355 | ||
348 | for (i = 0 ; i < nwords ; i += 2) { | 356 | for (i = 0; i < nwords; i += 2) { |
349 | if (!strcmp(words[i], "func")) | 357 | if (!strcmp(words[i], "func")) { |
350 | rc = check_set(&query->function, words[i+1], "func"); | 358 | rc = check_set(&query->function, words[i+1], "func"); |
351 | else if (!strcmp(words[i], "file")) | 359 | } else if (!strcmp(words[i], "file")) { |
352 | rc = check_set(&query->filename, words[i+1], "file"); | 360 | rc = check_set(&query->filename, words[i+1], "file"); |
353 | else if (!strcmp(words[i], "module")) | 361 | } else if (!strcmp(words[i], "module")) { |
354 | rc = check_set(&query->module, words[i+1], "module"); | 362 | rc = check_set(&query->module, words[i+1], "module"); |
355 | else if (!strcmp(words[i], "format")) | 363 | } else if (!strcmp(words[i], "format")) { |
356 | rc = check_set(&query->format, unescape(words[i+1]), | 364 | rc = check_set(&query->format, unescape(words[i+1]), |
357 | "format"); | 365 | "format"); |
358 | else if (!strcmp(words[i], "line")) { | 366 | } else if (!strcmp(words[i], "line")) { |
359 | char *first = words[i+1]; | 367 | char *first = words[i+1]; |
360 | char *last = strchr(first, '-'); | 368 | char *last = strchr(first, '-'); |
361 | if (query->first_lineno || query->last_lineno) { | 369 | if (query->first_lineno || query->last_lineno) { |
@@ -410,7 +418,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp, | |||
410 | } | 418 | } |
411 | vpr_info("op='%c'\n", op); | 419 | vpr_info("op='%c'\n", op); |
412 | 420 | ||
413 | for ( ; *str ; ++str) { | 421 | for (; *str ; ++str) { |
414 | for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) { | 422 | for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) { |
415 | if (*str == opt_array[i].opt_char) { | 423 | if (*str == opt_array[i].opt_char) { |
416 | flags |= opt_array[i].flag; | 424 | flags |= opt_array[i].flag; |
@@ -459,7 +467,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) | |||
459 | 467 | ||
460 | /* actually go and implement the change */ | 468 | /* actually go and implement the change */ |
461 | nfound = ddebug_change(&query, flags, mask); | 469 | nfound = ddebug_change(&query, flags, mask); |
462 | vpr_info_dq((&query), (nfound) ? "applied" : "no-match"); | 470 | vpr_info_dq(&query, nfound ? "applied" : "no-match"); |
463 | 471 | ||
464 | return nfound; | 472 | return nfound; |
465 | } | 473 | } |
@@ -488,8 +496,9 @@ static int ddebug_exec_queries(char *query, const char *modname) | |||
488 | if (rc < 0) { | 496 | if (rc < 0) { |
489 | errs++; | 497 | errs++; |
490 | exitcode = rc; | 498 | exitcode = rc; |
491 | } else | 499 | } else { |
492 | nfound += rc; | 500 | nfound += rc; |
501 | } | ||
493 | i++; | 502 | i++; |
494 | } | 503 | } |
495 | vpr_info("processed %d queries, with %d matches, %d errs\n", | 504 | vpr_info("processed %d queries, with %d matches, %d errs\n", |
@@ -765,7 +774,7 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos) | |||
765 | struct _ddebug *dp; | 774 | struct _ddebug *dp; |
766 | 775 | ||
767 | vpr_info("called m=%p p=%p *pos=%lld\n", | 776 | vpr_info("called m=%p p=%p *pos=%lld\n", |
768 | m, p, (unsigned long long)*pos); | 777 | m, p, (unsigned long long)*pos); |
769 | 778 | ||
770 | if (p == SEQ_START_TOKEN) | 779 | if (p == SEQ_START_TOKEN) |
771 | dp = ddebug_iter_first(iter); | 780 | dp = ddebug_iter_first(iter); |
@@ -791,14 +800,14 @@ static int ddebug_proc_show(struct seq_file *m, void *p) | |||
791 | 800 | ||
792 | if (p == SEQ_START_TOKEN) { | 801 | if (p == SEQ_START_TOKEN) { |
793 | seq_puts(m, | 802 | seq_puts(m, |
794 | "# filename:lineno [module]function flags format\n"); | 803 | "# filename:lineno [module]function flags format\n"); |
795 | return 0; | 804 | return 0; |
796 | } | 805 | } |
797 | 806 | ||
798 | seq_printf(m, "%s:%u [%s]%s =%s \"", | 807 | seq_printf(m, "%s:%u [%s]%s =%s \"", |
799 | trim_prefix(dp->filename), dp->lineno, | 808 | trim_prefix(dp->filename), dp->lineno, |
800 | iter->table->mod_name, dp->function, | 809 | iter->table->mod_name, dp->function, |
801 | ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf))); | 810 | ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf))); |
802 | seq_escape(m, dp->format, "\t\r\n\""); | 811 | seq_escape(m, dp->format, "\t\r\n\""); |
803 | seq_puts(m, "\"\n"); | 812 | seq_puts(m, "\"\n"); |
804 | 813 | ||
@@ -845,7 +854,7 @@ static int ddebug_proc_open(struct inode *inode, struct file *file) | |||
845 | kfree(iter); | 854 | kfree(iter); |
846 | return err; | 855 | return err; |
847 | } | 856 | } |
848 | ((struct seq_file *) file->private_data)->private = iter; | 857 | ((struct seq_file *)file->private_data)->private = iter; |
849 | return 0; | 858 | return 0; |
850 | } | 859 | } |
851 | 860 | ||
@@ -1002,8 +1011,7 @@ static int __init dynamic_debug_init(void) | |||
1002 | int verbose_bytes = 0; | 1011 | int verbose_bytes = 0; |
1003 | 1012 | ||
1004 | if (__start___verbose == __stop___verbose) { | 1013 | if (__start___verbose == __stop___verbose) { |
1005 | pr_warn("_ddebug table is empty in a " | 1014 | pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n"); |
1006 | "CONFIG_DYNAMIC_DEBUG build"); | ||
1007 | return 1; | 1015 | return 1; |
1008 | } | 1016 | } |
1009 | iter = __start___verbose; | 1017 | iter = __start___verbose; |
@@ -1030,18 +1038,16 @@ static int __init dynamic_debug_init(void) | |||
1030 | goto out_err; | 1038 | goto out_err; |
1031 | 1039 | ||
1032 | ddebug_init_success = 1; | 1040 | ddebug_init_success = 1; |
1033 | vpr_info("%d modules, %d entries and %d bytes in ddebug tables," | 1041 | vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in (readonly) verbose section\n", |
1034 | " %d bytes in (readonly) verbose section\n", | 1042 | modct, entries, (int)(modct * sizeof(struct ddebug_table)), |
1035 | modct, entries, (int)( modct * sizeof(struct ddebug_table)), | 1043 | verbose_bytes + (int)(__stop___verbose - __start___verbose)); |
1036 | verbose_bytes + (int)(__stop___verbose - __start___verbose)); | ||
1037 | 1044 | ||
1038 | /* apply ddebug_query boot param, dont unload tables on err */ | 1045 | /* apply ddebug_query boot param, dont unload tables on err */ |
1039 | if (ddebug_setup_string[0] != '\0') { | 1046 | if (ddebug_setup_string[0] != '\0') { |
1040 | pr_warn("ddebug_query param name is deprecated," | 1047 | pr_warn("ddebug_query param name is deprecated, change it to dyndbg\n"); |
1041 | " change it to dyndbg\n"); | ||
1042 | ret = ddebug_exec_queries(ddebug_setup_string, NULL); | 1048 | ret = ddebug_exec_queries(ddebug_setup_string, NULL); |
1043 | if (ret < 0) | 1049 | if (ret < 0) |
1044 | pr_warn("Invalid ddebug boot param %s", | 1050 | pr_warn("Invalid ddebug boot param %s\n", |
1045 | ddebug_setup_string); | 1051 | ddebug_setup_string); |
1046 | else | 1052 | else |
1047 | pr_info("%d changes by ddebug_query\n", ret); | 1053 | pr_info("%d changes by ddebug_query\n", ret); |