Blame view

lib/dynamic_debug.c 28.3 KB
e9d376f0f   Jason Baron   dynamic debug: co...
1
2
3
4
5
6
7
8
9
  /*
   * lib/dynamic_debug.c
   *
   * make pr_debug()/dev_dbg() calls runtime configurable based upon their
   * source module.
   *
   * Copyright (C) 2008 Jason Baron <jbaron@redhat.com>
   * By Greg Banks <gnb@melbourne.sgi.com>
   * Copyright (c) 2008 Silicon Graphics Inc.  All Rights Reserved.
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
10
   * Copyright (C) 2011 Bart Van Assche.  All Rights Reserved.
578b1e070   Du, Changbin   dynamic_debug: ad...
11
   * Copyright (C) 2013 Du, Changbin <changbin.du@gmail.com>
e9d376f0f   Jason Baron   dynamic debug: co...
12
   */
5aa9ffbba   Jim Cromie   dyndbg: shorten o...
13
  #define pr_fmt(fmt) "dyndbg: " fmt
4ad275e5c   Joe Perches   dynamic_debug: Co...
14

e9d376f0f   Jason Baron   dynamic debug: co...
15
16
  #include <linux/kernel.h>
  #include <linux/module.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
17
18
19
  #include <linux/moduleparam.h>
  #include <linux/kallsyms.h>
  #include <linux/types.h>
e9d376f0f   Jason Baron   dynamic debug: co...
20
  #include <linux/mutex.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
21
  #include <linux/proc_fs.h>
e9d376f0f   Jason Baron   dynamic debug: co...
22
  #include <linux/seq_file.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
23
24
  #include <linux/list.h>
  #include <linux/sysctl.h>
e9d376f0f   Jason Baron   dynamic debug: co...
25
  #include <linux/ctype.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
26
  #include <linux/string.h>
578b1e070   Du, Changbin   dynamic_debug: ad...
27
  #include <linux/parser.h>
d338b1379   Andy Shevchenko   dynamic_debug: re...
28
  #include <linux/string_helpers.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
29
  #include <linux/uaccess.h>
e9d376f0f   Jason Baron   dynamic debug: co...
30
31
  #include <linux/dynamic_debug.h>
  #include <linux/debugfs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
32
  #include <linux/slab.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
33
  #include <linux/jump_label.h>
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
34
  #include <linux/hardirq.h>
e8d9792aa   Greg Kroah-Hartman   dynamic_debug: ad...
35
  #include <linux/sched.h>
fef15d2f3   Greg Kroah-Hartman   Revert "dynamic_d...
36
  #include <linux/device.h>
ffa10cb47   Jason Baron   dynamic_debug: ma...
37
  #include <linux/netdevice.h>
e9d376f0f   Jason Baron   dynamic debug: co...
38

923abb9d7   Gal Pressman   RDMA/core: Introd...
39
  #include <rdma/ib_verbs.h>
e5ebffe18   Jim Cromie   dyndbg: rename __...
40
41
  extern struct _ddebug __start___dyndbg[];
  extern struct _ddebug __stop___dyndbg[];
e9d376f0f   Jason Baron   dynamic debug: co...
42

e9d376f0f   Jason Baron   dynamic debug: co...
43
44
  struct ddebug_table {
  	struct list_head link;
3e406b1d7   Rasmus Villemoes   lib/dynamic_debug...
45
  	const char *mod_name;
e9d376f0f   Jason Baron   dynamic debug: co...
46
  	unsigned int num_ddebugs;
e9d376f0f   Jason Baron   dynamic debug: co...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  	struct _ddebug *ddebugs;
  };
  
  struct ddebug_query {
  	const char *filename;
  	const char *module;
  	const char *function;
  	const char *format;
  	unsigned int first_lineno, last_lineno;
  };
  
  struct ddebug_iter {
  	struct ddebug_table *table;
  	unsigned int idx;
  };
84da83a6f   Jim Cromie   dyndbg: combine f...
62
63
64
65
  struct flag_settings {
  	unsigned int flags;
  	unsigned int mask;
  };
e9d376f0f   Jason Baron   dynamic debug: co...
66
67
  static DEFINE_MUTEX(ddebug_lock);
  static LIST_HEAD(ddebug_tables);
f657fd21e   Joe Perches   dynamic_debug: Fi...
68
  static int verbose;
74df138d5   Jim Cromie   dynamic_debug: ch...
69
  module_param(verbose, int, 0644);
e9d376f0f   Jason Baron   dynamic debug: co...
70

2b6783191   Jim Cromie   dynamic_debug: ad...
71
72
73
74
75
76
77
78
79
80
  /* Return the path relative to source root */
  static inline const char *trim_prefix(const char *path)
  {
  	int skip = strlen(__FILE__) - strlen("lib/dynamic_debug.c");
  
  	if (strncmp(path, __FILE__, skip))
  		skip = 0; /* prefix mismatch, don't skip */
  
  	return path + skip;
  }
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
81
82
83
84
85
86
  static struct { unsigned flag:8; char opt_char; } opt_array[] = {
  	{ _DPRINTK_FLAGS_PRINT, 'p' },
  	{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
  	{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
  	{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
  	{ _DPRINTK_FLAGS_INCL_TID, 't' },
5ca7d2a6c   Jim Cromie   dynamic_debug: de...
87
  	{ _DPRINTK_FLAGS_NONE, '_' },
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
88
  };
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
89
  struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
e9d376f0f   Jason Baron   dynamic debug: co...
90
  /* format a string into buf[] which describes the _ddebug's flags */
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
91
  static char *ddebug_describe_flags(unsigned int flags, struct flagsbuf *fb)
e9d376f0f   Jason Baron   dynamic debug: co...
92
  {
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
93
  	char *p = fb->buf;
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
94
  	int i;
e9d376f0f   Jason Baron   dynamic debug: co...
95

8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
96
  	for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
97
  		if (flags & opt_array[i].flag)
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
98
  			*p++ = opt_array[i].opt_char;
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
99
  	if (p == fb->buf)
5ca7d2a6c   Jim Cromie   dynamic_debug: de...
100
  		*p++ = '_';
e9d376f0f   Jason Baron   dynamic debug: co...
101
  	*p = '\0';
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
102
  	return fb->buf;
e9d376f0f   Jason Baron   dynamic debug: co...
103
  }
481c0e33f   Jim Cromie   dyndbg: refine de...
104
  #define vnpr_info(lvl, fmt, ...)				\
b8ccd5dee   Jim Cromie   dynamic_debug: re...
105
  do {								\
481c0e33f   Jim Cromie   dyndbg: refine de...
106
  	if (verbose >= lvl)					\
f657fd21e   Joe Perches   dynamic_debug: Fi...
107
  		pr_info(fmt, ##__VA_ARGS__);			\
574b3725e   Jim Cromie   dynamic_debug: fa...
108
  } while (0)
481c0e33f   Jim Cromie   dyndbg: refine de...
109
110
  #define vpr_info(fmt, ...)	vnpr_info(1, fmt, ##__VA_ARGS__)
  #define v2pr_info(fmt, ...)	vnpr_info(2, fmt, ##__VA_ARGS__)
f657fd21e   Joe Perches   dynamic_debug: Fi...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
  {
  	/* trim any trailing newlines */
  	int fmtlen = 0;
  
  	if (query->format) {
  		fmtlen = strlen(query->format);
  		while (fmtlen && query->format[fmtlen - 1] == '
  ')
  			fmtlen--;
  	}
  
  	vpr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u
  ",
  		 msg,
f62fc08fd   Jim Cromie   dyndbg: use gcc ?...
126
127
128
129
  		 query->function ?: "",
  		 query->filename ?: "",
  		 query->module ?: "",
  		 fmtlen, query->format ?: "",
f657fd21e   Joe Perches   dynamic_debug: Fi...
130
131
  		 query->first_lineno, query->last_lineno);
  }
e9d376f0f   Jason Baron   dynamic debug: co...
132
  /*
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
133
134
135
136
   * Search the tables for _ddebug's which match the given `query' and
   * apply the `flags' and `mask' to them.  Returns number of matching
   * callsites, normally the same as number of changes.  If verbose,
   * logs the changes.  Takes ddebug_lock.
e9d376f0f   Jason Baron   dynamic debug: co...
137
   */
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
138
  static int ddebug_change(const struct ddebug_query *query,
84da83a6f   Jim Cromie   dyndbg: combine f...
139
  			 struct flag_settings *modifiers)
e9d376f0f   Jason Baron   dynamic debug: co...
140
141
142
143
144
  {
  	int i;
  	struct ddebug_table *dt;
  	unsigned int newflags;
  	unsigned int nfound = 0;
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
145
  	struct flagsbuf fbuf;
e9d376f0f   Jason Baron   dynamic debug: co...
146
147
148
149
150
151
  
  	/* search for matching ddebugs */
  	mutex_lock(&ddebug_lock);
  	list_for_each_entry(dt, &ddebug_tables, link) {
  
  		/* match against the module name */
578b1e070   Du, Changbin   dynamic_debug: ad...
152
153
  		if (query->module &&
  		    !match_wildcard(query->module, dt->mod_name))
e9d376f0f   Jason Baron   dynamic debug: co...
154
  			continue;
f657fd21e   Joe Perches   dynamic_debug: Fi...
155
  		for (i = 0; i < dt->num_ddebugs; i++) {
e9d376f0f   Jason Baron   dynamic debug: co...
156
157
158
  			struct _ddebug *dp = &dt->ddebugs[i];
  
  			/* match against the source filename */
d6a238d25   Jim Cromie   dynamic_debug: dr...
159
  			if (query->filename &&
578b1e070   Du, Changbin   dynamic_debug: ad...
160
161
162
163
164
  			    !match_wildcard(query->filename, dp->filename) &&
  			    !match_wildcard(query->filename,
  					   kbasename(dp->filename)) &&
  			    !match_wildcard(query->filename,
  					   trim_prefix(dp->filename)))
e9d376f0f   Jason Baron   dynamic debug: co...
165
166
167
  				continue;
  
  			/* match against the function */
d6a238d25   Jim Cromie   dynamic_debug: dr...
168
  			if (query->function &&
578b1e070   Du, Changbin   dynamic_debug: ad...
169
  			    !match_wildcard(query->function, dp->function))
e9d376f0f   Jason Baron   dynamic debug: co...
170
171
172
  				continue;
  
  			/* match against the format */
4b334484f   Jim Cromie   dyndbg: allow anc...
173
174
175
176
177
178
179
180
181
182
  			if (query->format) {
  				if (*query->format == '^') {
  					char *p;
  					/* anchored search. match must be at beginning */
  					p = strstr(dp->format, query->format+1);
  					if (p != dp->format)
  						continue;
  				} else if (!strstr(dp->format, query->format))
  					continue;
  			}
e9d376f0f   Jason Baron   dynamic debug: co...
183
184
185
186
187
188
189
190
191
192
  
  			/* match against the line number range */
  			if (query->first_lineno &&
  			    dp->lineno < query->first_lineno)
  				continue;
  			if (query->last_lineno &&
  			    dp->lineno > query->last_lineno)
  				continue;
  
  			nfound++;
84da83a6f   Jim Cromie   dyndbg: combine f...
193
  			newflags = (dp->flags & modifiers->mask) | modifiers->flags;
e9d376f0f   Jason Baron   dynamic debug: co...
194
195
  			if (newflags == dp->flags)
  				continue;
e9666d10a   Masahiro Yamada   jump_label: move ...
196
  #ifdef CONFIG_JUMP_LABEL
9049fc745   Jason Baron   dynamic_debug: ad...
197
  			if (dp->flags & _DPRINTK_FLAGS_PRINT) {
84da83a6f   Jim Cromie   dyndbg: combine f...
198
  				if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
9049fc745   Jason Baron   dynamic_debug: ad...
199
  					static_branch_disable(&dp->key.dd_key_true);
84da83a6f   Jim Cromie   dyndbg: combine f...
200
  			} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
9049fc745   Jason Baron   dynamic_debug: ad...
201
202
  				static_branch_enable(&dp->key.dd_key_true);
  #endif
e9d376f0f   Jason Baron   dynamic debug: co...
203
  			dp->flags = newflags;
481c0e33f   Jim Cromie   dyndbg: refine de...
204
205
  			v2pr_info("changed %s:%d [%s]%s =%s
  ",
f657fd21e   Joe Perches   dynamic_debug: Fi...
206
207
  				 trim_prefix(dp->filename), dp->lineno,
  				 dt->mod_name, dp->function,
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
208
  				 ddebug_describe_flags(dp->flags, &fbuf));
e9d376f0f   Jason Baron   dynamic debug: co...
209
210
211
212
213
  		}
  	}
  	mutex_unlock(&ddebug_lock);
  
  	if (!nfound && verbose)
4ad275e5c   Joe Perches   dynamic_debug: Co...
214
215
  		pr_info("no matches for query
  ");
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
216
217
  
  	return nfound;
e9d376f0f   Jason Baron   dynamic debug: co...
218
219
220
  }
  
  /*
e9d376f0f   Jason Baron   dynamic debug: co...
221
   * Split the buffer `buf' into space-separated words.
9898abb3d   Greg Banks   Dynamic debug: al...
222
223
224
   * Handles simple " and ' quoting, i.e. without nested,
   * embedded or escaped \".  Return the number of words
   * or <0 on error.
e9d376f0f   Jason Baron   dynamic debug: co...
225
226
227
228
   */
  static int ddebug_tokenize(char *buf, char *words[], int maxwords)
  {
  	int nwords = 0;
9898abb3d   Greg Banks   Dynamic debug: al...
229
230
231
232
  	while (*buf) {
  		char *end;
  
  		/* Skip leading whitespace */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
233
  		buf = skip_spaces(buf);
9898abb3d   Greg Banks   Dynamic debug: al...
234
235
  		if (!*buf)
  			break;	/* oh, it was trailing whitespace */
8bd6026e8   Jim Cromie   dynamic_debug: ch...
236
237
  		if (*buf == '#')
  			break;	/* token starts comment, skip rest of line */
9898abb3d   Greg Banks   Dynamic debug: al...
238

07100be7e   Jim Cromie   dynamic_debug: fi...
239
  		/* find `end' of word, whitespace separated or quoted */
9898abb3d   Greg Banks   Dynamic debug: al...
240
241
  		if (*buf == '"' || *buf == '\'') {
  			int quote = *buf++;
f657fd21e   Joe Perches   dynamic_debug: Fi...
242
  			for (end = buf; *end && *end != quote; end++)
9898abb3d   Greg Banks   Dynamic debug: al...
243
  				;
18c216c53   Jim Cromie   dynamic_debug: ad...
244
245
246
  			if (!*end) {
  				pr_err("unclosed quote: %s
  ", buf);
9898abb3d   Greg Banks   Dynamic debug: al...
247
  				return -EINVAL;	/* unclosed quote */
18c216c53   Jim Cromie   dynamic_debug: ad...
248
  			}
9898abb3d   Greg Banks   Dynamic debug: al...
249
  		} else {
7f6e1f307   Greg Kroah-Hartman   Revert "dyndbg: f...
250
  			for (end = buf; *end && !isspace(*end); end++)
9898abb3d   Greg Banks   Dynamic debug: al...
251
252
253
  				;
  			BUG_ON(end == buf);
  		}
9898abb3d   Greg Banks   Dynamic debug: al...
254

07100be7e   Jim Cromie   dynamic_debug: fi...
255
  		/* `buf' is start of word, `end' is one past its end */
18c216c53   Jim Cromie   dynamic_debug: ad...
256
257
258
  		if (nwords == maxwords) {
  			pr_err("too many words, legal max <=%d
  ", maxwords);
9898abb3d   Greg Banks   Dynamic debug: al...
259
  			return -EINVAL;	/* ran out of words[] before bytes */
18c216c53   Jim Cromie   dynamic_debug: ad...
260
  		}
9898abb3d   Greg Banks   Dynamic debug: al...
261
262
263
264
265
  		if (*end)
  			*end++ = '\0';	/* terminate the word */
  		words[nwords++] = buf;
  		buf = end;
  	}
e9d376f0f   Jason Baron   dynamic debug: co...
266
267
268
  
  	if (verbose) {
  		int i;
4ad275e5c   Joe Perches   dynamic_debug: Co...
269
  		pr_info("split into words:");
f657fd21e   Joe Perches   dynamic_debug: Fi...
270
  		for (i = 0; i < nwords; i++)
4ad275e5c   Joe Perches   dynamic_debug: Co...
271
272
273
  			pr_cont(" \"%s\"", words[i]);
  		pr_cont("
  ");
e9d376f0f   Jason Baron   dynamic debug: co...
274
275
276
277
278
279
280
281
282
283
284
285
  	}
  
  	return nwords;
  }
  
  /*
   * Parse a single line number.  Note that the empty string ""
   * is treated as a special case and converted to zero, which
   * is later treated as a "don't care" value.
   */
  static inline int parse_lineno(const char *str, unsigned int *val)
  {
e9d376f0f   Jason Baron   dynamic debug: co...
286
287
288
289
290
  	BUG_ON(str == NULL);
  	if (*str == '\0') {
  		*val = 0;
  		return 0;
  	}
4592599af   Andrey Ryabinin   dynamic_debug: re...
291
  	if (kstrtouint(str, 10, val) < 0) {
18c216c53   Jim Cromie   dynamic_debug: ad...
292
293
294
295
296
  		pr_err("bad line-number: %s
  ", str);
  		return -EINVAL;
  	}
  	return 0;
e9d376f0f   Jason Baron   dynamic debug: co...
297
  }
8037072d8   Jim Cromie   dyndbg: refactor ...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  static int parse_linerange(struct ddebug_query *query, const char *first)
  {
  	char *last = strchr(first, '-');
  
  	if (query->first_lineno || query->last_lineno) {
  		pr_err("match-spec: line used 2x
  ");
  		return -EINVAL;
  	}
  	if (last)
  		*last++ = '\0';
  	if (parse_lineno(first, &query->first_lineno) < 0)
  		return -EINVAL;
  	if (last) {
  		/* range <first>-<last> */
  		if (parse_lineno(last, &query->last_lineno) < 0)
  			return -EINVAL;
  
  		/* special case for last lineno not specified */
  		if (query->last_lineno == 0)
  			query->last_lineno = UINT_MAX;
  
  		if (query->last_lineno < query->first_lineno) {
  			pr_err("last-line:%d < 1st-line:%d
  ",
  			       query->last_lineno,
  			       query->first_lineno);
  			return -EINVAL;
  		}
  	} else {
  		query->last_lineno = query->first_lineno;
  	}
  	vpr_info("parsed line %d-%d
  ", query->first_lineno,
  		 query->last_lineno);
  	return 0;
  }
820874c75   Jim Cromie   dynamic_debug: ti...
335
336
337
338
339
340
  static int check_set(const char **dest, char *src, char *name)
  {
  	int rc = 0;
  
  	if (*dest) {
  		rc = -EINVAL;
f657fd21e   Joe Perches   dynamic_debug: Fi...
341
342
343
  		pr_err("match-spec:%s val:%s overridden by %s
  ",
  		       name, *dest, src);
820874c75   Jim Cromie   dynamic_debug: ti...
344
345
346
347
  	}
  	*dest = src;
  	return rc;
  }
e9d376f0f   Jason Baron   dynamic debug: co...
348
349
  /*
   * Parse words[] as a ddebug query specification, which is a series
952e934d7   Greg Kroah-Hartman   Revert "dyndbg: a...
350
   * of (keyword, value) pairs chosen from these possibilities:
e9d376f0f   Jason Baron   dynamic debug: co...
351
352
353
354
355
356
357
358
   *
   * func <function-name>
   * file <full-pathname>
   * file <base-filename>
   * module <module-name>
   * format <escaped-string-to-find-in-format>
   * line <lineno>
   * line <first-lineno>-<last-lineno> // where either may be empty
820874c75   Jim Cromie   dynamic_debug: ti...
359
360
361
   *
   * Only 1 of each type is allowed.
   * Returns 0 on success, <0 on error.
e9d376f0f   Jason Baron   dynamic debug: co...
362
363
   */
  static int ddebug_parse_query(char *words[], int nwords,
8e59b5cfb   Jim Cromie   dynamic_debug: ad...
364
  			struct ddebug_query *query, const char *modname)
e9d376f0f   Jason Baron   dynamic debug: co...
365
366
  {
  	unsigned int i;
bd8c154a6   jbaron@akamai.com   dynamic debug: li...
367
  	int rc = 0;
aaebe329b   Jim Cromie   dyndbg: accept 'f...
368
  	char *fline;
952e934d7   Greg Kroah-Hartman   Revert "dyndbg: a...
369
370
371
372
373
374
375
  
  	/* check we have an even number of words */
  	if (nwords % 2 != 0) {
  		pr_err("expecting pairs of match-spec <value>
  ");
  		return -EINVAL;
  	}
e9d376f0f   Jason Baron   dynamic debug: co...
376

7f6e1f307   Greg Kroah-Hartman   Revert "dyndbg: f...
377
  	if (modname)
8e59b5cfb   Jim Cromie   dynamic_debug: ad...
378
379
  		/* support $modname.dyndbg=<multiple queries> */
  		query->module = modname;
952e934d7   Greg Kroah-Hartman   Revert "dyndbg: a...
380
  	for (i = 0; i < nwords; i += 2) {
e5e5fcef6   Jim Cromie   dyndbg: use keywo...
381
382
383
384
385
386
387
  		char *keyword = words[i];
  		char *arg = words[i+1];
  
  		if (!strcmp(keyword, "func")) {
  			rc = check_set(&query->function, arg, "func");
  		} else if (!strcmp(keyword, "file")) {
  			if (check_set(&query->filename, arg, "file"))
aaebe329b   Jim Cromie   dyndbg: accept 'f...
388
389
390
391
392
  				return -EINVAL;
  
  			/* tail :$info is function or line-range */
  			fline = strchr(query->filename, ':');
  			if (!fline)
7b1ae2482   Shuo Chen   dyndbg: fix parsi...
393
  				continue;
aaebe329b   Jim Cromie   dyndbg: accept 'f...
394
395
396
397
398
399
400
401
402
  			*fline++ = '\0';
  			if (isalpha(*fline) || *fline == '*' || *fline == '?') {
  				/* take as function name */
  				if (check_set(&query->function, fline, "func"))
  					return -EINVAL;
  			} else {
  				if (parse_linerange(query, fline))
  					return -EINVAL;
  			}
e5e5fcef6   Jim Cromie   dyndbg: use keywo...
403
404
405
406
  		} else if (!strcmp(keyword, "module")) {
  			rc = check_set(&query->module, arg, "module");
  		} else if (!strcmp(keyword, "format")) {
  			string_unescape_inplace(arg, UNESCAPE_SPACE |
d338b1379   Andy Shevchenko   dynamic_debug: re...
407
408
  							    UNESCAPE_OCTAL |
  							    UNESCAPE_SPECIAL);
e5e5fcef6   Jim Cromie   dyndbg: use keywo...
409
410
411
  			rc = check_set(&query->format, arg, "format");
  		} else if (!strcmp(keyword, "line")) {
  			if (parse_linerange(query, arg))
e9d376f0f   Jason Baron   dynamic debug: co...
412
  				return -EINVAL;
e9d376f0f   Jason Baron   dynamic debug: co...
413
  		} else {
e5e5fcef6   Jim Cromie   dyndbg: use keywo...
414
415
  			pr_err("unknown keyword \"%s\"
  ", keyword);
e9d376f0f   Jason Baron   dynamic debug: co...
416
417
  			return -EINVAL;
  		}
820874c75   Jim Cromie   dynamic_debug: ti...
418
419
  		if (rc)
  			return rc;
e9d376f0f   Jason Baron   dynamic debug: co...
420
  	}
574b3725e   Jim Cromie   dynamic_debug: fa...
421
  	vpr_info_dq(query, "parsed");
e9d376f0f   Jason Baron   dynamic debug: co...
422
423
424
425
426
427
428
429
430
  	return 0;
  }
  
  /*
   * Parse `str' as a flags specification, format [-+=][p]+.
   * Sets up *maskp and *flagsp to be used when changing the
   * flags fields of matched _ddebug's.  Returns 0 on success
   * or <0 on error.
   */
84da83a6f   Jim Cromie   dyndbg: combine f...
431
  static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
e9d376f0f   Jason Baron   dynamic debug: co...
432
  {
84da83a6f   Jim Cromie   dyndbg: combine f...
433
  	int op, i;
e9d376f0f   Jason Baron   dynamic debug: co...
434
435
436
437
438
439
440
441
  
  	switch (*str) {
  	case '+':
  	case '-':
  	case '=':
  		op = *str++;
  		break;
  	default:
18c216c53   Jim Cromie   dynamic_debug: ad...
442
443
  		pr_err("bad flag-op %c, at start of %s
  ", *str, str);
e9d376f0f   Jason Baron   dynamic debug: co...
444
445
  		return -EINVAL;
  	}
b8ccd5dee   Jim Cromie   dynamic_debug: re...
446
447
  	vpr_info("op='%c'
  ", op);
e9d376f0f   Jason Baron   dynamic debug: co...
448

f657fd21e   Joe Perches   dynamic_debug: Fi...
449
  	for (; *str ; ++str) {
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
450
451
  		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
  			if (*str == opt_array[i].opt_char) {
84da83a6f   Jim Cromie   dyndbg: combine f...
452
  				modifiers->flags |= opt_array[i].flag;
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
453
454
  				break;
  			}
e9d376f0f   Jason Baron   dynamic debug: co...
455
  		}
18c216c53   Jim Cromie   dynamic_debug: ad...
456
  		if (i < 0) {
0b8f96be9   Jim Cromie   dyndbg: fix pr_er...
457
458
  			pr_err("unknown flag '%c'
  ", *str);
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
459
  			return -EINVAL;
18c216c53   Jim Cromie   dynamic_debug: ad...
460
  		}
e9d376f0f   Jason Baron   dynamic debug: co...
461
  	}
84da83a6f   Jim Cromie   dyndbg: combine f...
462
463
  	vpr_info("flags=0x%x
  ", modifiers->flags);
e9d376f0f   Jason Baron   dynamic debug: co...
464

84da83a6f   Jim Cromie   dyndbg: combine f...
465
  	/* calculate final flags, mask based upon op */
e9d376f0f   Jason Baron   dynamic debug: co...
466
467
  	switch (op) {
  	case '=':
84da83a6f   Jim Cromie   dyndbg: combine f...
468
469
  		/* modifiers->flags already set */
  		modifiers->mask = 0;
e9d376f0f   Jason Baron   dynamic debug: co...
470
471
  		break;
  	case '+':
84da83a6f   Jim Cromie   dyndbg: combine f...
472
  		modifiers->mask = ~0U;
e9d376f0f   Jason Baron   dynamic debug: co...
473
474
  		break;
  	case '-':
84da83a6f   Jim Cromie   dyndbg: combine f...
475
476
  		modifiers->mask = ~modifiers->flags;
  		modifiers->flags = 0;
e9d376f0f   Jason Baron   dynamic debug: co...
477
478
  		break;
  	}
84da83a6f   Jim Cromie   dyndbg: combine f...
479
480
  	vpr_info("*flagsp=0x%x *maskp=0x%x
  ", modifiers->flags, modifiers->mask);
e9d376f0f   Jason Baron   dynamic debug: co...
481
482
  	return 0;
  }
8e59b5cfb   Jim Cromie   dynamic_debug: ad...
483
  static int ddebug_exec_query(char *query_string, const char *modname)
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
484
  {
84da83a6f   Jim Cromie   dyndbg: combine f...
485
  	struct flag_settings modifiers = {};
9c9d0acbe   Jim Cromie   dyndbg: prefer de...
486
  	struct ddebug_query query = {};
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
487
  #define MAXWORDS 9
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
488
  	int nwords, nfound;
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
489
490
491
  	char *words[MAXWORDS];
  
  	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
18c216c53   Jim Cromie   dynamic_debug: ad...
492
493
494
  	if (nwords <= 0) {
  		pr_err("tokenize failed
  ");
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
495
  		return -EINVAL;
18c216c53   Jim Cromie   dynamic_debug: ad...
496
497
  	}
  	/* check flags 1st (last arg) so query is pairs of spec,val */
84da83a6f   Jim Cromie   dyndbg: combine f...
498
  	if (ddebug_parse_flags(words[nwords-1], &modifiers)) {
18c216c53   Jim Cromie   dynamic_debug: ad...
499
500
  		pr_err("flags parse failed
  ");
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
501
  		return -EINVAL;
18c216c53   Jim Cromie   dynamic_debug: ad...
502
503
504
505
  	}
  	if (ddebug_parse_query(words, nwords-1, &query, modname)) {
  		pr_err("query parse failed
  ");
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
506
  		return -EINVAL;
18c216c53   Jim Cromie   dynamic_debug: ad...
507
  	}
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
508
  	/* actually go and implement the change */
84da83a6f   Jim Cromie   dyndbg: combine f...
509
  	nfound = ddebug_change(&query, &modifiers);
f657fd21e   Joe Perches   dynamic_debug: Fi...
510
  	vpr_info_dq(&query, nfound ? "applied" : "no-match");
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
511
512
513
514
515
516
517
518
  
  	return nfound;
  }
  
  /* handle multiple queries in query string, continue on error, return
     last error or number of matching callsites.  Module name is either
     in param (for boot arg) or perhaps in query string.
  */
a2d375eda   Jim Cromie   dyndbg: refine ex...
519
  static int ddebug_exec_queries(char *query, const char *modname)
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
520
521
522
523
524
525
526
527
528
529
530
531
532
  {
  	char *split;
  	int i, errs = 0, exitcode = 0, rc, nfound = 0;
  
  	for (i = 0; query; query = split) {
  		split = strpbrk(query, ";
  ");
  		if (split)
  			*split++ = '\0';
  
  		query = skip_spaces(query);
  		if (!query || !*query || *query == '#')
  			continue;
b8ccd5dee   Jim Cromie   dynamic_debug: re...
533
534
  		vpr_info("query %d: \"%s\"
  ", i, query);
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
535

8e59b5cfb   Jim Cromie   dynamic_debug: ad...
536
  		rc = ddebug_exec_query(query, modname);
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
537
538
539
  		if (rc < 0) {
  			errs++;
  			exitcode = rc;
f657fd21e   Joe Perches   dynamic_debug: Fi...
540
  		} else {
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
541
  			nfound += rc;
f657fd21e   Joe Perches   dynamic_debug: Fi...
542
  		}
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
543
544
  		i++;
  	}
b8ccd5dee   Jim Cromie   dynamic_debug: re...
545
546
  	vpr_info("processed %d queries, with %d matches, %d errs
  ",
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
547
548
549
550
551
  		 i, nfound, errs);
  
  	if (exitcode)
  		return exitcode;
  	return nfound;
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
552
  }
a2d375eda   Jim Cromie   dyndbg: refine ex...
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  
  /**
   * dynamic_debug_exec_queries - select and change dynamic-debug prints
   * @query: query-string described in admin-guide/dynamic-debug-howto
   * @modname: string containing module name, usually &module.mod_name
   *
   * This uses the >/proc/dynamic_debug/control reader, allowing module
   * authors to modify their dynamic-debug callsites. The modname is
   * canonically struct module.mod_name, but can also be null or a
   * module-wildcard, for example: "drm*".
   */
  int dynamic_debug_exec_queries(const char *query, const char *modname)
  {
  	int rc;
3577afb00   Jim Cromie   dyndbg: fix use b...
567
  	char *qry; /* writable copy of query */
a2d375eda   Jim Cromie   dyndbg: refine ex...
568

3577afb00   Jim Cromie   dyndbg: fix use b...
569
570
571
572
573
574
575
  	if (!query) {
  		pr_err("non-null query/command string expected
  ");
  		return -EINVAL;
  	}
  	qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
  	if (!qry)
a2d375eda   Jim Cromie   dyndbg: refine ex...
576
577
578
579
580
581
582
  		return -ENOMEM;
  
  	rc = ddebug_exec_queries(qry, modname);
  	kfree(qry);
  	return rc;
  }
  EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
583

431625dac   Jason Baron   dynamic_debug: us...
584
585
586
587
588
589
590
591
  #define PREFIX_SIZE 64
  
  static int remaining(int wrote)
  {
  	if (PREFIX_SIZE - wrote > 0)
  		return PREFIX_SIZE - wrote;
  	return 0;
  }
640d1eaff   Jim Cromie   dyndbg: avoid cal...
592
  static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
593
  {
431625dac   Jason Baron   dynamic_debug: us...
594
595
  	int pos_after_tid;
  	int pos = 0;
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
596

431625dac   Jason Baron   dynamic_debug: us...
597
  	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
598
  		if (in_interrupt())
798efc60e   Joe Perches   dev_dbg/dynamic_d...
599
  			pos += snprintf(buf + pos, remaining(pos), "<intr> ");
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
600
  		else
431625dac   Jason Baron   dynamic_debug: us...
601
  			pos += snprintf(buf + pos, remaining(pos), "[%d] ",
798efc60e   Joe Perches   dev_dbg/dynamic_d...
602
  					task_pid_vnr(current));
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
603
  	}
431625dac   Jason Baron   dynamic_debug: us...
604
605
606
  	pos_after_tid = pos;
  	if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
  		pos += snprintf(buf + pos, remaining(pos), "%s:",
798efc60e   Joe Perches   dev_dbg/dynamic_d...
607
  				desc->modname);
431625dac   Jason Baron   dynamic_debug: us...
608
609
  	if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
  		pos += snprintf(buf + pos, remaining(pos), "%s:",
798efc60e   Joe Perches   dev_dbg/dynamic_d...
610
  				desc->function);
431625dac   Jason Baron   dynamic_debug: us...
611
  	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
07100be7e   Jim Cromie   dynamic_debug: fi...
612
  		pos += snprintf(buf + pos, remaining(pos), "%d:",
798efc60e   Joe Perches   dev_dbg/dynamic_d...
613
  				desc->lineno);
431625dac   Jason Baron   dynamic_debug: us...
614
615
616
617
  	if (pos - pos_after_tid)
  		pos += snprintf(buf + pos, remaining(pos), " ");
  	if (pos >= PREFIX_SIZE)
  		buf[PREFIX_SIZE - 1] = '\0';
6c2140ee0   Joe Perches   dynamic_debug: Co...
618

431625dac   Jason Baron   dynamic_debug: us...
619
  	return buf;
6c2140ee0   Joe Perches   dynamic_debug: Co...
620
  }
640d1eaff   Jim Cromie   dyndbg: avoid cal...
621
622
623
624
625
626
  static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf)
  {
  	if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY))
  		return __dynamic_emit_prefix(desc, buf);
  	return buf;
  }
906d20153   Joe Perches   dynamic_debug: ch...
627
  void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
628
629
  {
  	va_list args;
431625dac   Jason Baron   dynamic_debug: us...
630
  	struct va_format vaf;
640d1eaff   Jim Cromie   dyndbg: avoid cal...
631
  	char buf[PREFIX_SIZE] = "";
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
632
633
634
635
636
  
  	BUG_ON(!descriptor);
  	BUG_ON(!fmt);
  
  	va_start(args, fmt);
798efc60e   Joe Perches   dev_dbg/dynamic_d...
637

431625dac   Jason Baron   dynamic_debug: us...
638
639
  	vaf.fmt = fmt;
  	vaf.va = &args;
798efc60e   Joe Perches   dev_dbg/dynamic_d...
640

906d20153   Joe Perches   dynamic_debug: ch...
641
  	printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
798efc60e   Joe Perches   dev_dbg/dynamic_d...
642

8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
643
  	va_end(args);
8ba6ebf58   Bart Van Assche   Dynamic debug: Ad...
644
645
  }
  EXPORT_SYMBOL(__dynamic_pr_debug);
906d20153   Joe Perches   dynamic_debug: ch...
646
  void __dynamic_dev_dbg(struct _ddebug *descriptor,
cbc466355   Joe Perches   dynamic_debug: Ad...
647
648
649
650
  		      const struct device *dev, const char *fmt, ...)
  {
  	struct va_format vaf;
  	va_list args;
cbc466355   Joe Perches   dynamic_debug: Ad...
651
652
653
654
655
  
  	BUG_ON(!descriptor);
  	BUG_ON(!fmt);
  
  	va_start(args, fmt);
798efc60e   Joe Perches   dev_dbg/dynamic_d...
656

cbc466355   Joe Perches   dynamic_debug: Ad...
657
658
  	vaf.fmt = fmt;
  	vaf.va = &args;
798efc60e   Joe Perches   dev_dbg/dynamic_d...
659
660
  
  	if (!dev) {
906d20153   Joe Perches   dynamic_debug: ch...
661
  		printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
798efc60e   Joe Perches   dev_dbg/dynamic_d...
662
  	} else {
640d1eaff   Jim Cromie   dyndbg: avoid cal...
663
  		char buf[PREFIX_SIZE] = "";
798efc60e   Joe Perches   dev_dbg/dynamic_d...
664

a39d4a857   Joe Perches   printk: add and u...
665
  		dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",
906d20153   Joe Perches   dynamic_debug: ch...
666
667
668
  				dynamic_emit_prefix(descriptor, buf),
  				dev_driver_string(dev), dev_name(dev),
  				&vaf);
798efc60e   Joe Perches   dev_dbg/dynamic_d...
669
  	}
cbc466355   Joe Perches   dynamic_debug: Ad...
670
  	va_end(args);
cbc466355   Joe Perches   dynamic_debug: Ad...
671
672
  }
  EXPORT_SYMBOL(__dynamic_dev_dbg);
0feefd978   Jason Baron   dynamic_debug: fi...
673
  #ifdef CONFIG_NET
906d20153   Joe Perches   dynamic_debug: ch...
674
675
  void __dynamic_netdev_dbg(struct _ddebug *descriptor,
  			  const struct net_device *dev, const char *fmt, ...)
ffa10cb47   Jason Baron   dynamic_debug: ma...
676
677
678
  {
  	struct va_format vaf;
  	va_list args;
ffa10cb47   Jason Baron   dynamic_debug: ma...
679
680
681
682
683
  
  	BUG_ON(!descriptor);
  	BUG_ON(!fmt);
  
  	va_start(args, fmt);
b004ff497   Joe Perches   netdev_printk/dyn...
684

ffa10cb47   Jason Baron   dynamic_debug: ma...
685
686
  	vaf.fmt = fmt;
  	vaf.va = &args;
b004ff497   Joe Perches   netdev_printk/dyn...
687
688
  
  	if (dev && dev->dev.parent) {
640d1eaff   Jim Cromie   dyndbg: avoid cal...
689
  		char buf[PREFIX_SIZE] = "";
666f355f3   Joe Perches   device and dynami...
690

a39d4a857   Joe Perches   printk: add and u...
691
  		dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,
906d20153   Joe Perches   dynamic_debug: ch...
692
693
694
695
696
697
  				"%s%s %s %s%s: %pV",
  				dynamic_emit_prefix(descriptor, buf),
  				dev_driver_string(dev->dev.parent),
  				dev_name(dev->dev.parent),
  				netdev_name(dev), netdev_reg_state(dev),
  				&vaf);
b004ff497   Joe Perches   netdev_printk/dyn...
698
  	} else if (dev) {
906d20153   Joe Perches   dynamic_debug: ch...
699
700
  		printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev),
  		       netdev_reg_state(dev), &vaf);
b004ff497   Joe Perches   netdev_printk/dyn...
701
  	} else {
906d20153   Joe Perches   dynamic_debug: ch...
702
  		printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
b004ff497   Joe Perches   netdev_printk/dyn...
703
  	}
ffa10cb47   Jason Baron   dynamic_debug: ma...
704
  	va_end(args);
ffa10cb47   Jason Baron   dynamic_debug: ma...
705
706
  }
  EXPORT_SYMBOL(__dynamic_netdev_dbg);
0feefd978   Jason Baron   dynamic_debug: fi...
707
  #endif
923abb9d7   Gal Pressman   RDMA/core: Introd...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  #if IS_ENABLED(CONFIG_INFINIBAND)
  
  void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
  			 const struct ib_device *ibdev, const char *fmt, ...)
  {
  	struct va_format vaf;
  	va_list args;
  
  	va_start(args, fmt);
  
  	vaf.fmt = fmt;
  	vaf.va = &args;
  
  	if (ibdev && ibdev->dev.parent) {
640d1eaff   Jim Cromie   dyndbg: avoid cal...
722
  		char buf[PREFIX_SIZE] = "";
923abb9d7   Gal Pressman   RDMA/core: Introd...
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  
  		dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent,
  				"%s%s %s %s: %pV",
  				dynamic_emit_prefix(descriptor, buf),
  				dev_driver_string(ibdev->dev.parent),
  				dev_name(ibdev->dev.parent),
  				dev_name(&ibdev->dev),
  				&vaf);
  	} else if (ibdev) {
  		printk(KERN_DEBUG "%s: %pV", dev_name(&ibdev->dev), &vaf);
  	} else {
  		printk(KERN_DEBUG "(NULL ib_device): %pV", &vaf);
  	}
  
  	va_end(args);
  }
  EXPORT_SYMBOL(__dynamic_ibdev_dbg);
  
  #endif
bc757f6f5   Jim Cromie   dynamic_debug: re...
742
743
  #define DDEBUG_STRING_SIZE 1024
  static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE];
a648ec05b   Thomas Renninger   Dynamic Debug: In...
744
745
  static __init int ddebug_setup_query(char *str)
  {
bc757f6f5   Jim Cromie   dynamic_debug: re...
746
  	if (strlen(str) >= DDEBUG_STRING_SIZE) {
4ad275e5c   Joe Perches   dynamic_debug: Co...
747
748
  		pr_warn("ddebug boot param string too large
  ");
a648ec05b   Thomas Renninger   Dynamic Debug: In...
749
750
  		return 0;
  	}
bc757f6f5   Jim Cromie   dynamic_debug: re...
751
  	strlcpy(ddebug_setup_string, str, DDEBUG_STRING_SIZE);
a648ec05b   Thomas Renninger   Dynamic Debug: In...
752
753
754
755
  	return 1;
  }
  
  __setup("ddebug_query=", ddebug_setup_query);
e9d376f0f   Jason Baron   dynamic debug: co...
756
  /*
a14e312ad   Andrew Halaney   dyndbg: make dynd...
757
758
759
760
761
762
763
764
765
766
767
768
   * Install a noop handler to make dyndbg look like a normal kernel cli param.
   * This avoids warnings about dyndbg being an unknown cli param when supplied
   * by a user.
   */
  static __init int dyndbg_setup(char *str)
  {
  	return 1;
  }
  
  __setup("dyndbg=", dyndbg_setup);
  
  /*
231821d4c   Masatake YAMATO   dynamic_debug: fi...
769
   * File_ops->write method for <debugfs>/dynamic_debug/control.  Gathers the
e9d376f0f   Jason Baron   dynamic debug: co...
770
771
   * command text from userspace, parses and executes it.
   */
7281491c5   Jim Cromie   dynamic_debug: en...
772
  #define USER_BUF_PAGE 4096
e9d376f0f   Jason Baron   dynamic debug: co...
773
774
775
  static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
  				  size_t len, loff_t *offp)
  {
7281491c5   Jim Cromie   dynamic_debug: en...
776
  	char *tmpbuf;
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
777
  	int ret;
e9d376f0f   Jason Baron   dynamic debug: co...
778
779
780
  
  	if (len == 0)
  		return 0;
7281491c5   Jim Cromie   dynamic_debug: en...
781
782
783
  	if (len > USER_BUF_PAGE - 1) {
  		pr_warn("expected <%d bytes into control
  ", USER_BUF_PAGE);
e9d376f0f   Jason Baron   dynamic debug: co...
784
  		return -E2BIG;
7281491c5   Jim Cromie   dynamic_debug: en...
785
  	}
16e5c1fc3   Al Viro   convert a bunch o...
786
787
788
  	tmpbuf = memdup_user_nul(ubuf, len);
  	if (IS_ERR(tmpbuf))
  		return PTR_ERR(tmpbuf);
b8ccd5dee   Jim Cromie   dynamic_debug: re...
789
790
  	vpr_info("read %d bytes from userspace
  ", (int)len);
e9d376f0f   Jason Baron   dynamic debug: co...
791

8e59b5cfb   Jim Cromie   dynamic_debug: ad...
792
  	ret = ddebug_exec_queries(tmpbuf, NULL);
7281491c5   Jim Cromie   dynamic_debug: en...
793
  	kfree(tmpbuf);
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
794
  	if (ret < 0)
fd89cfb87   Thomas Renninger   Dynamic Debug: Sp...
795
  		return ret;
e9d376f0f   Jason Baron   dynamic debug: co...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
  
  	*offp += len;
  	return len;
  }
  
  /*
   * Set the iterator to point to the first _ddebug object
   * and return a pointer to that first object.  Returns
   * NULL if there are no _ddebugs at all.
   */
  static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
  {
  	if (list_empty(&ddebug_tables)) {
  		iter->table = NULL;
  		iter->idx = 0;
  		return NULL;
  	}
  	iter->table = list_entry(ddebug_tables.next,
  				 struct ddebug_table, link);
  	iter->idx = 0;
  	return &iter->table->ddebugs[iter->idx];
  }
  
  /*
   * Advance the iterator to point to the next _ddebug
   * object from the one the iterator currently points at,
   * and returns a pointer to the new _ddebug.  Returns
   * NULL if the iterator has seen all the _ddebugs.
   */
  static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
  {
  	if (iter->table == NULL)
  		return NULL;
  	if (++iter->idx == iter->table->num_ddebugs) {
  		/* iterate to next table */
  		iter->idx = 0;
  		if (list_is_last(&iter->table->link, &ddebug_tables)) {
  			iter->table = NULL;
  			return NULL;
  		}
  		iter->table = list_entry(iter->table->link.next,
  					 struct ddebug_table, link);
  	}
  	return &iter->table->ddebugs[iter->idx];
  }
  
  /*
   * Seq_ops start method.  Called at the start of every
   * read() call from userspace.  Takes the ddebug_lock and
   * seeks the seq_file's iterator to the given position.
   */
  static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
  {
  	struct ddebug_iter *iter = m->private;
  	struct _ddebug *dp;
  	int n = *pos;
e9d376f0f   Jason Baron   dynamic debug: co...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  	mutex_lock(&ddebug_lock);
  
  	if (!n)
  		return SEQ_START_TOKEN;
  	if (n < 0)
  		return NULL;
  	dp = ddebug_iter_first(iter);
  	while (dp != NULL && --n > 0)
  		dp = ddebug_iter_next(iter);
  	return dp;
  }
  
  /*
   * Seq_ops next method.  Called several times within a read()
   * call from userspace, with ddebug_lock held.  Walks to the
   * next _ddebug object with a special case for the header line.
   */
  static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
  {
  	struct ddebug_iter *iter = m->private;
  	struct _ddebug *dp;
e9d376f0f   Jason Baron   dynamic debug: co...
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  	if (p == SEQ_START_TOKEN)
  		dp = ddebug_iter_first(iter);
  	else
  		dp = ddebug_iter_next(iter);
  	++*pos;
  	return dp;
  }
  
  /*
   * Seq_ops show method.  Called several times within a read()
   * call from userspace, with ddebug_lock held.  Formats the
   * current _ddebug as a single human-readable line, with a
   * special case for the header line.
   */
  static int ddebug_proc_show(struct seq_file *m, void *p)
  {
  	struct ddebug_iter *iter = m->private;
  	struct _ddebug *dp = p;
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
891
  	struct flagsbuf flags;
e9d376f0f   Jason Baron   dynamic debug: co...
892

e9d376f0f   Jason Baron   dynamic debug: co...
893
894
  	if (p == SEQ_START_TOKEN) {
  		seq_puts(m,
f657fd21e   Joe Perches   dynamic_debug: Fi...
895
896
  			 "# filename:lineno [module]function flags format
  ");
e9d376f0f   Jason Baron   dynamic debug: co...
897
898
  		return 0;
  	}
5ca7d2a6c   Jim Cromie   dynamic_debug: de...
899
  	seq_printf(m, "%s:%u [%s]%s =%s \"",
f657fd21e   Joe Perches   dynamic_debug: Fi...
900
901
  		   trim_prefix(dp->filename), dp->lineno,
  		   iter->table->mod_name, dp->function,
f678ce8cc   Jim Cromie   dyndbg: fix a BUG...
902
  		   ddebug_describe_flags(dp->flags, &flags));
e9d376f0f   Jason Baron   dynamic debug: co...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
  	seq_escape(m, dp->format, "\t\r
  \"");
  	seq_puts(m, "\"
  ");
  
  	return 0;
  }
  
  /*
   * Seq_ops stop method.  Called at the end of each read()
   * call from userspace.  Drops ddebug_lock.
   */
  static void ddebug_proc_stop(struct seq_file *m, void *p)
  {
e9d376f0f   Jason Baron   dynamic debug: co...
917
918
919
920
921
922
923
924
925
  	mutex_unlock(&ddebug_lock);
  }
  
  static const struct seq_operations ddebug_proc_seqops = {
  	.start = ddebug_proc_start,
  	.next = ddebug_proc_next,
  	.show = ddebug_proc_show,
  	.stop = ddebug_proc_stop
  };
e9d376f0f   Jason Baron   dynamic debug: co...
926
927
  static int ddebug_proc_open(struct inode *inode, struct file *file)
  {
4bad78c55   Rob Jones   lib/dynamic_debug...
928
929
  	return seq_open_private(file, &ddebug_proc_seqops,
  				sizeof(struct ddebug_iter));
e9d376f0f   Jason Baron   dynamic debug: co...
930
931
932
933
934
935
936
937
938
939
  }
  
  static const struct file_operations ddebug_proc_fops = {
  	.owner = THIS_MODULE,
  	.open = ddebug_proc_open,
  	.read = seq_read,
  	.llseek = seq_lseek,
  	.release = seq_release_private,
  	.write = ddebug_proc_write
  };
239a5791f   Greg Kroah-Hartman   dynamic_debug: al...
940
941
942
943
944
945
946
  static const struct proc_ops proc_fops = {
  	.proc_open = ddebug_proc_open,
  	.proc_read = seq_read,
  	.proc_lseek = seq_lseek,
  	.proc_release = seq_release_private,
  	.proc_write = ddebug_proc_write
  };
e9d376f0f   Jason Baron   dynamic debug: co...
947
948
949
950
951
952
953
954
  /*
   * Allocate a new ddebug_table for the given module
   * and add it to the global list.
   */
  int ddebug_add_module(struct _ddebug *tab, unsigned int n,
  			     const char *name)
  {
  	struct ddebug_table *dt;
e9d376f0f   Jason Baron   dynamic debug: co...
955
956
  
  	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
513770f54   Rasmus Villemoes   dynamic_debug: mo...
957
958
959
  	if (dt == NULL) {
  		pr_err("error adding module: %s
  ", name);
e9d376f0f   Jason Baron   dynamic debug: co...
960
  		return -ENOMEM;
513770f54   Rasmus Villemoes   dynamic_debug: mo...
961
  	}
cdf6d0069   Rasmus Villemoes   dynamic_debug: do...
962
963
964
965
966
967
968
  	/*
  	 * For built-in modules, name lives in .rodata and is
  	 * immortal. For loaded modules, name points at the name[]
  	 * member of struct module, which lives at least as long as
  	 * this struct ddebug_table.
  	 */
  	dt->mod_name = name;
e9d376f0f   Jason Baron   dynamic debug: co...
969
  	dt->num_ddebugs = n;
e9d376f0f   Jason Baron   dynamic debug: co...
970
971
972
  	dt->ddebugs = tab;
  
  	mutex_lock(&ddebug_lock);
47e9f5a82   Jim Cromie   dyndbg: make ddeb...
973
  	list_add(&dt->link, &ddebug_tables);
e9d376f0f   Jason Baron   dynamic debug: co...
974
  	mutex_unlock(&ddebug_lock);
b52a95eac   Jim Cromie   dyndbg: give %3u ...
975
976
  	v2pr_info("%3u debug prints in module %s
  ", n, dt->mod_name);
e9d376f0f   Jason Baron   dynamic debug: co...
977
978
  	return 0;
  }
e9d376f0f   Jason Baron   dynamic debug: co...
979

6ab676e96   Jim Cromie   dynamic_debug: co...
980
981
982
  /* helper for ddebug_dyndbg_(boot|module)_param_cb */
  static int ddebug_dyndbg_param_cb(char *param, char *val,
  				const char *modname, int on_err)
b48420c1d   Jim Cromie   dynamic_debug: ma...
983
  {
b48420c1d   Jim Cromie   dynamic_debug: ma...
984
985
986
987
  	char *sep;
  
  	sep = strchr(param, '.');
  	if (sep) {
6ab676e96   Jim Cromie   dynamic_debug: co...
988
  		/* needed only for ddebug_dyndbg_boot_param_cb */
b48420c1d   Jim Cromie   dynamic_debug: ma...
989
990
991
992
993
  		*sep = '\0';
  		modname = param;
  		param = sep + 1;
  	}
  	if (strcmp(param, "dyndbg"))
6ab676e96   Jim Cromie   dynamic_debug: co...
994
  		return on_err; /* determined by caller */
b48420c1d   Jim Cromie   dynamic_debug: ma...
995

8e59b5cfb   Jim Cromie   dynamic_debug: ad...
996
  	ddebug_exec_queries((val ? val : "+p"), modname);
9dbbc3b9d   Zhen Lei   lib: fix spelling...
997
  	return 0; /* query failure shouldn't stop module load */
b48420c1d   Jim Cromie   dynamic_debug: ma...
998
  }
6ab676e96   Jim Cromie   dynamic_debug: co...
999
1000
  /* handle both dyndbg and $module.dyndbg params at boot */
  static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
ecc861705   Luis R. Rodriguez   module: add extra...
1001
  				const char *unused, void *arg)
b48420c1d   Jim Cromie   dynamic_debug: ma...
1002
  {
6ab676e96   Jim Cromie   dynamic_debug: co...
1003
1004
1005
1006
  	vpr_info("%s=\"%s\"
  ", param, val);
  	return ddebug_dyndbg_param_cb(param, val, NULL, 0);
  }
b48420c1d   Jim Cromie   dynamic_debug: ma...
1007

6ab676e96   Jim Cromie   dynamic_debug: co...
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  /*
   * modprobe foo finds foo.params in boot-args, strips "foo.", and
   * passes them to load_module().  This callback gets unknown params,
   * processes dyndbg params, rejects others.
   */
  int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
  {
  	vpr_info("module: %s %s=\"%s\"
  ", module, param, val);
  	return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);
b48420c1d   Jim Cromie   dynamic_debug: ma...
1018
  }
e9d376f0f   Jason Baron   dynamic debug: co...
1019
1020
1021
  static void ddebug_table_free(struct ddebug_table *dt)
  {
  	list_del_init(&dt->link);
e9d376f0f   Jason Baron   dynamic debug: co...
1022
1023
1024
1025
1026
1027
1028
  	kfree(dt);
  }
  
  /*
   * Called in response to a module being unloaded.  Removes
   * any ddebug_table's which point at the module.
   */
ff49d74ad   Yehuda Sadeh   module: initializ...
1029
  int ddebug_remove_module(const char *mod_name)
e9d376f0f   Jason Baron   dynamic debug: co...
1030
1031
1032
  {
  	struct ddebug_table *dt, *nextdt;
  	int ret = -ENOENT;
481c0e33f   Jim Cromie   dyndbg: refine de...
1033
1034
  	v2pr_info("removing module \"%s\"
  ", mod_name);
e9d376f0f   Jason Baron   dynamic debug: co...
1035
1036
1037
  
  	mutex_lock(&ddebug_lock);
  	list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
4573fe154   Rasmus Villemoes   dynamic_debug: us...
1038
  		if (dt->mod_name == mod_name) {
e9d376f0f   Jason Baron   dynamic debug: co...
1039
1040
  			ddebug_table_free(dt);
  			ret = 0;
4573fe154   Rasmus Villemoes   dynamic_debug: us...
1041
  			break;
e9d376f0f   Jason Baron   dynamic debug: co...
1042
1043
1044
1045
1046
  		}
  	}
  	mutex_unlock(&ddebug_lock);
  	return ret;
  }
e9d376f0f   Jason Baron   dynamic debug: co...
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  
  static void ddebug_remove_all_tables(void)
  {
  	mutex_lock(&ddebug_lock);
  	while (!list_empty(&ddebug_tables)) {
  		struct ddebug_table *dt = list_entry(ddebug_tables.next,
  						      struct ddebug_table,
  						      link);
  		ddebug_table_free(dt);
  	}
  	mutex_unlock(&ddebug_lock);
  }
6a5c083de   Thomas Renninger   Dynamic Debug: In...
1059
  static __initdata int ddebug_init_success;
239a5791f   Greg Kroah-Hartman   dynamic_debug: al...
1060
  static int __init dynamic_debug_init_control(void)
e9d376f0f   Jason Baron   dynamic debug: co...
1061
  {
239a5791f   Greg Kroah-Hartman   dynamic_debug: al...
1062
1063
  	struct proc_dir_entry *procfs_dir;
  	struct dentry *debugfs_dir;
6a5c083de   Thomas Renninger   Dynamic Debug: In...
1064
1065
1066
  
  	if (!ddebug_init_success)
  		return -ENODEV;
e9d376f0f   Jason Baron   dynamic debug: co...
1067

239a5791f   Greg Kroah-Hartman   dynamic_debug: al...
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  	/* Create the control file in debugfs if it is enabled */
  	if (debugfs_initialized()) {
  		debugfs_dir = debugfs_create_dir("dynamic_debug", NULL);
  		debugfs_create_file("control", 0644, debugfs_dir, NULL,
  				    &ddebug_proc_fops);
  	}
  
  	/* Also create the control file in procfs */
  	procfs_dir = proc_mkdir("dynamic_debug", NULL);
  	if (procfs_dir)
  		proc_create("control", 0644, procfs_dir, &proc_fops);
9fd714cd7   Greg Kroah-Hartman   lib: dynamic_debu...
1079

6a5c083de   Thomas Renninger   Dynamic Debug: In...
1080
1081
1082
1083
1084
1085
1086
  	return 0;
  }
  
  static int __init dynamic_debug_init(void)
  {
  	struct _ddebug *iter, *iter_start;
  	const char *modname = NULL;
b48420c1d   Jim Cromie   dynamic_debug: ma...
1087
  	char *cmdline;
6a5c083de   Thomas Renninger   Dynamic Debug: In...
1088
  	int ret = 0;
410769276   Jim Cromie   dynamic_debug: pr...
1089
  	int n = 0, entries = 0, modct = 0;
6a5c083de   Thomas Renninger   Dynamic Debug: In...
1090

e5ebffe18   Jim Cromie   dyndbg: rename __...
1091
  	if (&__start___dyndbg == &__stop___dyndbg) {
ceabef7dd   Orson Zhai   dynamic_debug: ad...
1092
1093
1094
1095
1096
1097
1098
1099
1100
  		if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
  			pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build
  ");
  			return 1;
  		}
  		pr_info("Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build
  ");
  		ddebug_init_success = 1;
  		return 0;
b5b78f838   Jim Cromie   dynamic_debug: ea...
1101
  	}
e5ebffe18   Jim Cromie   dyndbg: rename __...
1102
  	iter = __start___dyndbg;
b5b78f838   Jim Cromie   dynamic_debug: ea...
1103
1104
  	modname = iter->modname;
  	iter_start = iter;
e5ebffe18   Jim Cromie   dyndbg: rename __...
1105
  	for (; iter < __stop___dyndbg; iter++) {
410769276   Jim Cromie   dynamic_debug: pr...
1106
  		entries++;
b5b78f838   Jim Cromie   dynamic_debug: ea...
1107
  		if (strcmp(modname, iter->modname)) {
410769276   Jim Cromie   dynamic_debug: pr...
1108
  			modct++;
b5b78f838   Jim Cromie   dynamic_debug: ea...
1109
1110
  			ret = ddebug_add_module(iter_start, n, modname);
  			if (ret)
af442399f   Jim Cromie   dynamic_debug: si...
1111
  				goto out_err;
b5b78f838   Jim Cromie   dynamic_debug: ea...
1112
1113
1114
  			n = 0;
  			modname = iter->modname;
  			iter_start = iter;
e9d376f0f   Jason Baron   dynamic debug: co...
1115
  		}
b5b78f838   Jim Cromie   dynamic_debug: ea...
1116
  		n++;
e9d376f0f   Jason Baron   dynamic debug: co...
1117
  	}
b5b78f838   Jim Cromie   dynamic_debug: ea...
1118
1119
  	ret = ddebug_add_module(iter_start, n, modname);
  	if (ret)
af442399f   Jim Cromie   dynamic_debug: si...
1120
  		goto out_err;
a648ec05b   Thomas Renninger   Dynamic Debug: In...
1121

af442399f   Jim Cromie   dynamic_debug: si...
1122
  	ddebug_init_success = 1;
7af566282   Jim Cromie   dyndbg: display K...
1123
1124
1125
1126
  	vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section
  ",
  		 entries, modct, (int)((modct * sizeof(struct ddebug_table)) >> 10),
  		 (int)((entries * sizeof(struct _ddebug)) >> 10));
af442399f   Jim Cromie   dynamic_debug: si...
1127
1128
  
  	/* apply ddebug_query boot param, dont unload tables on err */
a648ec05b   Thomas Renninger   Dynamic Debug: In...
1129
  	if (ddebug_setup_string[0] != '\0') {
f657fd21e   Joe Perches   dynamic_debug: Fi...
1130
1131
  		pr_warn("ddebug_query param name is deprecated, change it to dyndbg
  ");
8e59b5cfb   Jim Cromie   dynamic_debug: ad...
1132
  		ret = ddebug_exec_queries(ddebug_setup_string, NULL);
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
1133
  		if (ret < 0)
f657fd21e   Joe Perches   dynamic_debug: Fi...
1134
1135
  			pr_warn("Invalid ddebug boot param %s
  ",
4ad275e5c   Joe Perches   dynamic_debug: Co...
1136
  				ddebug_setup_string);
a648ec05b   Thomas Renninger   Dynamic Debug: In...
1137
  		else
85f7f6c0e   Jim Cromie   dynamic_debug: pr...
1138
1139
  			pr_info("%d changes by ddebug_query
  ", ret);
a648ec05b   Thomas Renninger   Dynamic Debug: In...
1140
  	}
b48420c1d   Jim Cromie   dynamic_debug: ma...
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  	/* 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,
ecc861705   Luis R. Rodriguez   module: add extra...
1151
  		   0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb);
b48420c1d   Jim Cromie   dynamic_debug: ma...
1152
  	kfree(cmdline);
af442399f   Jim Cromie   dynamic_debug: si...
1153
  	return 0;
a648ec05b   Thomas Renninger   Dynamic Debug: In...
1154

af442399f   Jim Cromie   dynamic_debug: si...
1155
1156
  out_err:
  	ddebug_remove_all_tables();
e9d376f0f   Jason Baron   dynamic debug: co...
1157
1158
  	return 0;
  }
6a5c083de   Thomas Renninger   Dynamic Debug: In...
1159
  /* Allow early initialization for boot messages via boot param */
3ec5652ab   Jim Cromie   dynamic_debug: in...
1160
  early_initcall(dynamic_debug_init);
b48420c1d   Jim Cromie   dynamic_debug: ma...
1161

6a5c083de   Thomas Renninger   Dynamic Debug: In...
1162
  /* Debugfs setup must be done later */
239a5791f   Greg Kroah-Hartman   dynamic_debug: al...
1163
  fs_initcall(dynamic_debug_init_control);