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