Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/lib/dynamic_debug.c
10811 views
1
/*
2
* lib/dynamic_debug.c
3
*
4
* make pr_debug()/dev_dbg() calls runtime configurable based upon their
5
* source module.
6
*
7
* Copyright (C) 2008 Jason Baron <[email protected]>
8
* By Greg Banks <[email protected]>
9
* Copyright (c) 2008 Silicon Graphics Inc. All Rights Reserved.
10
* Copyright (C) 2011 Bart Van Assche. All Rights Reserved.
11
*/
12
13
#include <linux/kernel.h>
14
#include <linux/module.h>
15
#include <linux/moduleparam.h>
16
#include <linux/kallsyms.h>
17
#include <linux/version.h>
18
#include <linux/types.h>
19
#include <linux/mutex.h>
20
#include <linux/proc_fs.h>
21
#include <linux/seq_file.h>
22
#include <linux/list.h>
23
#include <linux/sysctl.h>
24
#include <linux/ctype.h>
25
#include <linux/string.h>
26
#include <linux/uaccess.h>
27
#include <linux/dynamic_debug.h>
28
#include <linux/debugfs.h>
29
#include <linux/slab.h>
30
#include <linux/jump_label.h>
31
#include <linux/hardirq.h>
32
#include <linux/sched.h>
33
34
extern struct _ddebug __start___verbose[];
35
extern struct _ddebug __stop___verbose[];
36
37
struct ddebug_table {
38
struct list_head link;
39
char *mod_name;
40
unsigned int num_ddebugs;
41
unsigned int num_enabled;
42
struct _ddebug *ddebugs;
43
};
44
45
struct ddebug_query {
46
const char *filename;
47
const char *module;
48
const char *function;
49
const char *format;
50
unsigned int first_lineno, last_lineno;
51
};
52
53
struct ddebug_iter {
54
struct ddebug_table *table;
55
unsigned int idx;
56
};
57
58
static DEFINE_MUTEX(ddebug_lock);
59
static LIST_HEAD(ddebug_tables);
60
static int verbose = 0;
61
62
/* Return the last part of a pathname */
63
static inline const char *basename(const char *path)
64
{
65
const char *tail = strrchr(path, '/');
66
return tail ? tail+1 : path;
67
}
68
69
static struct { unsigned flag:8; char opt_char; } opt_array[] = {
70
{ _DPRINTK_FLAGS_PRINT, 'p' },
71
{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
72
{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
73
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
74
{ _DPRINTK_FLAGS_INCL_TID, 't' },
75
};
76
77
/* format a string into buf[] which describes the _ddebug's flags */
78
static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
79
size_t maxlen)
80
{
81
char *p = buf;
82
int i;
83
84
BUG_ON(maxlen < 4);
85
for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
86
if (dp->flags & opt_array[i].flag)
87
*p++ = opt_array[i].opt_char;
88
if (p == buf)
89
*p++ = '-';
90
*p = '\0';
91
92
return buf;
93
}
94
95
/*
96
* Search the tables for _ddebug's which match the given
97
* `query' and apply the `flags' and `mask' to them. Tells
98
* the user which ddebug's were changed, or whether none
99
* were matched.
100
*/
101
static void ddebug_change(const struct ddebug_query *query,
102
unsigned int flags, unsigned int mask)
103
{
104
int i;
105
struct ddebug_table *dt;
106
unsigned int newflags;
107
unsigned int nfound = 0;
108
char flagbuf[8];
109
110
/* search for matching ddebugs */
111
mutex_lock(&ddebug_lock);
112
list_for_each_entry(dt, &ddebug_tables, link) {
113
114
/* match against the module name */
115
if (query->module != NULL &&
116
strcmp(query->module, dt->mod_name))
117
continue;
118
119
for (i = 0 ; i < dt->num_ddebugs ; i++) {
120
struct _ddebug *dp = &dt->ddebugs[i];
121
122
/* match against the source filename */
123
if (query->filename != NULL &&
124
strcmp(query->filename, dp->filename) &&
125
strcmp(query->filename, basename(dp->filename)))
126
continue;
127
128
/* match against the function */
129
if (query->function != NULL &&
130
strcmp(query->function, dp->function))
131
continue;
132
133
/* match against the format */
134
if (query->format != NULL &&
135
strstr(dp->format, query->format) == NULL)
136
continue;
137
138
/* match against the line number range */
139
if (query->first_lineno &&
140
dp->lineno < query->first_lineno)
141
continue;
142
if (query->last_lineno &&
143
dp->lineno > query->last_lineno)
144
continue;
145
146
nfound++;
147
148
newflags = (dp->flags & mask) | flags;
149
if (newflags == dp->flags)
150
continue;
151
152
if (!newflags)
153
dt->num_enabled--;
154
else if (!dp->flags)
155
dt->num_enabled++;
156
dp->flags = newflags;
157
if (newflags)
158
dp->enabled = 1;
159
else
160
dp->enabled = 0;
161
if (verbose)
162
printk(KERN_INFO
163
"ddebug: changed %s:%d [%s]%s %s\n",
164
dp->filename, dp->lineno,
165
dt->mod_name, dp->function,
166
ddebug_describe_flags(dp, flagbuf,
167
sizeof(flagbuf)));
168
}
169
}
170
mutex_unlock(&ddebug_lock);
171
172
if (!nfound && verbose)
173
printk(KERN_INFO "ddebug: no matches for query\n");
174
}
175
176
/*
177
* Split the buffer `buf' into space-separated words.
178
* Handles simple " and ' quoting, i.e. without nested,
179
* embedded or escaped \". Return the number of words
180
* or <0 on error.
181
*/
182
static int ddebug_tokenize(char *buf, char *words[], int maxwords)
183
{
184
int nwords = 0;
185
186
while (*buf) {
187
char *end;
188
189
/* Skip leading whitespace */
190
buf = skip_spaces(buf);
191
if (!*buf)
192
break; /* oh, it was trailing whitespace */
193
194
/* Run `end' over a word, either whitespace separated or quoted */
195
if (*buf == '"' || *buf == '\'') {
196
int quote = *buf++;
197
for (end = buf ; *end && *end != quote ; end++)
198
;
199
if (!*end)
200
return -EINVAL; /* unclosed quote */
201
} else {
202
for (end = buf ; *end && !isspace(*end) ; end++)
203
;
204
BUG_ON(end == buf);
205
}
206
/* Here `buf' is the start of the word, `end' is one past the end */
207
208
if (nwords == maxwords)
209
return -EINVAL; /* ran out of words[] before bytes */
210
if (*end)
211
*end++ = '\0'; /* terminate the word */
212
words[nwords++] = buf;
213
buf = end;
214
}
215
216
if (verbose) {
217
int i;
218
printk(KERN_INFO "%s: split into words:", __func__);
219
for (i = 0 ; i < nwords ; i++)
220
printk(" \"%s\"", words[i]);
221
printk("\n");
222
}
223
224
return nwords;
225
}
226
227
/*
228
* Parse a single line number. Note that the empty string ""
229
* is treated as a special case and converted to zero, which
230
* is later treated as a "don't care" value.
231
*/
232
static inline int parse_lineno(const char *str, unsigned int *val)
233
{
234
char *end = NULL;
235
BUG_ON(str == NULL);
236
if (*str == '\0') {
237
*val = 0;
238
return 0;
239
}
240
*val = simple_strtoul(str, &end, 10);
241
return end == NULL || end == str || *end != '\0' ? -EINVAL : 0;
242
}
243
244
/*
245
* Undo octal escaping in a string, inplace. This is useful to
246
* allow the user to express a query which matches a format
247
* containing embedded spaces.
248
*/
249
#define isodigit(c) ((c) >= '0' && (c) <= '7')
250
static char *unescape(char *str)
251
{
252
char *in = str;
253
char *out = str;
254
255
while (*in) {
256
if (*in == '\\') {
257
if (in[1] == '\\') {
258
*out++ = '\\';
259
in += 2;
260
continue;
261
} else if (in[1] == 't') {
262
*out++ = '\t';
263
in += 2;
264
continue;
265
} else if (in[1] == 'n') {
266
*out++ = '\n';
267
in += 2;
268
continue;
269
} else if (isodigit(in[1]) &&
270
isodigit(in[2]) &&
271
isodigit(in[3])) {
272
*out++ = ((in[1] - '0')<<6) |
273
((in[2] - '0')<<3) |
274
(in[3] - '0');
275
in += 4;
276
continue;
277
}
278
}
279
*out++ = *in++;
280
}
281
*out = '\0';
282
283
return str;
284
}
285
286
/*
287
* Parse words[] as a ddebug query specification, which is a series
288
* of (keyword, value) pairs chosen from these possibilities:
289
*
290
* func <function-name>
291
* file <full-pathname>
292
* file <base-filename>
293
* module <module-name>
294
* format <escaped-string-to-find-in-format>
295
* line <lineno>
296
* line <first-lineno>-<last-lineno> // where either may be empty
297
*/
298
static int ddebug_parse_query(char *words[], int nwords,
299
struct ddebug_query *query)
300
{
301
unsigned int i;
302
303
/* check we have an even number of words */
304
if (nwords % 2 != 0)
305
return -EINVAL;
306
memset(query, 0, sizeof(*query));
307
308
for (i = 0 ; i < nwords ; i += 2) {
309
if (!strcmp(words[i], "func"))
310
query->function = words[i+1];
311
else if (!strcmp(words[i], "file"))
312
query->filename = words[i+1];
313
else if (!strcmp(words[i], "module"))
314
query->module = words[i+1];
315
else if (!strcmp(words[i], "format"))
316
query->format = unescape(words[i+1]);
317
else if (!strcmp(words[i], "line")) {
318
char *first = words[i+1];
319
char *last = strchr(first, '-');
320
if (last)
321
*last++ = '\0';
322
if (parse_lineno(first, &query->first_lineno) < 0)
323
return -EINVAL;
324
if (last != NULL) {
325
/* range <first>-<last> */
326
if (parse_lineno(last, &query->last_lineno) < 0)
327
return -EINVAL;
328
} else {
329
query->last_lineno = query->first_lineno;
330
}
331
} else {
332
if (verbose)
333
printk(KERN_ERR "%s: unknown keyword \"%s\"\n",
334
__func__, words[i]);
335
return -EINVAL;
336
}
337
}
338
339
if (verbose)
340
printk(KERN_INFO "%s: q->function=\"%s\" q->filename=\"%s\" "
341
"q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
342
__func__, query->function, query->filename,
343
query->module, query->format, query->first_lineno,
344
query->last_lineno);
345
346
return 0;
347
}
348
349
/*
350
* Parse `str' as a flags specification, format [-+=][p]+.
351
* Sets up *maskp and *flagsp to be used when changing the
352
* flags fields of matched _ddebug's. Returns 0 on success
353
* or <0 on error.
354
*/
355
static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
356
unsigned int *maskp)
357
{
358
unsigned flags = 0;
359
int op = '=', i;
360
361
switch (*str) {
362
case '+':
363
case '-':
364
case '=':
365
op = *str++;
366
break;
367
default:
368
return -EINVAL;
369
}
370
if (verbose)
371
printk(KERN_INFO "%s: op='%c'\n", __func__, op);
372
373
for ( ; *str ; ++str) {
374
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
375
if (*str == opt_array[i].opt_char) {
376
flags |= opt_array[i].flag;
377
break;
378
}
379
}
380
if (i < 0)
381
return -EINVAL;
382
}
383
if (flags == 0)
384
return -EINVAL;
385
if (verbose)
386
printk(KERN_INFO "%s: flags=0x%x\n", __func__, flags);
387
388
/* calculate final *flagsp, *maskp according to mask and op */
389
switch (op) {
390
case '=':
391
*maskp = 0;
392
*flagsp = flags;
393
break;
394
case '+':
395
*maskp = ~0U;
396
*flagsp = flags;
397
break;
398
case '-':
399
*maskp = ~flags;
400
*flagsp = 0;
401
break;
402
}
403
if (verbose)
404
printk(KERN_INFO "%s: *flagsp=0x%x *maskp=0x%x\n",
405
__func__, *flagsp, *maskp);
406
return 0;
407
}
408
409
static int ddebug_exec_query(char *query_string)
410
{
411
unsigned int flags = 0, mask = 0;
412
struct ddebug_query query;
413
#define MAXWORDS 9
414
int nwords;
415
char *words[MAXWORDS];
416
417
nwords = ddebug_tokenize(query_string, words, MAXWORDS);
418
if (nwords <= 0)
419
return -EINVAL;
420
if (ddebug_parse_query(words, nwords-1, &query))
421
return -EINVAL;
422
if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
423
return -EINVAL;
424
425
/* actually go and implement the change */
426
ddebug_change(&query, flags, mask);
427
return 0;
428
}
429
430
int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
431
{
432
va_list args;
433
int res;
434
435
BUG_ON(!descriptor);
436
BUG_ON(!fmt);
437
438
va_start(args, fmt);
439
res = printk(KERN_DEBUG);
440
if (descriptor->flags & _DPRINTK_FLAGS_INCL_TID) {
441
if (in_interrupt())
442
res += printk(KERN_CONT "<intr> ");
443
else
444
res += printk(KERN_CONT "[%d] ", task_pid_vnr(current));
445
}
446
if (descriptor->flags & _DPRINTK_FLAGS_INCL_MODNAME)
447
res += printk(KERN_CONT "%s:", descriptor->modname);
448
if (descriptor->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
449
res += printk(KERN_CONT "%s:", descriptor->function);
450
if (descriptor->flags & _DPRINTK_FLAGS_INCL_LINENO)
451
res += printk(KERN_CONT "%d ", descriptor->lineno);
452
res += vprintk(fmt, args);
453
va_end(args);
454
455
return res;
456
}
457
EXPORT_SYMBOL(__dynamic_pr_debug);
458
459
static __initdata char ddebug_setup_string[1024];
460
static __init int ddebug_setup_query(char *str)
461
{
462
if (strlen(str) >= 1024) {
463
pr_warning("ddebug boot param string too large\n");
464
return 0;
465
}
466
strcpy(ddebug_setup_string, str);
467
return 1;
468
}
469
470
__setup("ddebug_query=", ddebug_setup_query);
471
472
/*
473
* File_ops->write method for <debugfs>/dynamic_debug/conrol. Gathers the
474
* command text from userspace, parses and executes it.
475
*/
476
static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
477
size_t len, loff_t *offp)
478
{
479
char tmpbuf[256];
480
int ret;
481
482
if (len == 0)
483
return 0;
484
/* we don't check *offp -- multiple writes() are allowed */
485
if (len > sizeof(tmpbuf)-1)
486
return -E2BIG;
487
if (copy_from_user(tmpbuf, ubuf, len))
488
return -EFAULT;
489
tmpbuf[len] = '\0';
490
if (verbose)
491
printk(KERN_INFO "%s: read %d bytes from userspace\n",
492
__func__, (int)len);
493
494
ret = ddebug_exec_query(tmpbuf);
495
if (ret)
496
return ret;
497
498
*offp += len;
499
return len;
500
}
501
502
/*
503
* Set the iterator to point to the first _ddebug object
504
* and return a pointer to that first object. Returns
505
* NULL if there are no _ddebugs at all.
506
*/
507
static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
508
{
509
if (list_empty(&ddebug_tables)) {
510
iter->table = NULL;
511
iter->idx = 0;
512
return NULL;
513
}
514
iter->table = list_entry(ddebug_tables.next,
515
struct ddebug_table, link);
516
iter->idx = 0;
517
return &iter->table->ddebugs[iter->idx];
518
}
519
520
/*
521
* Advance the iterator to point to the next _ddebug
522
* object from the one the iterator currently points at,
523
* and returns a pointer to the new _ddebug. Returns
524
* NULL if the iterator has seen all the _ddebugs.
525
*/
526
static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
527
{
528
if (iter->table == NULL)
529
return NULL;
530
if (++iter->idx == iter->table->num_ddebugs) {
531
/* iterate to next table */
532
iter->idx = 0;
533
if (list_is_last(&iter->table->link, &ddebug_tables)) {
534
iter->table = NULL;
535
return NULL;
536
}
537
iter->table = list_entry(iter->table->link.next,
538
struct ddebug_table, link);
539
}
540
return &iter->table->ddebugs[iter->idx];
541
}
542
543
/*
544
* Seq_ops start method. Called at the start of every
545
* read() call from userspace. Takes the ddebug_lock and
546
* seeks the seq_file's iterator to the given position.
547
*/
548
static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
549
{
550
struct ddebug_iter *iter = m->private;
551
struct _ddebug *dp;
552
int n = *pos;
553
554
if (verbose)
555
printk(KERN_INFO "%s: called m=%p *pos=%lld\n",
556
__func__, m, (unsigned long long)*pos);
557
558
mutex_lock(&ddebug_lock);
559
560
if (!n)
561
return SEQ_START_TOKEN;
562
if (n < 0)
563
return NULL;
564
dp = ddebug_iter_first(iter);
565
while (dp != NULL && --n > 0)
566
dp = ddebug_iter_next(iter);
567
return dp;
568
}
569
570
/*
571
* Seq_ops next method. Called several times within a read()
572
* call from userspace, with ddebug_lock held. Walks to the
573
* next _ddebug object with a special case for the header line.
574
*/
575
static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
576
{
577
struct ddebug_iter *iter = m->private;
578
struct _ddebug *dp;
579
580
if (verbose)
581
printk(KERN_INFO "%s: called m=%p p=%p *pos=%lld\n",
582
__func__, m, p, (unsigned long long)*pos);
583
584
if (p == SEQ_START_TOKEN)
585
dp = ddebug_iter_first(iter);
586
else
587
dp = ddebug_iter_next(iter);
588
++*pos;
589
return dp;
590
}
591
592
/*
593
* Seq_ops show method. Called several times within a read()
594
* call from userspace, with ddebug_lock held. Formats the
595
* current _ddebug as a single human-readable line, with a
596
* special case for the header line.
597
*/
598
static int ddebug_proc_show(struct seq_file *m, void *p)
599
{
600
struct ddebug_iter *iter = m->private;
601
struct _ddebug *dp = p;
602
char flagsbuf[8];
603
604
if (verbose)
605
printk(KERN_INFO "%s: called m=%p p=%p\n",
606
__func__, m, p);
607
608
if (p == SEQ_START_TOKEN) {
609
seq_puts(m,
610
"# filename:lineno [module]function flags format\n");
611
return 0;
612
}
613
614
seq_printf(m, "%s:%u [%s]%s %s \"",
615
dp->filename, dp->lineno,
616
iter->table->mod_name, dp->function,
617
ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
618
seq_escape(m, dp->format, "\t\r\n\"");
619
seq_puts(m, "\"\n");
620
621
return 0;
622
}
623
624
/*
625
* Seq_ops stop method. Called at the end of each read()
626
* call from userspace. Drops ddebug_lock.
627
*/
628
static void ddebug_proc_stop(struct seq_file *m, void *p)
629
{
630
if (verbose)
631
printk(KERN_INFO "%s: called m=%p p=%p\n",
632
__func__, m, p);
633
mutex_unlock(&ddebug_lock);
634
}
635
636
static const struct seq_operations ddebug_proc_seqops = {
637
.start = ddebug_proc_start,
638
.next = ddebug_proc_next,
639
.show = ddebug_proc_show,
640
.stop = ddebug_proc_stop
641
};
642
643
/*
644
* File_ops->open method for <debugfs>/dynamic_debug/control. Does the seq_file
645
* setup dance, and also creates an iterator to walk the _ddebugs.
646
* Note that we create a seq_file always, even for O_WRONLY files
647
* where it's not needed, as doing so simplifies the ->release method.
648
*/
649
static int ddebug_proc_open(struct inode *inode, struct file *file)
650
{
651
struct ddebug_iter *iter;
652
int err;
653
654
if (verbose)
655
printk(KERN_INFO "%s: called\n", __func__);
656
657
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
658
if (iter == NULL)
659
return -ENOMEM;
660
661
err = seq_open(file, &ddebug_proc_seqops);
662
if (err) {
663
kfree(iter);
664
return err;
665
}
666
((struct seq_file *) file->private_data)->private = iter;
667
return 0;
668
}
669
670
static const struct file_operations ddebug_proc_fops = {
671
.owner = THIS_MODULE,
672
.open = ddebug_proc_open,
673
.read = seq_read,
674
.llseek = seq_lseek,
675
.release = seq_release_private,
676
.write = ddebug_proc_write
677
};
678
679
/*
680
* Allocate a new ddebug_table for the given module
681
* and add it to the global list.
682
*/
683
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
684
const char *name)
685
{
686
struct ddebug_table *dt;
687
char *new_name;
688
689
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
690
if (dt == NULL)
691
return -ENOMEM;
692
new_name = kstrdup(name, GFP_KERNEL);
693
if (new_name == NULL) {
694
kfree(dt);
695
return -ENOMEM;
696
}
697
dt->mod_name = new_name;
698
dt->num_ddebugs = n;
699
dt->num_enabled = 0;
700
dt->ddebugs = tab;
701
702
mutex_lock(&ddebug_lock);
703
list_add_tail(&dt->link, &ddebug_tables);
704
mutex_unlock(&ddebug_lock);
705
706
if (verbose)
707
printk(KERN_INFO "%u debug prints in module %s\n",
708
n, dt->mod_name);
709
return 0;
710
}
711
EXPORT_SYMBOL_GPL(ddebug_add_module);
712
713
static void ddebug_table_free(struct ddebug_table *dt)
714
{
715
list_del_init(&dt->link);
716
kfree(dt->mod_name);
717
kfree(dt);
718
}
719
720
/*
721
* Called in response to a module being unloaded. Removes
722
* any ddebug_table's which point at the module.
723
*/
724
int ddebug_remove_module(const char *mod_name)
725
{
726
struct ddebug_table *dt, *nextdt;
727
int ret = -ENOENT;
728
729
if (verbose)
730
printk(KERN_INFO "%s: removing module \"%s\"\n",
731
__func__, mod_name);
732
733
mutex_lock(&ddebug_lock);
734
list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
735
if (!strcmp(dt->mod_name, mod_name)) {
736
ddebug_table_free(dt);
737
ret = 0;
738
}
739
}
740
mutex_unlock(&ddebug_lock);
741
return ret;
742
}
743
EXPORT_SYMBOL_GPL(ddebug_remove_module);
744
745
static void ddebug_remove_all_tables(void)
746
{
747
mutex_lock(&ddebug_lock);
748
while (!list_empty(&ddebug_tables)) {
749
struct ddebug_table *dt = list_entry(ddebug_tables.next,
750
struct ddebug_table,
751
link);
752
ddebug_table_free(dt);
753
}
754
mutex_unlock(&ddebug_lock);
755
}
756
757
static __initdata int ddebug_init_success;
758
759
static int __init dynamic_debug_init_debugfs(void)
760
{
761
struct dentry *dir, *file;
762
763
if (!ddebug_init_success)
764
return -ENODEV;
765
766
dir = debugfs_create_dir("dynamic_debug", NULL);
767
if (!dir)
768
return -ENOMEM;
769
file = debugfs_create_file("control", 0644, dir, NULL,
770
&ddebug_proc_fops);
771
if (!file) {
772
debugfs_remove(dir);
773
return -ENOMEM;
774
}
775
return 0;
776
}
777
778
static int __init dynamic_debug_init(void)
779
{
780
struct _ddebug *iter, *iter_start;
781
const char *modname = NULL;
782
int ret = 0;
783
int n = 0;
784
785
if (__start___verbose != __stop___verbose) {
786
iter = __start___verbose;
787
modname = iter->modname;
788
iter_start = iter;
789
for (; iter < __stop___verbose; iter++) {
790
if (strcmp(modname, iter->modname)) {
791
ret = ddebug_add_module(iter_start, n, modname);
792
if (ret)
793
goto out_free;
794
n = 0;
795
modname = iter->modname;
796
iter_start = iter;
797
}
798
n++;
799
}
800
ret = ddebug_add_module(iter_start, n, modname);
801
}
802
803
/* ddebug_query boot param got passed -> set it up */
804
if (ddebug_setup_string[0] != '\0') {
805
ret = ddebug_exec_query(ddebug_setup_string);
806
if (ret)
807
pr_warning("Invalid ddebug boot param %s",
808
ddebug_setup_string);
809
else
810
pr_info("ddebug initialized with string %s",
811
ddebug_setup_string);
812
}
813
814
out_free:
815
if (ret)
816
ddebug_remove_all_tables();
817
else
818
ddebug_init_success = 1;
819
return 0;
820
}
821
/* Allow early initialization for boot messages via boot param */
822
arch_initcall(dynamic_debug_init);
823
/* Debugfs setup must be done later */
824
module_init(dynamic_debug_init_debugfs);
825
826