xref: /openbmc/linux/lib/dynamic_debug.c (revision e0d77d0f38aa60ca61b3ce6e60d64fad2aa0853d)
1e9d376f0SJason Baron /*
2e9d376f0SJason Baron  * lib/dynamic_debug.c
3e9d376f0SJason Baron  *
4e9d376f0SJason Baron  * make pr_debug()/dev_dbg() calls runtime configurable based upon their
5e9d376f0SJason Baron  * source module.
6e9d376f0SJason Baron  *
7e9d376f0SJason Baron  * Copyright (C) 2008 Jason Baron <jbaron@redhat.com>
8e9d376f0SJason Baron  * By Greg Banks <gnb@melbourne.sgi.com>
9e9d376f0SJason Baron  * Copyright (c) 2008 Silicon Graphics Inc.  All Rights Reserved.
108ba6ebf5SBart Van Assche  * Copyright (C) 2011 Bart Van Assche.  All Rights Reserved.
11578b1e07SDu, Changbin  * Copyright (C) 2013 Du, Changbin <changbin.du@gmail.com>
12e9d376f0SJason Baron  */
13e9d376f0SJason Baron 
145aa9ffbbSJim Cromie #define pr_fmt(fmt) "dyndbg: " fmt
154ad275e5SJoe Perches 
16e9d376f0SJason Baron #include <linux/kernel.h>
17e9d376f0SJason Baron #include <linux/module.h>
18fef15d2fSGreg Kroah-Hartman #include <linux/moduleparam.h>
19fef15d2fSGreg Kroah-Hartman #include <linux/kallsyms.h>
20fef15d2fSGreg Kroah-Hartman #include <linux/types.h>
21e9d376f0SJason Baron #include <linux/mutex.h>
22fef15d2fSGreg Kroah-Hartman #include <linux/proc_fs.h>
23e9d376f0SJason Baron #include <linux/seq_file.h>
24fef15d2fSGreg Kroah-Hartman #include <linux/list.h>
25fef15d2fSGreg Kroah-Hartman #include <linux/sysctl.h>
26e9d376f0SJason Baron #include <linux/ctype.h>
27fef15d2fSGreg Kroah-Hartman #include <linux/string.h>
28578b1e07SDu, Changbin #include <linux/parser.h>
29d338b137SAndy Shevchenko #include <linux/string_helpers.h>
30fef15d2fSGreg Kroah-Hartman #include <linux/uaccess.h>
31e9d376f0SJason Baron #include <linux/dynamic_debug.h>
32e9d376f0SJason Baron #include <linux/debugfs.h>
335a0e3ad6STejun Heo #include <linux/slab.h>
34fef15d2fSGreg Kroah-Hartman #include <linux/jump_label.h>
358ba6ebf5SBart Van Assche #include <linux/hardirq.h>
36e8d9792aSGreg Kroah-Hartman #include <linux/sched.h>
37fef15d2fSGreg Kroah-Hartman #include <linux/device.h>
38ffa10cb4SJason Baron #include <linux/netdevice.h>
39e9d376f0SJason Baron 
40923abb9dSGal Pressman #include <rdma/ib_verbs.h>
41923abb9dSGal Pressman 
42e5ebffe1SJim Cromie extern struct _ddebug __start___dyndbg[];
43e5ebffe1SJim Cromie extern struct _ddebug __stop___dyndbg[];
4466f4006bSJim Cromie extern struct ddebug_class_map __start___dyndbg_classes[];
4566f4006bSJim Cromie extern struct ddebug_class_map __stop___dyndbg_classes[];
46e9d376f0SJason Baron 
47e9d376f0SJason Baron struct ddebug_table {
48c45f67acSJim Cromie 	struct list_head link, maps;
493e406b1dSRasmus Villemoes 	const char *mod_name;
50e9d376f0SJason Baron 	unsigned int num_ddebugs;
51e9d376f0SJason Baron 	struct _ddebug *ddebugs;
52e9d376f0SJason Baron };
53e9d376f0SJason Baron 
54e9d376f0SJason Baron struct ddebug_query {
55e9d376f0SJason Baron 	const char *filename;
56e9d376f0SJason Baron 	const char *module;
57e9d376f0SJason Baron 	const char *function;
58e9d376f0SJason Baron 	const char *format;
59a4a2a427SJim Cromie 	const char *class_string;
60e9d376f0SJason Baron 	unsigned int first_lineno, last_lineno;
61e9d376f0SJason Baron };
62e9d376f0SJason Baron 
63e9d376f0SJason Baron struct ddebug_iter {
64e9d376f0SJason Baron 	struct ddebug_table *table;
65773beabbSJim Cromie 	int idx;
66e9d376f0SJason Baron };
67e9d376f0SJason Baron 
6884da83a6SJim Cromie struct flag_settings {
6984da83a6SJim Cromie 	unsigned int flags;
7084da83a6SJim Cromie 	unsigned int mask;
7184da83a6SJim Cromie };
7284da83a6SJim Cromie 
73e9d376f0SJason Baron static DEFINE_MUTEX(ddebug_lock);
74e9d376f0SJason Baron static LIST_HEAD(ddebug_tables);
75f657fd21SJoe Perches static int verbose;
7674df138dSJim Cromie module_param(verbose, int, 0644);
7709ee10ffSJim Cromie MODULE_PARM_DESC(verbose, " dynamic_debug/control processing "
7809ee10ffSJim Cromie 		 "( 0 = off (default), 1 = module add/rm, 2 = >control summary, 3 = parsing, 4 = per-site changes)");
79e9d376f0SJason Baron 
802b678319SJim Cromie /* Return the path relative to source root */
trim_prefix(const char * path)812b678319SJim Cromie static inline const char *trim_prefix(const char *path)
822b678319SJim Cromie {
832b678319SJim Cromie 	int skip = strlen(__FILE__) - strlen("lib/dynamic_debug.c");
842b678319SJim Cromie 
852b678319SJim Cromie 	if (strncmp(path, __FILE__, skip))
862b678319SJim Cromie 		skip = 0; /* prefix mismatch, don't skip */
872b678319SJim Cromie 
882b678319SJim Cromie 	return path + skip;
892b678319SJim Cromie }
902b678319SJim Cromie 
91882f7a64SThomas Weißschuh static const struct { unsigned flag:8; char opt_char; } opt_array[] = {
928ba6ebf5SBart Van Assche 	{ _DPRINTK_FLAGS_PRINT, 'p' },
938ba6ebf5SBart Van Assche 	{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
948ba6ebf5SBart Van Assche 	{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
9531ed379bSThomas Weißschuh 	{ _DPRINTK_FLAGS_INCL_SOURCENAME, 's' },
968ba6ebf5SBart Van Assche 	{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
978ba6ebf5SBart Van Assche 	{ _DPRINTK_FLAGS_INCL_TID, 't' },
985ca7d2a6SJim Cromie 	{ _DPRINTK_FLAGS_NONE, '_' },
998ba6ebf5SBart Van Assche };
1008ba6ebf5SBart Van Assche 
101f678ce8cSJim Cromie struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
102f678ce8cSJim Cromie 
103e9d376f0SJason Baron /* format a string into buf[] which describes the _ddebug's flags */
ddebug_describe_flags(unsigned int flags,struct flagsbuf * fb)104f678ce8cSJim Cromie static char *ddebug_describe_flags(unsigned int flags, struct flagsbuf *fb)
105e9d376f0SJason Baron {
106f678ce8cSJim Cromie 	char *p = fb->buf;
1078ba6ebf5SBart Van Assche 	int i;
108e9d376f0SJason Baron 
1098ba6ebf5SBart Van Assche 	for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
110f678ce8cSJim Cromie 		if (flags & opt_array[i].flag)
1118ba6ebf5SBart Van Assche 			*p++ = opt_array[i].opt_char;
112f678ce8cSJim Cromie 	if (p == fb->buf)
1135ca7d2a6SJim Cromie 		*p++ = '_';
114e9d376f0SJason Baron 	*p = '\0';
115e9d376f0SJason Baron 
116f678ce8cSJim Cromie 	return fb->buf;
117e9d376f0SJason Baron }
118e9d376f0SJason Baron 
119481c0e33SJim Cromie #define vnpr_info(lvl, fmt, ...)				\
120574b3725SJim Cromie do {								\
121481c0e33SJim Cromie 	if (verbose >= lvl)					\
122f657fd21SJoe Perches 		pr_info(fmt, ##__VA_ARGS__);			\
123574b3725SJim Cromie } while (0)
124574b3725SJim Cromie 
125481c0e33SJim Cromie #define vpr_info(fmt, ...)	vnpr_info(1, fmt, ##__VA_ARGS__)
126481c0e33SJim Cromie #define v2pr_info(fmt, ...)	vnpr_info(2, fmt, ##__VA_ARGS__)
12709ee10ffSJim Cromie #define v3pr_info(fmt, ...)	vnpr_info(3, fmt, ##__VA_ARGS__)
12809ee10ffSJim Cromie #define v4pr_info(fmt, ...)	vnpr_info(4, fmt, ##__VA_ARGS__)
129481c0e33SJim Cromie 
vpr_info_dq(const struct ddebug_query * query,const char * msg)130f657fd21SJoe Perches static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
131f657fd21SJoe Perches {
132f657fd21SJoe Perches 	/* trim any trailing newlines */
133f657fd21SJoe Perches 	int fmtlen = 0;
134f657fd21SJoe Perches 
135f657fd21SJoe Perches 	if (query->format) {
136f657fd21SJoe Perches 		fmtlen = strlen(query->format);
137f657fd21SJoe Perches 		while (fmtlen && query->format[fmtlen - 1] == '\n')
138f657fd21SJoe Perches 			fmtlen--;
139f657fd21SJoe Perches 	}
140f657fd21SJoe Perches 
141a4a2a427SJim Cromie 	v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n",
142f657fd21SJoe Perches 		  msg,
143f62fc08fSJim Cromie 		  query->function ?: "",
144f62fc08fSJim Cromie 		  query->filename ?: "",
145f62fc08fSJim Cromie 		  query->module ?: "",
146f62fc08fSJim Cromie 		  fmtlen, query->format ?: "",
147a4a2a427SJim Cromie 		  query->first_lineno, query->last_lineno, query->class_string);
148f657fd21SJoe Perches }
149f657fd21SJoe Perches 
ddebug_find_valid_class(struct ddebug_table const * dt,const char * class_string,int * class_id)150a4a2a427SJim Cromie static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
151a4a2a427SJim Cromie 							  const char *class_string, int *class_id)
152a4a2a427SJim Cromie {
153a4a2a427SJim Cromie 	struct ddebug_class_map *map;
154a4a2a427SJim Cromie 	int idx;
155a4a2a427SJim Cromie 
156a4a2a427SJim Cromie 	list_for_each_entry(map, &dt->maps, link) {
157a4a2a427SJim Cromie 		idx = match_string(map->class_names, map->length, class_string);
158a4a2a427SJim Cromie 		if (idx >= 0) {
159a4a2a427SJim Cromie 			*class_id = idx + map->base;
160a4a2a427SJim Cromie 			return map;
161a4a2a427SJim Cromie 		}
162a4a2a427SJim Cromie 	}
163a4a2a427SJim Cromie 	*class_id = -ENOENT;
164a4a2a427SJim Cromie 	return NULL;
165a4a2a427SJim Cromie }
166a4a2a427SJim Cromie 
167a4a2a427SJim Cromie #define __outvar /* filled by callee */
168e9d376f0SJason Baron /*
16985f7f6c0SJim Cromie  * Search the tables for _ddebug's which match the given `query' and
17085f7f6c0SJim Cromie  * apply the `flags' and `mask' to them.  Returns number of matching
17185f7f6c0SJim Cromie  * callsites, normally the same as number of changes.  If verbose,
17285f7f6c0SJim Cromie  * logs the changes.  Takes ddebug_lock.
173e9d376f0SJason Baron  */
ddebug_change(const struct ddebug_query * query,struct flag_settings * modifiers)17485f7f6c0SJim Cromie static int ddebug_change(const struct ddebug_query *query,
17584da83a6SJim Cromie 			 struct flag_settings *modifiers)
176e9d376f0SJason Baron {
177e9d376f0SJason Baron 	int i;
178e9d376f0SJason Baron 	struct ddebug_table *dt;
179e9d376f0SJason Baron 	unsigned int newflags;
180e9d376f0SJason Baron 	unsigned int nfound = 0;
181bfa3ca44SJim Cromie 	struct flagsbuf fbuf, nbuf;
182a4a2a427SJim Cromie 	struct ddebug_class_map *map = NULL;
183a4a2a427SJim Cromie 	int __outvar valid_class;
184e9d376f0SJason Baron 
185e9d376f0SJason Baron 	/* search for matching ddebugs */
186e9d376f0SJason Baron 	mutex_lock(&ddebug_lock);
187e9d376f0SJason Baron 	list_for_each_entry(dt, &ddebug_tables, link) {
188e9d376f0SJason Baron 
189e9d376f0SJason Baron 		/* match against the module name */
190578b1e07SDu, Changbin 		if (query->module &&
191578b1e07SDu, Changbin 		    !match_wildcard(query->module, dt->mod_name))
192e9d376f0SJason Baron 			continue;
193e9d376f0SJason Baron 
194a4a2a427SJim Cromie 		if (query->class_string) {
195a4a2a427SJim Cromie 			map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
196a4a2a427SJim Cromie 			if (!map)
197a4a2a427SJim Cromie 				continue;
198a4a2a427SJim Cromie 		} else {
199a4a2a427SJim Cromie 			/* constrain query, do not touch class'd callsites */
200a4a2a427SJim Cromie 			valid_class = _DPRINTK_CLASS_DFLT;
201a4a2a427SJim Cromie 		}
202a4a2a427SJim Cromie 
203e9d376f0SJason Baron 		for (i = 0; i < dt->num_ddebugs; i++) {
204e9d376f0SJason Baron 			struct _ddebug *dp = &dt->ddebugs[i];
205e9d376f0SJason Baron 
206a4a2a427SJim Cromie 			/* match site against query-class */
207a4a2a427SJim Cromie 			if (dp->class_id != valid_class)
208a4a2a427SJim Cromie 				continue;
209a4a2a427SJim Cromie 
210e9d376f0SJason Baron 			/* match against the source filename */
211d6a238d2SJim Cromie 			if (query->filename &&
212578b1e07SDu, Changbin 			    !match_wildcard(query->filename, dp->filename) &&
213578b1e07SDu, Changbin 			    !match_wildcard(query->filename,
214578b1e07SDu, Changbin 					   kbasename(dp->filename)) &&
215578b1e07SDu, Changbin 			    !match_wildcard(query->filename,
216578b1e07SDu, Changbin 					   trim_prefix(dp->filename)))
217e9d376f0SJason Baron 				continue;
218e9d376f0SJason Baron 
219e9d376f0SJason Baron 			/* match against the function */
220d6a238d2SJim Cromie 			if (query->function &&
221578b1e07SDu, Changbin 			    !match_wildcard(query->function, dp->function))
222e9d376f0SJason Baron 				continue;
223e9d376f0SJason Baron 
224e9d376f0SJason Baron 			/* match against the format */
2254b334484SJim Cromie 			if (query->format) {
2264b334484SJim Cromie 				if (*query->format == '^') {
2274b334484SJim Cromie 					char *p;
2284b334484SJim Cromie 					/* anchored search. match must be at beginning */
2294b334484SJim Cromie 					p = strstr(dp->format, query->format+1);
2304b334484SJim Cromie 					if (p != dp->format)
231e9d376f0SJason Baron 						continue;
2324b334484SJim Cromie 				} else if (!strstr(dp->format, query->format))
2334b334484SJim Cromie 					continue;
2344b334484SJim Cromie 			}
235e9d376f0SJason Baron 
236e9d376f0SJason Baron 			/* match against the line number range */
237e9d376f0SJason Baron 			if (query->first_lineno &&
238e9d376f0SJason Baron 			    dp->lineno < query->first_lineno)
239e9d376f0SJason Baron 				continue;
240e9d376f0SJason Baron 			if (query->last_lineno &&
241e9d376f0SJason Baron 			    dp->lineno > query->last_lineno)
242e9d376f0SJason Baron 				continue;
243e9d376f0SJason Baron 
244e9d376f0SJason Baron 			nfound++;
245e9d376f0SJason Baron 
24684da83a6SJim Cromie 			newflags = (dp->flags & modifiers->mask) | modifiers->flags;
247e9d376f0SJason Baron 			if (newflags == dp->flags)
248e9d376f0SJason Baron 				continue;
249e9666d10SMasahiro Yamada #ifdef CONFIG_JUMP_LABEL
2509049fc74SJason Baron 			if (dp->flags & _DPRINTK_FLAGS_PRINT) {
251ee879be3SJim Cromie 				if (!(newflags & _DPRINTK_FLAGS_PRINT))
2529049fc74SJason Baron 					static_branch_disable(&dp->key.dd_key_true);
253ee879be3SJim Cromie 			} else if (newflags & _DPRINTK_FLAGS_PRINT) {
2549049fc74SJason Baron 				static_branch_enable(&dp->key.dd_key_true);
255ee879be3SJim Cromie 			}
2569049fc74SJason Baron #endif
257bfa3ca44SJim Cromie 			v4pr_info("changed %s:%d [%s]%s %s => %s\n",
2582b678319SJim Cromie 				  trim_prefix(dp->filename), dp->lineno,
259e9d376f0SJason Baron 				  dt->mod_name, dp->function,
260bfa3ca44SJim Cromie 				  ddebug_describe_flags(dp->flags, &fbuf),
261bfa3ca44SJim Cromie 				  ddebug_describe_flags(newflags, &nbuf));
262bfa3ca44SJim Cromie 			dp->flags = newflags;
263e9d376f0SJason Baron 		}
264e9d376f0SJason Baron 	}
265e9d376f0SJason Baron 	mutex_unlock(&ddebug_lock);
266e9d376f0SJason Baron 
267e9d376f0SJason Baron 	if (!nfound && verbose)
2684ad275e5SJoe Perches 		pr_info("no matches for query\n");
26985f7f6c0SJim Cromie 
27085f7f6c0SJim Cromie 	return nfound;
271e9d376f0SJason Baron }
272e9d376f0SJason Baron 
273e9d376f0SJason Baron /*
274e9d376f0SJason Baron  * Split the buffer `buf' into space-separated words.
2759898abb3SGreg Banks  * Handles simple " and ' quoting, i.e. without nested,
2769898abb3SGreg Banks  * embedded or escaped \".  Return the number of words
2779898abb3SGreg Banks  * or <0 on error.
278e9d376f0SJason Baron  */
ddebug_tokenize(char * buf,char * words[],int maxwords)279e9d376f0SJason Baron static int ddebug_tokenize(char *buf, char *words[], int maxwords)
280e9d376f0SJason Baron {
281e9d376f0SJason Baron 	int nwords = 0;
282e9d376f0SJason Baron 
2839898abb3SGreg Banks 	while (*buf) {
2849898abb3SGreg Banks 		char *end;
2859898abb3SGreg Banks 
2869898abb3SGreg Banks 		/* Skip leading whitespace */
287e7d2860bSAndré Goddard Rosa 		buf = skip_spaces(buf);
2889898abb3SGreg Banks 		if (!*buf)
2899898abb3SGreg Banks 			break;	/* oh, it was trailing whitespace */
2908bd6026eSJim Cromie 		if (*buf == '#')
2918bd6026eSJim Cromie 			break;	/* token starts comment, skip rest of line */
2929898abb3SGreg Banks 
29307100be7SJim Cromie 		/* find `end' of word, whitespace separated or quoted */
2949898abb3SGreg Banks 		if (*buf == '"' || *buf == '\'') {
2959898abb3SGreg Banks 			int quote = *buf++;
2969898abb3SGreg Banks 			for (end = buf; *end && *end != quote; end++)
2979898abb3SGreg Banks 				;
29818c216c5SJim Cromie 			if (!*end) {
29918c216c5SJim Cromie 				pr_err("unclosed quote: %s\n", buf);
3009898abb3SGreg Banks 				return -EINVAL;	/* unclosed quote */
30118c216c5SJim Cromie 			}
3029898abb3SGreg Banks 		} else {
3037f6e1f30SGreg Kroah-Hartman 			for (end = buf; *end && !isspace(*end); end++)
3049898abb3SGreg Banks 				;
305*a69e1bddSJim Cromie 			if (end == buf) {
306*a69e1bddSJim Cromie 				pr_err("parse err after word:%d=%s\n", nwords,
307*a69e1bddSJim Cromie 				       nwords ? words[nwords - 1] : "<none>");
308*a69e1bddSJim Cromie 				return -EINVAL;
309*a69e1bddSJim Cromie 			}
3109898abb3SGreg Banks 		}
3119898abb3SGreg Banks 
31207100be7SJim Cromie 		/* `buf' is start of word, `end' is one past its end */
31318c216c5SJim Cromie 		if (nwords == maxwords) {
31418c216c5SJim Cromie 			pr_err("too many words, legal max <=%d\n", maxwords);
315e9d376f0SJason Baron 			return -EINVAL;	/* ran out of words[] before bytes */
31618c216c5SJim Cromie 		}
3179898abb3SGreg Banks 		if (*end)
3189898abb3SGreg Banks 			*end++ = '\0';	/* terminate the word */
3199898abb3SGreg Banks 		words[nwords++] = buf;
3209898abb3SGreg Banks 		buf = end;
3219898abb3SGreg Banks 	}
322e9d376f0SJason Baron 
32309ee10ffSJim Cromie 	if (verbose >= 3) {
324e9d376f0SJason Baron 		int i;
3254ad275e5SJoe Perches 		pr_info("split into words:");
326e9d376f0SJason Baron 		for (i = 0; i < nwords; i++)
3274ad275e5SJoe Perches 			pr_cont(" \"%s\"", words[i]);
3284ad275e5SJoe Perches 		pr_cont("\n");
329e9d376f0SJason Baron 	}
330e9d376f0SJason Baron 
331e9d376f0SJason Baron 	return nwords;
332e9d376f0SJason Baron }
333e9d376f0SJason Baron 
334e9d376f0SJason Baron /*
335e9d376f0SJason Baron  * Parse a single line number.  Note that the empty string ""
336e9d376f0SJason Baron  * is treated as a special case and converted to zero, which
337e9d376f0SJason Baron  * is later treated as a "don't care" value.
338e9d376f0SJason Baron  */
parse_lineno(const char * str,unsigned int * val)339e9d376f0SJason Baron static inline int parse_lineno(const char *str, unsigned int *val)
340e9d376f0SJason Baron {
341e9d376f0SJason Baron 	BUG_ON(str == NULL);
342e9d376f0SJason Baron 	if (*str == '\0') {
343e9d376f0SJason Baron 		*val = 0;
344e9d376f0SJason Baron 		return 0;
345e9d376f0SJason Baron 	}
3464592599aSAndrey Ryabinin 	if (kstrtouint(str, 10, val) < 0) {
34718c216c5SJim Cromie 		pr_err("bad line-number: %s\n", str);
34818c216c5SJim Cromie 		return -EINVAL;
34918c216c5SJim Cromie 	}
35018c216c5SJim Cromie 	return 0;
351e9d376f0SJason Baron }
352e9d376f0SJason Baron 
parse_linerange(struct ddebug_query * query,const char * first)3538037072dSJim Cromie static int parse_linerange(struct ddebug_query *query, const char *first)
3548037072dSJim Cromie {
3558037072dSJim Cromie 	char *last = strchr(first, '-');
3568037072dSJim Cromie 
3578037072dSJim Cromie 	if (query->first_lineno || query->last_lineno) {
3588037072dSJim Cromie 		pr_err("match-spec: line used 2x\n");
3598037072dSJim Cromie 		return -EINVAL;
3608037072dSJim Cromie 	}
3618037072dSJim Cromie 	if (last)
3628037072dSJim Cromie 		*last++ = '\0';
3638037072dSJim Cromie 	if (parse_lineno(first, &query->first_lineno) < 0)
3648037072dSJim Cromie 		return -EINVAL;
3658037072dSJim Cromie 	if (last) {
3668037072dSJim Cromie 		/* range <first>-<last> */
3678037072dSJim Cromie 		if (parse_lineno(last, &query->last_lineno) < 0)
3688037072dSJim Cromie 			return -EINVAL;
3698037072dSJim Cromie 
3708037072dSJim Cromie 		/* special case for last lineno not specified */
3718037072dSJim Cromie 		if (query->last_lineno == 0)
3728037072dSJim Cromie 			query->last_lineno = UINT_MAX;
3738037072dSJim Cromie 
3748037072dSJim Cromie 		if (query->last_lineno < query->first_lineno) {
3758037072dSJim Cromie 			pr_err("last-line:%d < 1st-line:%d\n",
3768037072dSJim Cromie 			       query->last_lineno,
3778037072dSJim Cromie 			       query->first_lineno);
3788037072dSJim Cromie 			return -EINVAL;
3798037072dSJim Cromie 		}
3808037072dSJim Cromie 	} else {
3818037072dSJim Cromie 		query->last_lineno = query->first_lineno;
3828037072dSJim Cromie 	}
38309ee10ffSJim Cromie 	v3pr_info("parsed line %d-%d\n", query->first_lineno,
3848037072dSJim Cromie 		 query->last_lineno);
3858037072dSJim Cromie 	return 0;
3868037072dSJim Cromie }
3878037072dSJim Cromie 
check_set(const char ** dest,char * src,char * name)388820874c7SJim Cromie static int check_set(const char **dest, char *src, char *name)
389820874c7SJim Cromie {
390820874c7SJim Cromie 	int rc = 0;
391820874c7SJim Cromie 
392820874c7SJim Cromie 	if (*dest) {
393820874c7SJim Cromie 		rc = -EINVAL;
394f657fd21SJoe Perches 		pr_err("match-spec:%s val:%s overridden by %s\n",
395820874c7SJim Cromie 		       name, *dest, src);
396820874c7SJim Cromie 	}
397820874c7SJim Cromie 	*dest = src;
398820874c7SJim Cromie 	return rc;
399820874c7SJim Cromie }
400820874c7SJim Cromie 
401e9d376f0SJason Baron /*
402e9d376f0SJason Baron  * Parse words[] as a ddebug query specification, which is a series
403952e934dSGreg Kroah-Hartman  * of (keyword, value) pairs chosen from these possibilities:
404e9d376f0SJason Baron  *
405e9d376f0SJason Baron  * func <function-name>
406e9d376f0SJason Baron  * file <full-pathname>
407e9d376f0SJason Baron  * file <base-filename>
408e9d376f0SJason Baron  * module <module-name>
409e9d376f0SJason Baron  * format <escaped-string-to-find-in-format>
410e9d376f0SJason Baron  * line <lineno>
411e9d376f0SJason Baron  * line <first-lineno>-<last-lineno> // where either may be empty
412820874c7SJim Cromie  *
413820874c7SJim Cromie  * Only 1 of each type is allowed.
414820874c7SJim Cromie  * Returns 0 on success, <0 on error.
415e9d376f0SJason Baron  */
ddebug_parse_query(char * words[],int nwords,struct ddebug_query * query,const char * modname)416e9d376f0SJason Baron static int ddebug_parse_query(char *words[], int nwords,
4178e59b5cfSJim Cromie 			struct ddebug_query *query, const char *modname)
418e9d376f0SJason Baron {
419e9d376f0SJason Baron 	unsigned int i;
420bd8c154aSjbaron@akamai.com 	int rc = 0;
421aaebe329SJim Cromie 	char *fline;
422952e934dSGreg Kroah-Hartman 
423952e934dSGreg Kroah-Hartman 	/* check we have an even number of words */
424952e934dSGreg Kroah-Hartman 	if (nwords % 2 != 0) {
425952e934dSGreg Kroah-Hartman 		pr_err("expecting pairs of match-spec <value>\n");
426952e934dSGreg Kroah-Hartman 		return -EINVAL;
427952e934dSGreg Kroah-Hartman 	}
428e9d376f0SJason Baron 
429952e934dSGreg Kroah-Hartman 	for (i = 0; i < nwords; i += 2) {
430e5e5fcefSJim Cromie 		char *keyword = words[i];
431e5e5fcefSJim Cromie 		char *arg = words[i+1];
432e5e5fcefSJim Cromie 
433e5e5fcefSJim Cromie 		if (!strcmp(keyword, "func")) {
434e5e5fcefSJim Cromie 			rc = check_set(&query->function, arg, "func");
435e5e5fcefSJim Cromie 		} else if (!strcmp(keyword, "file")) {
436e5e5fcefSJim Cromie 			if (check_set(&query->filename, arg, "file"))
437aaebe329SJim Cromie 				return -EINVAL;
438aaebe329SJim Cromie 
439aaebe329SJim Cromie 			/* tail :$info is function or line-range */
440aaebe329SJim Cromie 			fline = strchr(query->filename, ':');
441aaebe329SJim Cromie 			if (!fline)
4427b1ae248SShuo Chen 				continue;
443aaebe329SJim Cromie 			*fline++ = '\0';
444aaebe329SJim Cromie 			if (isalpha(*fline) || *fline == '*' || *fline == '?') {
445aaebe329SJim Cromie 				/* take as function name */
446aaebe329SJim Cromie 				if (check_set(&query->function, fline, "func"))
447aaebe329SJim Cromie 					return -EINVAL;
448aaebe329SJim Cromie 			} else {
449aaebe329SJim Cromie 				if (parse_linerange(query, fline))
450aaebe329SJim Cromie 					return -EINVAL;
451aaebe329SJim Cromie 			}
452e5e5fcefSJim Cromie 		} else if (!strcmp(keyword, "module")) {
453e5e5fcefSJim Cromie 			rc = check_set(&query->module, arg, "module");
454e5e5fcefSJim Cromie 		} else if (!strcmp(keyword, "format")) {
455e5e5fcefSJim Cromie 			string_unescape_inplace(arg, UNESCAPE_SPACE |
456d338b137SAndy Shevchenko 							    UNESCAPE_OCTAL |
457d338b137SAndy Shevchenko 							    UNESCAPE_SPECIAL);
458e5e5fcefSJim Cromie 			rc = check_set(&query->format, arg, "format");
459e5e5fcefSJim Cromie 		} else if (!strcmp(keyword, "line")) {
460e5e5fcefSJim Cromie 			if (parse_linerange(query, arg))
461820874c7SJim Cromie 				return -EINVAL;
462a4a2a427SJim Cromie 		} else if (!strcmp(keyword, "class")) {
463a4a2a427SJim Cromie 			rc = check_set(&query->class_string, arg, "class");
464e9d376f0SJason Baron 		} else {
465e5e5fcefSJim Cromie 			pr_err("unknown keyword \"%s\"\n", keyword);
466e9d376f0SJason Baron 			return -EINVAL;
467e9d376f0SJason Baron 		}
468820874c7SJim Cromie 		if (rc)
469820874c7SJim Cromie 			return rc;
470e9d376f0SJason Baron 	}
471e75ef56fSJim Cromie 	if (!query->module && modname)
472e75ef56fSJim Cromie 		/*
473e75ef56fSJim Cromie 		 * support $modname.dyndbg=<multiple queries>, when
474e75ef56fSJim Cromie 		 * not given in the query itself
475e75ef56fSJim Cromie 		 */
476e75ef56fSJim Cromie 		query->module = modname;
477e75ef56fSJim Cromie 
478574b3725SJim Cromie 	vpr_info_dq(query, "parsed");
479e9d376f0SJason Baron 	return 0;
480e9d376f0SJason Baron }
481e9d376f0SJason Baron 
482e9d376f0SJason Baron /*
483e9d376f0SJason Baron  * Parse `str' as a flags specification, format [-+=][p]+.
484e9d376f0SJason Baron  * Sets up *maskp and *flagsp to be used when changing the
485e9d376f0SJason Baron  * flags fields of matched _ddebug's.  Returns 0 on success
486e9d376f0SJason Baron  * or <0 on error.
487e9d376f0SJason Baron  */
ddebug_parse_flags(const char * str,struct flag_settings * modifiers)48884da83a6SJim Cromie static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
489e9d376f0SJason Baron {
49084da83a6SJim Cromie 	int op, i;
491e9d376f0SJason Baron 
492e9d376f0SJason Baron 	switch (*str) {
493e9d376f0SJason Baron 	case '+':
494e9d376f0SJason Baron 	case '-':
495e9d376f0SJason Baron 	case '=':
496e9d376f0SJason Baron 		op = *str++;
497e9d376f0SJason Baron 		break;
498e9d376f0SJason Baron 	default:
49918c216c5SJim Cromie 		pr_err("bad flag-op %c, at start of %s\n", *str, str);
500e9d376f0SJason Baron 		return -EINVAL;
501e9d376f0SJason Baron 	}
50209ee10ffSJim Cromie 	v3pr_info("op='%c'\n", op);
503e9d376f0SJason Baron 
504e9d376f0SJason Baron 	for (; *str ; ++str) {
5058ba6ebf5SBart Van Assche 		for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
5068ba6ebf5SBart Van Assche 			if (*str == opt_array[i].opt_char) {
50784da83a6SJim Cromie 				modifiers->flags |= opt_array[i].flag;
508e9d376f0SJason Baron 				break;
509e9d376f0SJason Baron 			}
510e9d376f0SJason Baron 		}
51118c216c5SJim Cromie 		if (i < 0) {
5120b8f96beSJim Cromie 			pr_err("unknown flag '%c'\n", *str);
5138ba6ebf5SBart Van Assche 			return -EINVAL;
5148ba6ebf5SBart Van Assche 		}
51518c216c5SJim Cromie 	}
51609ee10ffSJim Cromie 	v3pr_info("flags=0x%x\n", modifiers->flags);
517e9d376f0SJason Baron 
51884da83a6SJim Cromie 	/* calculate final flags, mask based upon op */
519e9d376f0SJason Baron 	switch (op) {
520e9d376f0SJason Baron 	case '=':
52184da83a6SJim Cromie 		/* modifiers->flags already set */
52284da83a6SJim Cromie 		modifiers->mask = 0;
523e9d376f0SJason Baron 		break;
524e9d376f0SJason Baron 	case '+':
52584da83a6SJim Cromie 		modifiers->mask = ~0U;
526e9d376f0SJason Baron 		break;
527e9d376f0SJason Baron 	case '-':
52884da83a6SJim Cromie 		modifiers->mask = ~modifiers->flags;
52984da83a6SJim Cromie 		modifiers->flags = 0;
530e9d376f0SJason Baron 		break;
531e9d376f0SJason Baron 	}
53209ee10ffSJim Cromie 	v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
53384da83a6SJim Cromie 
534e9d376f0SJason Baron 	return 0;
535e9d376f0SJason Baron }
536e9d376f0SJason Baron 
ddebug_exec_query(char * query_string,const char * modname)5378e59b5cfSJim Cromie static int ddebug_exec_query(char *query_string, const char *modname)
538fd89cfb8SThomas Renninger {
53984da83a6SJim Cromie 	struct flag_settings modifiers = {};
5409c9d0acbSJim Cromie 	struct ddebug_query query = {};
541fd89cfb8SThomas Renninger #define MAXWORDS 9
54285f7f6c0SJim Cromie 	int nwords, nfound;
543fd89cfb8SThomas Renninger 	char *words[MAXWORDS];
544fd89cfb8SThomas Renninger 
545fd89cfb8SThomas Renninger 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);
54618c216c5SJim Cromie 	if (nwords <= 0) {
54718c216c5SJim Cromie 		pr_err("tokenize failed\n");
548fd89cfb8SThomas Renninger 		return -EINVAL;
54918c216c5SJim Cromie 	}
55018c216c5SJim Cromie 	/* check flags 1st (last arg) so query is pairs of spec,val */
55184da83a6SJim Cromie 	if (ddebug_parse_flags(words[nwords-1], &modifiers)) {
55218c216c5SJim Cromie 		pr_err("flags parse failed\n");
553fd89cfb8SThomas Renninger 		return -EINVAL;
55418c216c5SJim Cromie 	}
55518c216c5SJim Cromie 	if (ddebug_parse_query(words, nwords-1, &query, modname)) {
55618c216c5SJim Cromie 		pr_err("query parse failed\n");
557fd89cfb8SThomas Renninger 		return -EINVAL;
55818c216c5SJim Cromie 	}
559fd89cfb8SThomas Renninger 	/* actually go and implement the change */
56084da83a6SJim Cromie 	nfound = ddebug_change(&query, &modifiers);
561f657fd21SJoe Perches 	vpr_info_dq(&query, nfound ? "applied" : "no-match");
56285f7f6c0SJim Cromie 
56385f7f6c0SJim Cromie 	return nfound;
56485f7f6c0SJim Cromie }
56585f7f6c0SJim Cromie 
56685f7f6c0SJim Cromie /* handle multiple queries in query string, continue on error, return
56785f7f6c0SJim Cromie    last error or number of matching callsites.  Module name is either
56885f7f6c0SJim Cromie    in param (for boot arg) or perhaps in query string.
56985f7f6c0SJim Cromie */
ddebug_exec_queries(char * query,const char * modname)570a2d375edSJim Cromie static int ddebug_exec_queries(char *query, const char *modname)
57185f7f6c0SJim Cromie {
57285f7f6c0SJim Cromie 	char *split;
57385f7f6c0SJim Cromie 	int i, errs = 0, exitcode = 0, rc, nfound = 0;
57485f7f6c0SJim Cromie 
57585f7f6c0SJim Cromie 	for (i = 0; query; query = split) {
57685f7f6c0SJim Cromie 		split = strpbrk(query, ";\n");
57785f7f6c0SJim Cromie 		if (split)
57885f7f6c0SJim Cromie 			*split++ = '\0';
57985f7f6c0SJim Cromie 
58085f7f6c0SJim Cromie 		query = skip_spaces(query);
58185f7f6c0SJim Cromie 		if (!query || !*query || *query == '#')
58285f7f6c0SJim Cromie 			continue;
58385f7f6c0SJim Cromie 
5841f8818e3SJim Cromie 		vpr_info("query %d: \"%s\" mod:%s\n", i, query, modname ?: "*");
58585f7f6c0SJim Cromie 
5868e59b5cfSJim Cromie 		rc = ddebug_exec_query(query, modname);
58785f7f6c0SJim Cromie 		if (rc < 0) {
58885f7f6c0SJim Cromie 			errs++;
58985f7f6c0SJim Cromie 			exitcode = rc;
590f657fd21SJoe Perches 		} else {
59185f7f6c0SJim Cromie 			nfound += rc;
592f657fd21SJoe Perches 		}
59385f7f6c0SJim Cromie 		i++;
59485f7f6c0SJim Cromie 	}
5957edde0c8SJim Cromie 	if (i)
59609ee10ffSJim Cromie 		v2pr_info("processed %d queries, with %d matches, %d errs\n",
59785f7f6c0SJim Cromie 			 i, nfound, errs);
59885f7f6c0SJim Cromie 
59985f7f6c0SJim Cromie 	if (exitcode)
60085f7f6c0SJim Cromie 		return exitcode;
60185f7f6c0SJim Cromie 	return nfound;
602fd89cfb8SThomas Renninger }
603a2d375edSJim Cromie 
604b9400852SJim Cromie /* apply a new bitmap to the sys-knob's current bit-state */
ddebug_apply_class_bitmap(const struct ddebug_class_param * dcp,unsigned long * new_bits,unsigned long * old_bits)605b9400852SJim Cromie static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
606b9400852SJim Cromie 				     unsigned long *new_bits, unsigned long *old_bits)
607b9400852SJim Cromie {
608b9400852SJim Cromie #define QUERY_SIZE 128
609b9400852SJim Cromie 	char query[QUERY_SIZE];
610b9400852SJim Cromie 	const struct ddebug_class_map *map = dcp->map;
611b9400852SJim Cromie 	int matches = 0;
612b9400852SJim Cromie 	int bi, ct;
613b9400852SJim Cromie 
614b9400852SJim Cromie 	v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
615b9400852SJim Cromie 
616b9400852SJim Cromie 	for (bi = 0; bi < map->length; bi++) {
617b9400852SJim Cromie 		if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
618b9400852SJim Cromie 			continue;
619b9400852SJim Cromie 
620b9400852SJim Cromie 		snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
621b9400852SJim Cromie 			 test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
622b9400852SJim Cromie 
623b9400852SJim Cromie 		ct = ddebug_exec_queries(query, NULL);
624b9400852SJim Cromie 		matches += ct;
625b9400852SJim Cromie 
626b9400852SJim Cromie 		v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
627b9400852SJim Cromie 			  ct, map->class_names[bi], *new_bits);
628b9400852SJim Cromie 	}
629b9400852SJim Cromie 	return matches;
630b9400852SJim Cromie }
631b9400852SJim Cromie 
632b9400852SJim Cromie /* stub to later conditionally add "$module." prefix where not already done */
633b9400852SJim Cromie #define KP_NAME(kp)	kp->name
634b9400852SJim Cromie 
635b9400852SJim Cromie #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
636b9400852SJim Cromie 
637b9400852SJim Cromie /* accept comma-separated-list of [+-] classnames */
param_set_dyndbg_classnames(const char * instr,const struct kernel_param * kp)638b9400852SJim Cromie static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
639b9400852SJim Cromie {
640b9400852SJim Cromie 	const struct ddebug_class_param *dcp = kp->arg;
641b9400852SJim Cromie 	const struct ddebug_class_map *map = dcp->map;
642b9400852SJim Cromie 	unsigned long curr_bits, old_bits;
643b9400852SJim Cromie 	char *cl_str, *p, *tmp;
644b9400852SJim Cromie 	int cls_id, totct = 0;
645b9400852SJim Cromie 	bool wanted;
646b9400852SJim Cromie 
647b9400852SJim Cromie 	cl_str = tmp = kstrdup(instr, GFP_KERNEL);
648b9400852SJim Cromie 	p = strchr(cl_str, '\n');
649b9400852SJim Cromie 	if (p)
650b9400852SJim Cromie 		*p = '\0';
651b9400852SJim Cromie 
652b9400852SJim Cromie 	/* start with previously set state-bits, then modify */
653b9400852SJim Cromie 	curr_bits = old_bits = *dcp->bits;
654b9400852SJim Cromie 	vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
655b9400852SJim Cromie 
656b9400852SJim Cromie 	for (; cl_str; cl_str = p) {
657b9400852SJim Cromie 		p = strchr(cl_str, ',');
658b9400852SJim Cromie 		if (p)
659b9400852SJim Cromie 			*p++ = '\0';
660b9400852SJim Cromie 
661b9400852SJim Cromie 		if (*cl_str == '-') {
662b9400852SJim Cromie 			wanted = false;
663b9400852SJim Cromie 			cl_str++;
664b9400852SJim Cromie 		} else {
665b9400852SJim Cromie 			wanted = true;
666b9400852SJim Cromie 			if (*cl_str == '+')
667b9400852SJim Cromie 				cl_str++;
668b9400852SJim Cromie 		}
669b9400852SJim Cromie 		cls_id = match_string(map->class_names, map->length, cl_str);
670b9400852SJim Cromie 		if (cls_id < 0) {
671b9400852SJim Cromie 			pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
672b9400852SJim Cromie 			continue;
673b9400852SJim Cromie 		}
674b9400852SJim Cromie 
675b9400852SJim Cromie 		/* have one or more valid class_ids of one *_NAMES type */
676b9400852SJim Cromie 		switch (map->map_type) {
677b9400852SJim Cromie 		case DD_CLASS_TYPE_DISJOINT_NAMES:
678b9400852SJim Cromie 			/* the +/- pertains to a single bit */
679b9400852SJim Cromie 			if (test_bit(cls_id, &curr_bits) == wanted) {
680b9400852SJim Cromie 				v3pr_info("no change on %s\n", cl_str);
681b9400852SJim Cromie 				continue;
682b9400852SJim Cromie 			}
683b9400852SJim Cromie 			curr_bits ^= BIT(cls_id);
684b9400852SJim Cromie 			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
685b9400852SJim Cromie 			*dcp->bits = curr_bits;
686b9400852SJim Cromie 			v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
687b9400852SJim Cromie 				  map->class_names[cls_id]);
688b9400852SJim Cromie 			break;
689b9400852SJim Cromie 		case DD_CLASS_TYPE_LEVEL_NAMES:
690b9400852SJim Cromie 			/* cls_id = N in 0..max. wanted +/- determines N or N-1 */
691b9400852SJim Cromie 			old_bits = CLASSMAP_BITMASK(*dcp->lvl);
692b9400852SJim Cromie 			curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
693b9400852SJim Cromie 
694b9400852SJim Cromie 			totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
695b9400852SJim Cromie 			*dcp->lvl = (cls_id + (wanted ? 1 : 0));
696b9400852SJim Cromie 			v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
697b9400852SJim Cromie 				  map->class_names[cls_id], old_bits, curr_bits);
698b9400852SJim Cromie 			break;
699b9400852SJim Cromie 		default:
700b9400852SJim Cromie 			pr_err("illegal map-type value %d\n", map->map_type);
701b9400852SJim Cromie 		}
702b9400852SJim Cromie 	}
703b9400852SJim Cromie 	kfree(tmp);
704b9400852SJim Cromie 	vpr_info("total matches: %d\n", totct);
705b9400852SJim Cromie 	return 0;
706b9400852SJim Cromie }
707b9400852SJim Cromie 
708b9400852SJim Cromie /**
709b9400852SJim Cromie  * param_set_dyndbg_classes - class FOO >control
710b9400852SJim Cromie  * @instr: string echo>d to sysfs, input depends on map_type
711b9400852SJim Cromie  * @kp:    kp->arg has state: bits/lvl, map, map_type
712b9400852SJim Cromie  *
713b9400852SJim Cromie  * Enable/disable prdbgs by their class, as given in the arguments to
714b9400852SJim Cromie  * DECLARE_DYNDBG_CLASSMAP.  For LEVEL map-types, enforce relative
715b9400852SJim Cromie  * levels by bitpos.
716b9400852SJim Cromie  *
717b9400852SJim Cromie  * Returns: 0 or <0 if error.
718b9400852SJim Cromie  */
param_set_dyndbg_classes(const char * instr,const struct kernel_param * kp)719b9400852SJim Cromie int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
720b9400852SJim Cromie {
721b9400852SJim Cromie 	const struct ddebug_class_param *dcp = kp->arg;
722b9400852SJim Cromie 	const struct ddebug_class_map *map = dcp->map;
723b9400852SJim Cromie 	unsigned long inrep, new_bits, old_bits;
724b9400852SJim Cromie 	int rc, totct = 0;
725b9400852SJim Cromie 
726b9400852SJim Cromie 	switch (map->map_type) {
727b9400852SJim Cromie 
728b9400852SJim Cromie 	case DD_CLASS_TYPE_DISJOINT_NAMES:
729b9400852SJim Cromie 	case DD_CLASS_TYPE_LEVEL_NAMES:
730b9400852SJim Cromie 		/* handle [+-]classnames list separately, we are done here */
731b9400852SJim Cromie 		return param_set_dyndbg_classnames(instr, kp);
732b9400852SJim Cromie 
733b9400852SJim Cromie 	case DD_CLASS_TYPE_DISJOINT_BITS:
734b9400852SJim Cromie 	case DD_CLASS_TYPE_LEVEL_NUM:
735b9400852SJim Cromie 		/* numeric input, accept and fall-thru */
736b9400852SJim Cromie 		rc = kstrtoul(instr, 0, &inrep);
737b9400852SJim Cromie 		if (rc) {
738b9400852SJim Cromie 			pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
739b9400852SJim Cromie 			return -EINVAL;
740b9400852SJim Cromie 		}
741b9400852SJim Cromie 		break;
742b9400852SJim Cromie 	default:
743b9400852SJim Cromie 		pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
744b9400852SJim Cromie 		return -EINVAL;
745b9400852SJim Cromie 	}
746b9400852SJim Cromie 
747b9400852SJim Cromie 	/* only _BITS,_NUM (numeric) map-types get here */
748b9400852SJim Cromie 	switch (map->map_type) {
749b9400852SJim Cromie 	case DD_CLASS_TYPE_DISJOINT_BITS:
750b9400852SJim Cromie 		/* expect bits. mask and warn if too many */
751b9400852SJim Cromie 		if (inrep & ~CLASSMAP_BITMASK(map->length)) {
752b9400852SJim Cromie 			pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
753b9400852SJim Cromie 				KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
754b9400852SJim Cromie 			inrep &= CLASSMAP_BITMASK(map->length);
755b9400852SJim Cromie 		}
756b9400852SJim Cromie 		v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
757b9400852SJim Cromie 		totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
758b9400852SJim Cromie 		*dcp->bits = inrep;
759b9400852SJim Cromie 		break;
760b9400852SJim Cromie 	case DD_CLASS_TYPE_LEVEL_NUM:
761b9400852SJim Cromie 		/* input is bitpos, of highest verbosity to be enabled */
762b9400852SJim Cromie 		if (inrep > map->length) {
763b9400852SJim Cromie 			pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
764b9400852SJim Cromie 				KP_NAME(kp), inrep, map->length);
765b9400852SJim Cromie 			inrep = map->length;
766b9400852SJim Cromie 		}
767b9400852SJim Cromie 		old_bits = CLASSMAP_BITMASK(*dcp->lvl);
768b9400852SJim Cromie 		new_bits = CLASSMAP_BITMASK(inrep);
769b9400852SJim Cromie 		v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
770b9400852SJim Cromie 		totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
771b9400852SJim Cromie 		*dcp->lvl = inrep;
772b9400852SJim Cromie 		break;
773b9400852SJim Cromie 	default:
774b9400852SJim Cromie 		pr_warn("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
775b9400852SJim Cromie 	}
776b9400852SJim Cromie 	vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
777b9400852SJim Cromie 	return 0;
778b9400852SJim Cromie }
779b9400852SJim Cromie EXPORT_SYMBOL(param_set_dyndbg_classes);
780b9400852SJim Cromie 
781b9400852SJim Cromie /**
782b9400852SJim Cromie  * param_get_dyndbg_classes - classes reader
783b9400852SJim Cromie  * @buffer: string description of controlled bits -> classes
784b9400852SJim Cromie  * @kp:     kp->arg has state: bits, map
785b9400852SJim Cromie  *
786b9400852SJim Cromie  * Reads last written state, underlying prdbg state may have been
787b9400852SJim Cromie  * altered by direct >control.  Displays 0x for DISJOINT, 0-N for
788b9400852SJim Cromie  * LEVEL Returns: #chars written or <0 on error
789b9400852SJim Cromie  */
param_get_dyndbg_classes(char * buffer,const struct kernel_param * kp)790b9400852SJim Cromie int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
791b9400852SJim Cromie {
792b9400852SJim Cromie 	const struct ddebug_class_param *dcp = kp->arg;
793b9400852SJim Cromie 	const struct ddebug_class_map *map = dcp->map;
794b9400852SJim Cromie 
795b9400852SJim Cromie 	switch (map->map_type) {
796b9400852SJim Cromie 
797b9400852SJim Cromie 	case DD_CLASS_TYPE_DISJOINT_NAMES:
798b9400852SJim Cromie 	case DD_CLASS_TYPE_DISJOINT_BITS:
799b9400852SJim Cromie 		return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
800b9400852SJim Cromie 
801b9400852SJim Cromie 	case DD_CLASS_TYPE_LEVEL_NAMES:
802b9400852SJim Cromie 	case DD_CLASS_TYPE_LEVEL_NUM:
803b9400852SJim Cromie 		return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
804b9400852SJim Cromie 	default:
805b9400852SJim Cromie 		return -1;
806b9400852SJim Cromie 	}
807b9400852SJim Cromie }
808b9400852SJim Cromie EXPORT_SYMBOL(param_get_dyndbg_classes);
809b9400852SJim Cromie 
810b9400852SJim Cromie const struct kernel_param_ops param_ops_dyndbg_classes = {
811b9400852SJim Cromie 	.set = param_set_dyndbg_classes,
812b9400852SJim Cromie 	.get = param_get_dyndbg_classes,
813b9400852SJim Cromie };
814b9400852SJim Cromie EXPORT_SYMBOL(param_ops_dyndbg_classes);
815b9400852SJim Cromie 
8163bdaf739SThomas Weißschuh #define PREFIX_SIZE 128
8178ba6ebf5SBart Van Assche 
remaining(int wrote)818431625daSJason Baron static int remaining(int wrote)
819431625daSJason Baron {
820431625daSJason Baron 	if (PREFIX_SIZE - wrote > 0)
821431625daSJason Baron 		return PREFIX_SIZE - wrote;
822431625daSJason Baron 	return 0;
8238ba6ebf5SBart Van Assche }
8246c2140eeSJoe Perches 
__dynamic_emit_prefix(const struct _ddebug * desc,char * buf)825640d1eafSJim Cromie static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
826431625daSJason Baron {
827431625daSJason Baron 	int pos_after_tid;
828431625daSJason Baron 	int pos = 0;
8295b2ebce4SJoe Perches 
830431625daSJason Baron 	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
831431625daSJason Baron 		if (in_interrupt())
832798efc60SJoe Perches 			pos += snprintf(buf + pos, remaining(pos), "<intr> ");
833431625daSJason Baron 		else
834431625daSJason Baron 			pos += snprintf(buf + pos, remaining(pos), "[%d] ",
835431625daSJason Baron 					task_pid_vnr(current));
836431625daSJason Baron 	}
837431625daSJason Baron 	pos_after_tid = pos;
838431625daSJason Baron 	if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
839431625daSJason Baron 		pos += snprintf(buf + pos, remaining(pos), "%s:",
840431625daSJason Baron 				desc->modname);
841431625daSJason Baron 	if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
842431625daSJason Baron 		pos += snprintf(buf + pos, remaining(pos), "%s:",
843431625daSJason Baron 				desc->function);
84431ed379bSThomas Weißschuh 	if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME)
84531ed379bSThomas Weißschuh 		pos += snprintf(buf + pos, remaining(pos), "%s:",
84631ed379bSThomas Weißschuh 				trim_prefix(desc->filename));
847431625daSJason Baron 	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
84807100be7SJim Cromie 		pos += snprintf(buf + pos, remaining(pos), "%d:",
84907100be7SJim Cromie 				desc->lineno);
850431625daSJason Baron 	if (pos - pos_after_tid)
851431625daSJason Baron 		pos += snprintf(buf + pos, remaining(pos), " ");
852431625daSJason Baron 	if (pos >= PREFIX_SIZE)
853431625daSJason Baron 		buf[PREFIX_SIZE - 1] = '\0';
854431625daSJason Baron 
855431625daSJason Baron 	return buf;
8566c2140eeSJoe Perches }
8576c2140eeSJoe Perches 
dynamic_emit_prefix(struct _ddebug * desc,char * buf)858640d1eafSJim Cromie static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf)
859640d1eafSJim Cromie {
860640d1eafSJim Cromie 	if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY))
861640d1eafSJim Cromie 		return __dynamic_emit_prefix(desc, buf);
862640d1eafSJim Cromie 	return buf;
863640d1eafSJim Cromie }
864640d1eafSJim Cromie 
__dynamic_pr_debug(struct _ddebug * descriptor,const char * fmt,...)865906d2015SJoe Perches void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
8668ba6ebf5SBart Van Assche {
8678ba6ebf5SBart Van Assche 	va_list args;
868431625daSJason Baron 	struct va_format vaf;
869640d1eafSJim Cromie 	char buf[PREFIX_SIZE] = "";
8708ba6ebf5SBart Van Assche 
8718ba6ebf5SBart Van Assche 	BUG_ON(!descriptor);
8728ba6ebf5SBart Van Assche 	BUG_ON(!fmt);
8738ba6ebf5SBart Van Assche 
8748ba6ebf5SBart Van Assche 	va_start(args, fmt);
875798efc60SJoe Perches 
876431625daSJason Baron 	vaf.fmt = fmt;
877431625daSJason Baron 	vaf.va = &args;
878798efc60SJoe Perches 
879906d2015SJoe Perches 	printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
880798efc60SJoe Perches 
8818ba6ebf5SBart Van Assche 	va_end(args);
8828ba6ebf5SBart Van Assche }
8838ba6ebf5SBart Van Assche EXPORT_SYMBOL(__dynamic_pr_debug);
8848ba6ebf5SBart Van Assche 
__dynamic_dev_dbg(struct _ddebug * descriptor,const struct device * dev,const char * fmt,...)885906d2015SJoe Perches void __dynamic_dev_dbg(struct _ddebug *descriptor,
886cbc46635SJoe Perches 		      const struct device *dev, const char *fmt, ...)
887cbc46635SJoe Perches {
888cbc46635SJoe Perches 	struct va_format vaf;
889cbc46635SJoe Perches 	va_list args;
890cbc46635SJoe Perches 
891cbc46635SJoe Perches 	BUG_ON(!descriptor);
892cbc46635SJoe Perches 	BUG_ON(!fmt);
893cbc46635SJoe Perches 
894cbc46635SJoe Perches 	va_start(args, fmt);
895798efc60SJoe Perches 
896cbc46635SJoe Perches 	vaf.fmt = fmt;
897cbc46635SJoe Perches 	vaf.va = &args;
898798efc60SJoe Perches 
899798efc60SJoe Perches 	if (!dev) {
900906d2015SJoe Perches 		printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
901798efc60SJoe Perches 	} else {
902640d1eafSJim Cromie 		char buf[PREFIX_SIZE] = "";
903798efc60SJoe Perches 
904a39d4a85SJoe Perches 		dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",
905798efc60SJoe Perches 				dynamic_emit_prefix(descriptor, buf),
906666f355fSJoe Perches 				dev_driver_string(dev), dev_name(dev),
907666f355fSJoe Perches 				&vaf);
908798efc60SJoe Perches 	}
909798efc60SJoe Perches 
910cbc46635SJoe Perches 	va_end(args);
911cbc46635SJoe Perches }
912cbc46635SJoe Perches EXPORT_SYMBOL(__dynamic_dev_dbg);
913cbc46635SJoe Perches 
9140feefd97SJason Baron #ifdef CONFIG_NET
9150feefd97SJason Baron 
__dynamic_netdev_dbg(struct _ddebug * descriptor,const struct net_device * dev,const char * fmt,...)916906d2015SJoe Perches void __dynamic_netdev_dbg(struct _ddebug *descriptor,
917ffa10cb4SJason Baron 			  const struct net_device *dev, const char *fmt, ...)
918ffa10cb4SJason Baron {
919ffa10cb4SJason Baron 	struct va_format vaf;
920ffa10cb4SJason Baron 	va_list args;
921ffa10cb4SJason Baron 
922ffa10cb4SJason Baron 	BUG_ON(!descriptor);
923ffa10cb4SJason Baron 	BUG_ON(!fmt);
924ffa10cb4SJason Baron 
925ffa10cb4SJason Baron 	va_start(args, fmt);
926b004ff49SJoe Perches 
927ffa10cb4SJason Baron 	vaf.fmt = fmt;
928ffa10cb4SJason Baron 	vaf.va = &args;
929b004ff49SJoe Perches 
930b004ff49SJoe Perches 	if (dev && dev->dev.parent) {
931640d1eafSJim Cromie 		char buf[PREFIX_SIZE] = "";
932b004ff49SJoe Perches 
933a39d4a85SJoe Perches 		dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,
934ccc7f496SVeaceslav Falico 				"%s%s %s %s%s: %pV",
935b004ff49SJoe Perches 				dynamic_emit_prefix(descriptor, buf),
936b004ff49SJoe Perches 				dev_driver_string(dev->dev.parent),
937b004ff49SJoe Perches 				dev_name(dev->dev.parent),
938ccc7f496SVeaceslav Falico 				netdev_name(dev), netdev_reg_state(dev),
939ccc7f496SVeaceslav Falico 				&vaf);
940b004ff49SJoe Perches 	} else if (dev) {
941906d2015SJoe Perches 		printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev),
942ccc7f496SVeaceslav Falico 		       netdev_reg_state(dev), &vaf);
943b004ff49SJoe Perches 	} else {
944906d2015SJoe Perches 		printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
945b004ff49SJoe Perches 	}
946b004ff49SJoe Perches 
947ffa10cb4SJason Baron 	va_end(args);
948ffa10cb4SJason Baron }
949ffa10cb4SJason Baron EXPORT_SYMBOL(__dynamic_netdev_dbg);
950ffa10cb4SJason Baron 
9510feefd97SJason Baron #endif
9520feefd97SJason Baron 
953923abb9dSGal Pressman #if IS_ENABLED(CONFIG_INFINIBAND)
954923abb9dSGal Pressman 
__dynamic_ibdev_dbg(struct _ddebug * descriptor,const struct ib_device * ibdev,const char * fmt,...)955923abb9dSGal Pressman void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
956923abb9dSGal Pressman 			 const struct ib_device *ibdev, const char *fmt, ...)
957923abb9dSGal Pressman {
958923abb9dSGal Pressman 	struct va_format vaf;
959923abb9dSGal Pressman 	va_list args;
960923abb9dSGal Pressman 
961923abb9dSGal Pressman 	va_start(args, fmt);
962923abb9dSGal Pressman 
963923abb9dSGal Pressman 	vaf.fmt = fmt;
964923abb9dSGal Pressman 	vaf.va = &args;
965923abb9dSGal Pressman 
966923abb9dSGal Pressman 	if (ibdev && ibdev->dev.parent) {
967640d1eafSJim Cromie 		char buf[PREFIX_SIZE] = "";
968923abb9dSGal Pressman 
969923abb9dSGal Pressman 		dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent,
970923abb9dSGal Pressman 				"%s%s %s %s: %pV",
971923abb9dSGal Pressman 				dynamic_emit_prefix(descriptor, buf),
972923abb9dSGal Pressman 				dev_driver_string(ibdev->dev.parent),
973923abb9dSGal Pressman 				dev_name(ibdev->dev.parent),
974923abb9dSGal Pressman 				dev_name(&ibdev->dev),
975923abb9dSGal Pressman 				&vaf);
976923abb9dSGal Pressman 	} else if (ibdev) {
977923abb9dSGal Pressman 		printk(KERN_DEBUG "%s: %pV", dev_name(&ibdev->dev), &vaf);
978923abb9dSGal Pressman 	} else {
979923abb9dSGal Pressman 		printk(KERN_DEBUG "(NULL ib_device): %pV", &vaf);
980923abb9dSGal Pressman 	}
981923abb9dSGal Pressman 
982923abb9dSGal Pressman 	va_end(args);
983923abb9dSGal Pressman }
984923abb9dSGal Pressman EXPORT_SYMBOL(__dynamic_ibdev_dbg);
985923abb9dSGal Pressman 
986923abb9dSGal Pressman #endif
987923abb9dSGal Pressman 
988e9d376f0SJason Baron /*
9895ca17397SAndrew Halaney  * Install a noop handler to make dyndbg look like a normal kernel cli param.
9905ca17397SAndrew Halaney  * This avoids warnings about dyndbg being an unknown cli param when supplied
9915ca17397SAndrew Halaney  * by a user.
9925ca17397SAndrew Halaney  */
dyndbg_setup(char * str)9935ca17397SAndrew Halaney static __init int dyndbg_setup(char *str)
9945ca17397SAndrew Halaney {
9955ca17397SAndrew Halaney 	return 1;
9965ca17397SAndrew Halaney }
9975ca17397SAndrew Halaney 
9985ca17397SAndrew Halaney __setup("dyndbg=", dyndbg_setup);
9995ca17397SAndrew Halaney 
10005ca17397SAndrew Halaney /*
1001231821d4SMasatake YAMATO  * File_ops->write method for <debugfs>/dynamic_debug/control.  Gathers the
1002e9d376f0SJason Baron  * command text from userspace, parses and executes it.
1003e9d376f0SJason Baron  */
10047281491cSJim Cromie #define USER_BUF_PAGE 4096
ddebug_proc_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)1005e9d376f0SJason Baron static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
1006e9d376f0SJason Baron 				  size_t len, loff_t *offp)
1007e9d376f0SJason Baron {
10087281491cSJim Cromie 	char *tmpbuf;
1009fd89cfb8SThomas Renninger 	int ret;
1010e9d376f0SJason Baron 
1011e9d376f0SJason Baron 	if (len == 0)
1012e9d376f0SJason Baron 		return 0;
10137281491cSJim Cromie 	if (len > USER_BUF_PAGE - 1) {
10147281491cSJim Cromie 		pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
1015e9d376f0SJason Baron 		return -E2BIG;
10167281491cSJim Cromie 	}
101716e5c1fcSAl Viro 	tmpbuf = memdup_user_nul(ubuf, len);
101816e5c1fcSAl Viro 	if (IS_ERR(tmpbuf))
101916e5c1fcSAl Viro 		return PTR_ERR(tmpbuf);
102009ee10ffSJim Cromie 	v2pr_info("read %zu bytes from userspace\n", len);
1021e9d376f0SJason Baron 
10228e59b5cfSJim Cromie 	ret = ddebug_exec_queries(tmpbuf, NULL);
10237281491cSJim Cromie 	kfree(tmpbuf);
102485f7f6c0SJim Cromie 	if (ret < 0)
1025fd89cfb8SThomas Renninger 		return ret;
1026e9d376f0SJason Baron 
1027e9d376f0SJason Baron 	*offp += len;
1028e9d376f0SJason Baron 	return len;
1029e9d376f0SJason Baron }
1030e9d376f0SJason Baron 
1031e9d376f0SJason Baron /*
1032e9d376f0SJason Baron  * Set the iterator to point to the first _ddebug object
1033e9d376f0SJason Baron  * and return a pointer to that first object.  Returns
1034e9d376f0SJason Baron  * NULL if there are no _ddebugs at all.
1035e9d376f0SJason Baron  */
ddebug_iter_first(struct ddebug_iter * iter)1036e9d376f0SJason Baron static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
1037e9d376f0SJason Baron {
1038e9d376f0SJason Baron 	if (list_empty(&ddebug_tables)) {
1039e9d376f0SJason Baron 		iter->table = NULL;
1040e9d376f0SJason Baron 		return NULL;
1041e9d376f0SJason Baron 	}
1042e9d376f0SJason Baron 	iter->table = list_entry(ddebug_tables.next,
1043e9d376f0SJason Baron 				 struct ddebug_table, link);
1044773beabbSJim Cromie 	iter->idx = iter->table->num_ddebugs;
1045773beabbSJim Cromie 	return &iter->table->ddebugs[--iter->idx];
1046e9d376f0SJason Baron }
1047e9d376f0SJason Baron 
1048e9d376f0SJason Baron /*
1049e9d376f0SJason Baron  * Advance the iterator to point to the next _ddebug
1050e9d376f0SJason Baron  * object from the one the iterator currently points at,
1051e9d376f0SJason Baron  * and returns a pointer to the new _ddebug.  Returns
1052e9d376f0SJason Baron  * NULL if the iterator has seen all the _ddebugs.
1053e9d376f0SJason Baron  */
ddebug_iter_next(struct ddebug_iter * iter)1054e9d376f0SJason Baron static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
1055e9d376f0SJason Baron {
1056e9d376f0SJason Baron 	if (iter->table == NULL)
1057e9d376f0SJason Baron 		return NULL;
1058773beabbSJim Cromie 	if (--iter->idx < 0) {
1059e9d376f0SJason Baron 		/* iterate to next table */
1060e9d376f0SJason Baron 		if (list_is_last(&iter->table->link, &ddebug_tables)) {
1061e9d376f0SJason Baron 			iter->table = NULL;
1062e9d376f0SJason Baron 			return NULL;
1063e9d376f0SJason Baron 		}
1064e9d376f0SJason Baron 		iter->table = list_entry(iter->table->link.next,
1065e9d376f0SJason Baron 					 struct ddebug_table, link);
1066773beabbSJim Cromie 		iter->idx = iter->table->num_ddebugs;
1067773beabbSJim Cromie 		--iter->idx;
1068e9d376f0SJason Baron 	}
1069e9d376f0SJason Baron 	return &iter->table->ddebugs[iter->idx];
1070e9d376f0SJason Baron }
1071e9d376f0SJason Baron 
1072e9d376f0SJason Baron /*
1073e9d376f0SJason Baron  * Seq_ops start method.  Called at the start of every
1074e9d376f0SJason Baron  * read() call from userspace.  Takes the ddebug_lock and
1075e9d376f0SJason Baron  * seeks the seq_file's iterator to the given position.
1076e9d376f0SJason Baron  */
ddebug_proc_start(struct seq_file * m,loff_t * pos)1077e9d376f0SJason Baron static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
1078e9d376f0SJason Baron {
1079e9d376f0SJason Baron 	struct ddebug_iter *iter = m->private;
1080e9d376f0SJason Baron 	struct _ddebug *dp;
1081e9d376f0SJason Baron 	int n = *pos;
1082e9d376f0SJason Baron 
1083e9d376f0SJason Baron 	mutex_lock(&ddebug_lock);
1084e9d376f0SJason Baron 
1085e9d376f0SJason Baron 	if (!n)
1086e9d376f0SJason Baron 		return SEQ_START_TOKEN;
1087e9d376f0SJason Baron 	if (n < 0)
1088e9d376f0SJason Baron 		return NULL;
1089e9d376f0SJason Baron 	dp = ddebug_iter_first(iter);
1090e9d376f0SJason Baron 	while (dp != NULL && --n > 0)
1091e9d376f0SJason Baron 		dp = ddebug_iter_next(iter);
1092e9d376f0SJason Baron 	return dp;
1093e9d376f0SJason Baron }
1094e9d376f0SJason Baron 
1095e9d376f0SJason Baron /*
1096e9d376f0SJason Baron  * Seq_ops next method.  Called several times within a read()
1097e9d376f0SJason Baron  * call from userspace, with ddebug_lock held.  Walks to the
1098e9d376f0SJason Baron  * next _ddebug object with a special case for the header line.
1099e9d376f0SJason Baron  */
ddebug_proc_next(struct seq_file * m,void * p,loff_t * pos)1100e9d376f0SJason Baron static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
1101e9d376f0SJason Baron {
1102e9d376f0SJason Baron 	struct ddebug_iter *iter = m->private;
1103e9d376f0SJason Baron 	struct _ddebug *dp;
1104e9d376f0SJason Baron 
1105e9d376f0SJason Baron 	if (p == SEQ_START_TOKEN)
1106e9d376f0SJason Baron 		dp = ddebug_iter_first(iter);
1107e9d376f0SJason Baron 	else
1108e9d376f0SJason Baron 		dp = ddebug_iter_next(iter);
1109e9d376f0SJason Baron 	++*pos;
1110e9d376f0SJason Baron 	return dp;
1111e9d376f0SJason Baron }
1112e9d376f0SJason Baron 
1113a4a2a427SJim Cromie #define class_in_range(class_id, map)					\
1114a4a2a427SJim Cromie 	(class_id >= map->base && class_id < map->base + map->length)
1115a4a2a427SJim Cromie 
ddebug_class_name(struct ddebug_iter * iter,struct _ddebug * dp)1116a4a2a427SJim Cromie static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
1117a4a2a427SJim Cromie {
1118a4a2a427SJim Cromie 	struct ddebug_class_map *map;
1119a4a2a427SJim Cromie 
1120a4a2a427SJim Cromie 	list_for_each_entry(map, &iter->table->maps, link)
1121a4a2a427SJim Cromie 		if (class_in_range(dp->class_id, map))
1122a4a2a427SJim Cromie 			return map->class_names[dp->class_id - map->base];
1123a4a2a427SJim Cromie 
1124a4a2a427SJim Cromie 	return NULL;
1125a4a2a427SJim Cromie }
1126a4a2a427SJim Cromie 
1127e9d376f0SJason Baron /*
1128e9d376f0SJason Baron  * Seq_ops show method.  Called several times within a read()
1129e9d376f0SJason Baron  * call from userspace, with ddebug_lock held.  Formats the
1130e9d376f0SJason Baron  * current _ddebug as a single human-readable line, with a
1131e9d376f0SJason Baron  * special case for the header line.
1132e9d376f0SJason Baron  */
ddebug_proc_show(struct seq_file * m,void * p)1133e9d376f0SJason Baron static int ddebug_proc_show(struct seq_file *m, void *p)
1134e9d376f0SJason Baron {
1135e9d376f0SJason Baron 	struct ddebug_iter *iter = m->private;
1136e9d376f0SJason Baron 	struct _ddebug *dp = p;
1137f678ce8cSJim Cromie 	struct flagsbuf flags;
1138a4a2a427SJim Cromie 	char const *class;
1139e9d376f0SJason Baron 
1140e9d376f0SJason Baron 	if (p == SEQ_START_TOKEN) {
1141e9d376f0SJason Baron 		seq_puts(m,
1142e9d376f0SJason Baron 			 "# filename:lineno [module]function flags format\n");
1143e9d376f0SJason Baron 		return 0;
1144e9d376f0SJason Baron 	}
1145e9d376f0SJason Baron 
11465ca7d2a6SJim Cromie 	seq_printf(m, "%s:%u [%s]%s =%s \"",
11472b678319SJim Cromie 		   trim_prefix(dp->filename), dp->lineno,
1148e9d376f0SJason Baron 		   iter->table->mod_name, dp->function,
1149f678ce8cSJim Cromie 		   ddebug_describe_flags(dp->flags, &flags));
115047ea6f99SJim Cromie 	seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
1151a4a2a427SJim Cromie 	seq_puts(m, "\"");
1152a4a2a427SJim Cromie 
1153a4a2a427SJim Cromie 	if (dp->class_id != _DPRINTK_CLASS_DFLT) {
1154a4a2a427SJim Cromie 		class = ddebug_class_name(iter, dp);
1155a4a2a427SJim Cromie 		if (class)
1156a4a2a427SJim Cromie 			seq_printf(m, " class:%s", class);
1157a4a2a427SJim Cromie 		else
1158a4a2a427SJim Cromie 			seq_printf(m, " class unknown, _id:%d", dp->class_id);
1159a4a2a427SJim Cromie 	}
1160a4a2a427SJim Cromie 	seq_puts(m, "\n");
1161e9d376f0SJason Baron 
1162e9d376f0SJason Baron 	return 0;
1163e9d376f0SJason Baron }
1164e9d376f0SJason Baron 
1165e9d376f0SJason Baron /*
1166e9d376f0SJason Baron  * Seq_ops stop method.  Called at the end of each read()
1167e9d376f0SJason Baron  * call from userspace.  Drops ddebug_lock.
1168e9d376f0SJason Baron  */
ddebug_proc_stop(struct seq_file * m,void * p)1169e9d376f0SJason Baron static void ddebug_proc_stop(struct seq_file *m, void *p)
1170e9d376f0SJason Baron {
1171e9d376f0SJason Baron 	mutex_unlock(&ddebug_lock);
1172e9d376f0SJason Baron }
1173e9d376f0SJason Baron 
1174e9d376f0SJason Baron static const struct seq_operations ddebug_proc_seqops = {
1175e9d376f0SJason Baron 	.start = ddebug_proc_start,
1176e9d376f0SJason Baron 	.next = ddebug_proc_next,
1177e9d376f0SJason Baron 	.show = ddebug_proc_show,
1178e9d376f0SJason Baron 	.stop = ddebug_proc_stop
1179e9d376f0SJason Baron };
1180e9d376f0SJason Baron 
ddebug_proc_open(struct inode * inode,struct file * file)1181e9d376f0SJason Baron static int ddebug_proc_open(struct inode *inode, struct file *file)
1182e9d376f0SJason Baron {
11834bad78c5SRob Jones 	return seq_open_private(file, &ddebug_proc_seqops,
11844bad78c5SRob Jones 				sizeof(struct ddebug_iter));
1185e9d376f0SJason Baron }
1186e9d376f0SJason Baron 
1187e9d376f0SJason Baron static const struct file_operations ddebug_proc_fops = {
1188e9d376f0SJason Baron 	.owner = THIS_MODULE,
1189e9d376f0SJason Baron 	.open = ddebug_proc_open,
1190e9d376f0SJason Baron 	.read = seq_read,
1191e9d376f0SJason Baron 	.llseek = seq_lseek,
1192e9d376f0SJason Baron 	.release = seq_release_private,
1193e9d376f0SJason Baron 	.write = ddebug_proc_write
1194e9d376f0SJason Baron };
1195e9d376f0SJason Baron 
1196239a5791SGreg Kroah-Hartman static const struct proc_ops proc_fops = {
1197239a5791SGreg Kroah-Hartman 	.proc_open = ddebug_proc_open,
1198239a5791SGreg Kroah-Hartman 	.proc_read = seq_read,
1199239a5791SGreg Kroah-Hartman 	.proc_lseek = seq_lseek,
1200239a5791SGreg Kroah-Hartman 	.proc_release = seq_release_private,
1201239a5791SGreg Kroah-Hartman 	.proc_write = ddebug_proc_write
1202239a5791SGreg Kroah-Hartman };
1203239a5791SGreg Kroah-Hartman 
ddebug_attach_module_classes(struct ddebug_table * dt,struct ddebug_class_map * classes,int num_classes)1204c45f67acSJim Cromie static void ddebug_attach_module_classes(struct ddebug_table *dt,
1205c45f67acSJim Cromie 					 struct ddebug_class_map *classes,
1206c45f67acSJim Cromie 					 int num_classes)
1207c45f67acSJim Cromie {
1208c45f67acSJim Cromie 	struct ddebug_class_map *cm;
1209c45f67acSJim Cromie 	int i, j, ct = 0;
1210c45f67acSJim Cromie 
1211c45f67acSJim Cromie 	for (cm = classes, i = 0; i < num_classes; i++, cm++) {
1212c45f67acSJim Cromie 
1213c45f67acSJim Cromie 		if (!strcmp(cm->mod_name, dt->mod_name)) {
1214c45f67acSJim Cromie 
1215c45f67acSJim Cromie 			v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
1216c45f67acSJim Cromie 				  cm->mod_name, cm->base, cm->length, cm->map_type);
1217c45f67acSJim Cromie 
1218c45f67acSJim Cromie 			for (j = 0; j < cm->length; j++)
1219c45f67acSJim Cromie 				v3pr_info(" %d: %d %s\n", j + cm->base, j,
1220c45f67acSJim Cromie 					  cm->class_names[j]);
1221c45f67acSJim Cromie 
1222c45f67acSJim Cromie 			list_add(&cm->link, &dt->maps);
1223c45f67acSJim Cromie 			ct++;
1224c45f67acSJim Cromie 		}
1225c45f67acSJim Cromie 	}
1226c45f67acSJim Cromie 	if (ct)
1227c45f67acSJim Cromie 		vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
1228c45f67acSJim Cromie }
1229c45f67acSJim Cromie 
1230e9d376f0SJason Baron /*
1231e9d376f0SJason Baron  * Allocate a new ddebug_table for the given module
1232e9d376f0SJason Baron  * and add it to the global list.
1233e9d376f0SJason Baron  */
ddebug_add_module(struct _ddebug_info * di,const char * modname)12347deabd67SJason Baron static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
1235e9d376f0SJason Baron {
1236e9d376f0SJason Baron 	struct ddebug_table *dt;
1237e9d376f0SJason Baron 
1238b7b4eebdSJim Cromie 	v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
1239b7b4eebdSJim Cromie 	if (!di->num_descs) {
1240b7b4eebdSJim Cromie 		v3pr_info(" skip %s\n", modname);
1241b7b4eebdSJim Cromie 		return 0;
1242b7b4eebdSJim Cromie 	}
1243b7b4eebdSJim Cromie 
1244e9d376f0SJason Baron 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);
1245513770f5SRasmus Villemoes 	if (dt == NULL) {
1246b7b4eebdSJim Cromie 		pr_err("error adding module: %s\n", modname);
1247e9d376f0SJason Baron 		return -ENOMEM;
1248513770f5SRasmus Villemoes 	}
1249cdf6d006SRasmus Villemoes 	/*
1250cdf6d006SRasmus Villemoes 	 * For built-in modules, name lives in .rodata and is
1251cdf6d006SRasmus Villemoes 	 * immortal. For loaded modules, name points at the name[]
1252cdf6d006SRasmus Villemoes 	 * member of struct module, which lives at least as long as
1253cdf6d006SRasmus Villemoes 	 * this struct ddebug_table.
1254cdf6d006SRasmus Villemoes 	 */
1255b7b4eebdSJim Cromie 	dt->mod_name = modname;
1256b7b4eebdSJim Cromie 	dt->ddebugs = di->descs;
1257b7b4eebdSJim Cromie 	dt->num_ddebugs = di->num_descs;
1258b7b4eebdSJim Cromie 
1259b7b4eebdSJim Cromie 	INIT_LIST_HEAD(&dt->link);
1260c45f67acSJim Cromie 	INIT_LIST_HEAD(&dt->maps);
1261c45f67acSJim Cromie 
1262c45f67acSJim Cromie 	if (di->classes && di->num_classes)
1263c45f67acSJim Cromie 		ddebug_attach_module_classes(dt, di->classes, di->num_classes);
1264e9d376f0SJason Baron 
1265e9d376f0SJason Baron 	mutex_lock(&ddebug_lock);
12662ad556f7SJim Cromie 	list_add_tail(&dt->link, &ddebug_tables);
1267e9d376f0SJason Baron 	mutex_unlock(&ddebug_lock);
1268e9d376f0SJason Baron 
1269b7b4eebdSJim Cromie 	vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
1270e9d376f0SJason Baron 	return 0;
1271e9d376f0SJason Baron }
1272e9d376f0SJason Baron 
12736ab676e9SJim Cromie /* helper for ddebug_dyndbg_(boot|module)_param_cb */
ddebug_dyndbg_param_cb(char * param,char * val,const char * modname,int on_err)12746ab676e9SJim Cromie static int ddebug_dyndbg_param_cb(char *param, char *val,
12756ab676e9SJim Cromie 				const char *modname, int on_err)
1276b48420c1SJim Cromie {
1277b48420c1SJim Cromie 	char *sep;
1278b48420c1SJim Cromie 
1279b48420c1SJim Cromie 	sep = strchr(param, '.');
1280b48420c1SJim Cromie 	if (sep) {
12816ab676e9SJim Cromie 		/* needed only for ddebug_dyndbg_boot_param_cb */
1282b48420c1SJim Cromie 		*sep = '\0';
1283b48420c1SJim Cromie 		modname = param;
1284b48420c1SJim Cromie 		param = sep + 1;
1285b48420c1SJim Cromie 	}
1286b48420c1SJim Cromie 	if (strcmp(param, "dyndbg"))
12876ab676e9SJim Cromie 		return on_err; /* determined by caller */
1288b48420c1SJim Cromie 
12898e59b5cfSJim Cromie 	ddebug_exec_queries((val ? val : "+p"), modname);
12908e59b5cfSJim Cromie 
12919dbbc3b9SZhen Lei 	return 0; /* query failure shouldn't stop module load */
1292b48420c1SJim Cromie }
1293b48420c1SJim Cromie 
12946ab676e9SJim Cromie /* handle both dyndbg and $module.dyndbg params at boot */
ddebug_dyndbg_boot_param_cb(char * param,char * val,const char * unused,void * arg)12956ab676e9SJim Cromie static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
1296ecc86170SLuis R. Rodriguez 				const char *unused, void *arg)
1297b48420c1SJim Cromie {
12986ab676e9SJim Cromie 	vpr_info("%s=\"%s\"\n", param, val);
12996ab676e9SJim Cromie 	return ddebug_dyndbg_param_cb(param, val, NULL, 0);
13006ab676e9SJim Cromie }
1301b48420c1SJim Cromie 
13026ab676e9SJim Cromie /*
13036ab676e9SJim Cromie  * modprobe foo finds foo.params in boot-args, strips "foo.", and
13046ab676e9SJim Cromie  * passes them to load_module().  This callback gets unknown params,
13056ab676e9SJim Cromie  * processes dyndbg params, rejects others.
13066ab676e9SJim Cromie  */
ddebug_dyndbg_module_param_cb(char * param,char * val,const char * module)13076ab676e9SJim Cromie int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
13086ab676e9SJim Cromie {
13096ab676e9SJim Cromie 	vpr_info("module: %s %s=\"%s\"\n", module, param, val);
13106ab676e9SJim Cromie 	return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);
1311b48420c1SJim Cromie }
1312b48420c1SJim Cromie 
ddebug_table_free(struct ddebug_table * dt)1313e9d376f0SJason Baron static void ddebug_table_free(struct ddebug_table *dt)
1314e9d376f0SJason Baron {
1315e9d376f0SJason Baron 	list_del_init(&dt->link);
1316e9d376f0SJason Baron 	kfree(dt);
1317e9d376f0SJason Baron }
1318e9d376f0SJason Baron 
13197deabd67SJason Baron #ifdef CONFIG_MODULES
13207deabd67SJason Baron 
1321e9d376f0SJason Baron /*
1322e9d376f0SJason Baron  * Called in response to a module being unloaded.  Removes
1323e9d376f0SJason Baron  * any ddebug_table's which point at the module.
1324e9d376f0SJason Baron  */
ddebug_remove_module(const char * mod_name)13257deabd67SJason Baron static int ddebug_remove_module(const char *mod_name)
1326e9d376f0SJason Baron {
1327e9d376f0SJason Baron 	struct ddebug_table *dt, *nextdt;
1328e9d376f0SJason Baron 	int ret = -ENOENT;
1329e9d376f0SJason Baron 
1330e9d376f0SJason Baron 	mutex_lock(&ddebug_lock);
1331e9d376f0SJason Baron 	list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
13324573fe15SRasmus Villemoes 		if (dt->mod_name == mod_name) {
1333e9d376f0SJason Baron 			ddebug_table_free(dt);
1334e9d376f0SJason Baron 			ret = 0;
13354573fe15SRasmus Villemoes 			break;
1336e9d376f0SJason Baron 		}
1337e9d376f0SJason Baron 	}
1338e9d376f0SJason Baron 	mutex_unlock(&ddebug_lock);
13397a5e202dSJim Cromie 	if (!ret)
13407a5e202dSJim Cromie 		v2pr_info("removed module \"%s\"\n", mod_name);
1341e9d376f0SJason Baron 	return ret;
1342e9d376f0SJason Baron }
1343e9d376f0SJason Baron 
ddebug_module_notify(struct notifier_block * self,unsigned long val,void * data)13447deabd67SJason Baron static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
13457deabd67SJason Baron 				void *data)
13467deabd67SJason Baron {
13477deabd67SJason Baron 	struct module *mod = data;
13487deabd67SJason Baron 	int ret = 0;
13497deabd67SJason Baron 
13507deabd67SJason Baron 	switch (val) {
13517deabd67SJason Baron 	case MODULE_STATE_COMING:
13527deabd67SJason Baron 		ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
13537deabd67SJason Baron 		if (ret)
13547deabd67SJason Baron 			WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
13557deabd67SJason Baron 		break;
13567deabd67SJason Baron 	case MODULE_STATE_GOING:
13577deabd67SJason Baron 		ddebug_remove_module(mod->name);
13587deabd67SJason Baron 		break;
13597deabd67SJason Baron 	}
13607deabd67SJason Baron 
13617deabd67SJason Baron 	return notifier_from_errno(ret);
13627deabd67SJason Baron }
13637deabd67SJason Baron 
13647deabd67SJason Baron static struct notifier_block ddebug_module_nb = {
13657deabd67SJason Baron 	.notifier_call = ddebug_module_notify,
13667deabd67SJason Baron 	.priority = 0, /* dynamic debug depends on jump label */
13677deabd67SJason Baron };
13687deabd67SJason Baron 
13697deabd67SJason Baron #endif /* CONFIG_MODULES */
13707deabd67SJason Baron 
ddebug_remove_all_tables(void)1371e9d376f0SJason Baron static void ddebug_remove_all_tables(void)
1372e9d376f0SJason Baron {
1373e9d376f0SJason Baron 	mutex_lock(&ddebug_lock);
1374e9d376f0SJason Baron 	while (!list_empty(&ddebug_tables)) {
1375e9d376f0SJason Baron 		struct ddebug_table *dt = list_entry(ddebug_tables.next,
1376e9d376f0SJason Baron 						      struct ddebug_table,
1377e9d376f0SJason Baron 						      link);
1378e9d376f0SJason Baron 		ddebug_table_free(dt);
1379e9d376f0SJason Baron 	}
1380e9d376f0SJason Baron 	mutex_unlock(&ddebug_lock);
1381e9d376f0SJason Baron }
1382e9d376f0SJason Baron 
13836a5c083dSThomas Renninger static __initdata int ddebug_init_success;
13846a5c083dSThomas Renninger 
dynamic_debug_init_control(void)1385239a5791SGreg Kroah-Hartman static int __init dynamic_debug_init_control(void)
1386e9d376f0SJason Baron {
1387239a5791SGreg Kroah-Hartman 	struct proc_dir_entry *procfs_dir;
1388239a5791SGreg Kroah-Hartman 	struct dentry *debugfs_dir;
13896a5c083dSThomas Renninger 
13906a5c083dSThomas Renninger 	if (!ddebug_init_success)
13916a5c083dSThomas Renninger 		return -ENODEV;
1392e9d376f0SJason Baron 
1393239a5791SGreg Kroah-Hartman 	/* Create the control file in debugfs if it is enabled */
1394239a5791SGreg Kroah-Hartman 	if (debugfs_initialized()) {
1395239a5791SGreg Kroah-Hartman 		debugfs_dir = debugfs_create_dir("dynamic_debug", NULL);
1396239a5791SGreg Kroah-Hartman 		debugfs_create_file("control", 0644, debugfs_dir, NULL,
1397239a5791SGreg Kroah-Hartman 				    &ddebug_proc_fops);
1398239a5791SGreg Kroah-Hartman 	}
1399239a5791SGreg Kroah-Hartman 
1400239a5791SGreg Kroah-Hartman 	/* Also create the control file in procfs */
1401239a5791SGreg Kroah-Hartman 	procfs_dir = proc_mkdir("dynamic_debug", NULL);
1402239a5791SGreg Kroah-Hartman 	if (procfs_dir)
1403239a5791SGreg Kroah-Hartman 		proc_create("control", 0644, procfs_dir, &proc_fops);
14049fd714cdSGreg Kroah-Hartman 
14056a5c083dSThomas Renninger 	return 0;
14066a5c083dSThomas Renninger }
14076a5c083dSThomas Renninger 
dynamic_debug_init(void)14086a5c083dSThomas Renninger static int __init dynamic_debug_init(void)
14096a5c083dSThomas Renninger {
1410aa86a154SJim Cromie 	struct _ddebug *iter, *iter_mod_start;
1411aa86a154SJim Cromie 	int ret, i, mod_sites, mod_ct;
1412aa86a154SJim Cromie 	const char *modname;
1413b48420c1SJim Cromie 	char *cmdline;
14146a5c083dSThomas Renninger 
1415b7b4eebdSJim Cromie 	struct _ddebug_info di = {
1416b7b4eebdSJim Cromie 		.descs = __start___dyndbg,
141766f4006bSJim Cromie 		.classes = __start___dyndbg_classes,
1418b7b4eebdSJim Cromie 		.num_descs = __stop___dyndbg - __start___dyndbg,
141966f4006bSJim Cromie 		.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
1420b7b4eebdSJim Cromie 	};
1421b7b4eebdSJim Cromie 
14227deabd67SJason Baron #ifdef CONFIG_MODULES
14237deabd67SJason Baron 	ret = register_module_notifier(&ddebug_module_nb);
14247deabd67SJason Baron 	if (ret) {
14257deabd67SJason Baron 		pr_warn("Failed to register dynamic debug module notifier\n");
14267deabd67SJason Baron 		return ret;
14277deabd67SJason Baron 	}
14287deabd67SJason Baron #endif /* CONFIG_MODULES */
14297deabd67SJason Baron 
1430e5ebffe1SJim Cromie 	if (&__start___dyndbg == &__stop___dyndbg) {
1431ceabef7dSOrson Zhai 		if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
1432f657fd21SJoe Perches 			pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
1433b5b78f83SJim Cromie 			return 1;
1434b5b78f83SJim Cromie 		}
1435ceabef7dSOrson Zhai 		pr_info("Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build\n");
1436ceabef7dSOrson Zhai 		ddebug_init_success = 1;
1437ceabef7dSOrson Zhai 		return 0;
1438ceabef7dSOrson Zhai 	}
1439aa86a154SJim Cromie 
1440aa86a154SJim Cromie 	iter = iter_mod_start = __start___dyndbg;
1441e9d376f0SJason Baron 	modname = iter->modname;
1442aa86a154SJim Cromie 	i = mod_sites = mod_ct = 0;
1443aa86a154SJim Cromie 
1444aa86a154SJim Cromie 	for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
1445aa86a154SJim Cromie 
1446e9d376f0SJason Baron 		if (strcmp(modname, iter->modname)) {
1447aa86a154SJim Cromie 			mod_ct++;
1448b7b4eebdSJim Cromie 			di.num_descs = mod_sites;
1449b7b4eebdSJim Cromie 			di.descs = iter_mod_start;
14507deabd67SJason Baron 			ret = ddebug_add_module(&di, modname);
1451e9d376f0SJason Baron 			if (ret)
1452af442399SJim Cromie 				goto out_err;
1453aa86a154SJim Cromie 
1454aa86a154SJim Cromie 			mod_sites = 0;
1455e9d376f0SJason Baron 			modname = iter->modname;
1456aa86a154SJim Cromie 			iter_mod_start = iter;
1457e9d376f0SJason Baron 		}
1458e9d376f0SJason Baron 	}
1459b7b4eebdSJim Cromie 	di.num_descs = mod_sites;
1460b7b4eebdSJim Cromie 	di.descs = iter_mod_start;
14617deabd67SJason Baron 	ret = ddebug_add_module(&di, modname);
1462b5b78f83SJim Cromie 	if (ret)
1463af442399SJim Cromie 		goto out_err;
1464a648ec05SThomas Renninger 
1465af442399SJim Cromie 	ddebug_init_success = 1;
14667af56628SJim Cromie 	vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
1467aa86a154SJim Cromie 		 i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
1468aa86a154SJim Cromie 		 (int)((i * sizeof(struct _ddebug)) >> 10));
1469af442399SJim Cromie 
147066f4006bSJim Cromie 	if (di.num_classes)
147166f4006bSJim Cromie 		v2pr_info("  %d builtin ddebug class-maps\n", di.num_classes);
147266f4006bSJim Cromie 
1473b48420c1SJim Cromie 	/* now that ddebug tables are loaded, process all boot args
1474b48420c1SJim Cromie 	 * again to find and activate queries given in dyndbg params.
1475b48420c1SJim Cromie 	 * While this has already been done for known boot params, it
1476b48420c1SJim Cromie 	 * ignored the unknown ones (dyndbg in particular).  Reusing
1477b48420c1SJim Cromie 	 * parse_args avoids ad-hoc parsing.  This will also attempt
1478b48420c1SJim Cromie 	 * to activate queries for not-yet-loaded modules, which is
1479b48420c1SJim Cromie 	 * slightly noisy if verbose, but harmless.
1480b48420c1SJim Cromie 	 */
1481b48420c1SJim Cromie 	cmdline = kstrdup(saved_command_line, GFP_KERNEL);
1482b48420c1SJim Cromie 	parse_args("dyndbg params", cmdline, NULL,
1483ecc86170SLuis R. Rodriguez 		   0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb);
1484b48420c1SJim Cromie 	kfree(cmdline);
1485af442399SJim Cromie 	return 0;
1486a648ec05SThomas Renninger 
1487af442399SJim Cromie out_err:
1488e9d376f0SJason Baron 	ddebug_remove_all_tables();
1489e9d376f0SJason Baron 	return 0;
1490e9d376f0SJason Baron }
14916a5c083dSThomas Renninger /* Allow early initialization for boot messages via boot param */
14923ec5652aSJim Cromie early_initcall(dynamic_debug_init);
1493b48420c1SJim Cromie 
14946a5c083dSThomas Renninger /* Debugfs setup must be done later */
1495239a5791SGreg Kroah-Hartman fs_initcall(dynamic_debug_init_control);
1496