Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Userspace indexing of printk formats
  4 */
  5
  6#include <linux/debugfs.h>
  7#include <linux/module.h>
  8#include <linux/printk.h>
  9#include <linux/slab.h>
 10#include <linux/string_helpers.h>
 11
 12#include "internal.h"
 13
 14extern struct pi_entry *__start_printk_index[];
 15extern struct pi_entry *__stop_printk_index[];
 16
 17/* The base dir for module formats, typically debugfs/printk/index/ */
 18static struct dentry *dfs_index;
 19
 20static struct pi_entry *pi_get_entry(const struct module *mod, loff_t pos)
 21{
 22	struct pi_entry **entries;
 23	unsigned int nr_entries;
 24
 25#ifdef CONFIG_MODULES
 26	if (mod) {
 27		entries = mod->printk_index_start;
 28		nr_entries = mod->printk_index_size;
 29	} else
 30#endif
 31	{
 32		/* vmlinux, comes from linker symbols */
 33		entries = __start_printk_index;
 34		nr_entries = __stop_printk_index - __start_printk_index;
 35	}
 36
 37	if (pos >= nr_entries)
 38		return NULL;
 39
 40	return entries[pos];
 41}
 42
 43static void *pi_next(struct seq_file *s, void *v, loff_t *pos)
 44{
 45	const struct module *mod = s->file->f_inode->i_private;
 46	struct pi_entry *entry = pi_get_entry(mod, *pos);
 47
 48	(*pos)++;
 49
 50	return entry;
 51}
 52
 53static void *pi_start(struct seq_file *s, loff_t *pos)
 54{
 55	/*
 56	 * Make show() print the header line. Do not update *pos because
 57	 * pi_next() still has to return the entry at index 0 later.
 58	 */
 59	if (*pos == 0)
 60		return SEQ_START_TOKEN;
 61
 62	return pi_next(s, NULL, pos);
 63}
 64
 65/*
 66 * We need both ESCAPE_ANY and explicit characters from ESCAPE_SPECIAL in @only
 67 * because otherwise ESCAPE_NAP will cause double quotes and backslashes to be
 68 * ignored for quoting.
 69 */
 70#define seq_escape_printf_format(s, src) \
 71	seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
 72
 73static int pi_show(struct seq_file *s, void *v)
 74{
 75	const struct pi_entry *entry = v;
 76	int level = LOGLEVEL_DEFAULT;
 77	enum printk_info_flags flags = 0;
 78	u16 prefix_len = 0;
 79
 80	if (v == SEQ_START_TOKEN) {
 81		seq_puts(s, "# <level/flags> filename:line function \"format\"\n");
 82		return 0;
 83	}
 84
 85	if (!entry->fmt)
 86		return 0;
 87
 88	if (entry->level)
 89		printk_parse_prefix(entry->level, &level, &flags);
 90	else
 91		prefix_len = printk_parse_prefix(entry->fmt, &level, &flags);
 92
 93
 94	if (flags & LOG_CONT) {
 95		/*
 96		 * LOGLEVEL_DEFAULT here means "use the same level as the
 97		 * message we're continuing from", not the default message
 98		 * loglevel, so don't display it as such.
 99		 */
100		if (level == LOGLEVEL_DEFAULT)
101			seq_puts(s, "<c>");
102		else
103			seq_printf(s, "<%d,c>", level);
104	} else
105		seq_printf(s, "<%d>", level);
106
107	seq_printf(s, " %s:%d %s \"", entry->file, entry->line, entry->func);
108	if (entry->subsys_fmt_prefix)
109		seq_escape_printf_format(s, entry->subsys_fmt_prefix);
110	seq_escape_printf_format(s, entry->fmt + prefix_len);
111	seq_puts(s, "\"\n");
112
113	return 0;
114}
115
116static void pi_stop(struct seq_file *p, void *v) { }
117
118static const struct seq_operations dfs_index_sops = {
119	.start = pi_start,
120	.next  = pi_next,
121	.show  = pi_show,
122	.stop  = pi_stop,
123};
124
125DEFINE_SEQ_ATTRIBUTE(dfs_index);
126
127#ifdef CONFIG_MODULES
128static const char *pi_get_module_name(struct module *mod)
129{
130	return mod ? mod->name : "vmlinux";
131}
132#else
133static const char *pi_get_module_name(struct module *mod)
134{
135	return "vmlinux";
136}
137#endif
138
139static void pi_create_file(struct module *mod)
140{
141	debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index,
142				       mod, &dfs_index_fops);
143}
144
145#ifdef CONFIG_MODULES
146static void pi_remove_file(struct module *mod)
147{
148	debugfs_lookup_and_remove(pi_get_module_name(mod), dfs_index);
149}
150
151static int pi_module_notify(struct notifier_block *nb, unsigned long op,
152			    void *data)
153{
154	struct module *mod = data;
155
156	switch (op) {
157	case MODULE_STATE_COMING:
158		pi_create_file(mod);
159		break;
160	case MODULE_STATE_GOING:
161		pi_remove_file(mod);
162		break;
163	default: /* we don't care about other module states */
164		break;
165	}
166
167	return NOTIFY_OK;
168}
169
170static struct notifier_block module_printk_fmts_nb = {
171	.notifier_call = pi_module_notify,
172};
173
174static void __init pi_setup_module_notifier(void)
175{
176	register_module_notifier(&module_printk_fmts_nb);
177}
178#else
179static inline void __init pi_setup_module_notifier(void) { }
180#endif
181
182static int __init pi_init(void)
183{
184	struct dentry *dfs_root = debugfs_create_dir("printk", NULL);
185
186	dfs_index = debugfs_create_dir("index", dfs_root);
187	pi_setup_module_notifier();
188	pi_create_file(NULL);
189
190	return 0;
191}
192
193/* debugfs comes up on core and must be initialised first */
194postcore_initcall(pi_init);