1 // SPDX-License-Identifier: GPL-2.0
3 * Userspace indexing of printk formats
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>
14 extern struct pi_entry *__start_printk_index[];
15 extern struct pi_entry *__stop_printk_index[];
17 /* The base dir for module formats, typically debugfs/printk/index/ */
18 static struct dentry *dfs_index;
20 static struct pi_entry *pi_get_entry(const struct module *mod, loff_t pos)
22 struct pi_entry **entries;
23 unsigned int nr_entries;
27 entries = mod->printk_index_start;
28 nr_entries = mod->printk_index_size;
33 /* vmlinux, comes from linker symbols */
34 entries = __start_printk_index;
35 nr_entries = __stop_printk_index - __start_printk_index;
38 if (pos >= nr_entries)
44 static void *pi_next(struct seq_file *s, void *v, loff_t *pos)
46 const struct module *mod = s->file->f_inode->i_private;
47 struct pi_entry *entry = pi_get_entry(mod, *pos);
54 static void *pi_start(struct seq_file *s, loff_t *pos)
57 * Make show() print the header line. Do not update *pos because
58 * pi_next() still has to return the entry at index 0 later.
61 return SEQ_START_TOKEN;
63 return pi_next(s, NULL, pos);
67 * We need both ESCAPE_ANY and explicit characters from ESCAPE_SPECIAL in @only
68 * because otherwise ESCAPE_NAP will cause double quotes and backslashes to be
69 * ignored for quoting.
71 #define seq_escape_printf_format(s, src) \
72 seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
74 static int pi_show(struct seq_file *s, void *v)
76 const struct pi_entry *entry = v;
77 int level = LOGLEVEL_DEFAULT;
78 enum printk_info_flags flags = 0;
81 if (v == SEQ_START_TOKEN) {
82 seq_puts(s, "# <level/flags> filename:line function \"format\"\n");
90 printk_parse_prefix(entry->level, &level, &flags);
92 prefix_len = printk_parse_prefix(entry->fmt, &level, &flags);
95 if (flags & LOG_CONT) {
97 * LOGLEVEL_DEFAULT here means "use the same level as the
98 * message we're continuing from", not the default message
99 * loglevel, so don't display it as such.
101 if (level == LOGLEVEL_DEFAULT)
104 seq_printf(s, "<%d,c>", level);
106 seq_printf(s, "<%d>", level);
108 seq_printf(s, " %s:%d %s \"", entry->file, entry->line, entry->func);
109 if (entry->subsys_fmt_prefix)
110 seq_escape_printf_format(s, entry->subsys_fmt_prefix);
111 seq_escape_printf_format(s, entry->fmt + prefix_len);
117 static void pi_stop(struct seq_file *p, void *v) { }
119 static const struct seq_operations dfs_index_sops = {
126 DEFINE_SEQ_ATTRIBUTE(dfs_index);
128 #ifdef CONFIG_MODULES
129 static const char *pi_get_module_name(struct module *mod)
131 return mod ? mod->name : "vmlinux";
134 static const char *pi_get_module_name(struct module *mod)
140 static void pi_create_file(struct module *mod)
142 debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index,
143 mod, &dfs_index_fops);
146 #ifdef CONFIG_MODULES
147 static void pi_remove_file(struct module *mod)
149 debugfs_remove(debugfs_lookup(pi_get_module_name(mod), dfs_index));
152 static int pi_module_notify(struct notifier_block *nb, unsigned long op,
155 struct module *mod = data;
158 case MODULE_STATE_COMING:
161 case MODULE_STATE_GOING:
164 default: /* we don't care about other module states */
171 static struct notifier_block module_printk_fmts_nb = {
172 .notifier_call = pi_module_notify,
175 static void __init pi_setup_module_notifier(void)
177 register_module_notifier(&module_printk_fmts_nb);
180 static inline void __init pi_setup_module_notifier(void) { }
183 static int __init pi_init(void)
185 struct dentry *dfs_root = debugfs_create_dir("printk", NULL);
187 dfs_index = debugfs_create_dir("index", dfs_root);
188 pi_setup_module_notifier();
189 pi_create_file(NULL);
194 /* debugfs comes up on core and must be initialised first */
195 postcore_initcall(pi_init);