133701557SChris Down // SPDX-License-Identifier: GPL-2.0
233701557SChris Down /*
333701557SChris Down * Userspace indexing of printk formats
433701557SChris Down */
533701557SChris Down
633701557SChris Down #include <linux/debugfs.h>
733701557SChris Down #include <linux/module.h>
833701557SChris Down #include <linux/printk.h>
933701557SChris Down #include <linux/slab.h>
1033701557SChris Down #include <linux/string_helpers.h>
1133701557SChris Down
1233701557SChris Down #include "internal.h"
1333701557SChris Down
1433701557SChris Down extern struct pi_entry *__start_printk_index[];
1533701557SChris Down extern struct pi_entry *__stop_printk_index[];
1633701557SChris Down
1733701557SChris Down /* The base dir for module formats, typically debugfs/printk/index/ */
1833701557SChris Down static struct dentry *dfs_index;
1933701557SChris Down
pi_get_entry(const struct module * mod,loff_t pos)2033701557SChris Down static struct pi_entry *pi_get_entry(const struct module *mod, loff_t pos)
2133701557SChris Down {
2233701557SChris Down struct pi_entry **entries;
2333701557SChris Down unsigned int nr_entries;
2433701557SChris Down
2533701557SChris Down #ifdef CONFIG_MODULES
2633701557SChris Down if (mod) {
2733701557SChris Down entries = mod->printk_index_start;
2833701557SChris Down nr_entries = mod->printk_index_size;
295aa7eea9SArnd Bergmann } else
3033701557SChris Down #endif
315aa7eea9SArnd Bergmann {
3233701557SChris Down /* vmlinux, comes from linker symbols */
3333701557SChris Down entries = __start_printk_index;
3433701557SChris Down nr_entries = __stop_printk_index - __start_printk_index;
3533701557SChris Down }
3633701557SChris Down
3733701557SChris Down if (pos >= nr_entries)
3833701557SChris Down return NULL;
3933701557SChris Down
4033701557SChris Down return entries[pos];
4133701557SChris Down }
4233701557SChris Down
pi_next(struct seq_file * s,void * v,loff_t * pos)4333701557SChris Down static void *pi_next(struct seq_file *s, void *v, loff_t *pos)
4433701557SChris Down {
4533701557SChris Down const struct module *mod = s->file->f_inode->i_private;
4633701557SChris Down struct pi_entry *entry = pi_get_entry(mod, *pos);
4733701557SChris Down
4833701557SChris Down (*pos)++;
4933701557SChris Down
5033701557SChris Down return entry;
5133701557SChris Down }
5233701557SChris Down
pi_start(struct seq_file * s,loff_t * pos)5333701557SChris Down static void *pi_start(struct seq_file *s, loff_t *pos)
5433701557SChris Down {
5533701557SChris Down /*
5633701557SChris Down * Make show() print the header line. Do not update *pos because
5733701557SChris Down * pi_next() still has to return the entry at index 0 later.
5833701557SChris Down */
5933701557SChris Down if (*pos == 0)
6033701557SChris Down return SEQ_START_TOKEN;
6133701557SChris Down
6233701557SChris Down return pi_next(s, NULL, pos);
6333701557SChris Down }
6433701557SChris Down
6533701557SChris Down /*
6633701557SChris Down * We need both ESCAPE_ANY and explicit characters from ESCAPE_SPECIAL in @only
6733701557SChris Down * because otherwise ESCAPE_NAP will cause double quotes and backslashes to be
6833701557SChris Down * ignored for quoting.
6933701557SChris Down */
7033701557SChris Down #define seq_escape_printf_format(s, src) \
7133701557SChris Down seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
7233701557SChris Down
pi_show(struct seq_file * s,void * v)7333701557SChris Down static int pi_show(struct seq_file *s, void *v)
7433701557SChris Down {
7533701557SChris Down const struct pi_entry *entry = v;
7633701557SChris Down int level = LOGLEVEL_DEFAULT;
7733701557SChris Down enum printk_info_flags flags = 0;
7833701557SChris Down u16 prefix_len = 0;
7933701557SChris Down
8033701557SChris Down if (v == SEQ_START_TOKEN) {
8133701557SChris Down seq_puts(s, "# <level/flags> filename:line function \"format\"\n");
8233701557SChris Down return 0;
8333701557SChris Down }
8433701557SChris Down
8533701557SChris Down if (!entry->fmt)
8633701557SChris Down return 0;
8733701557SChris Down
8833701557SChris Down if (entry->level)
8933701557SChris Down printk_parse_prefix(entry->level, &level, &flags);
9033701557SChris Down else
9133701557SChris Down prefix_len = printk_parse_prefix(entry->fmt, &level, &flags);
9233701557SChris Down
9333701557SChris Down
9433701557SChris Down if (flags & LOG_CONT) {
9533701557SChris Down /*
9633701557SChris Down * LOGLEVEL_DEFAULT here means "use the same level as the
9733701557SChris Down * message we're continuing from", not the default message
9833701557SChris Down * loglevel, so don't display it as such.
9933701557SChris Down */
10033701557SChris Down if (level == LOGLEVEL_DEFAULT)
10133701557SChris Down seq_puts(s, "<c>");
10233701557SChris Down else
10333701557SChris Down seq_printf(s, "<%d,c>", level);
10433701557SChris Down } else
10533701557SChris Down seq_printf(s, "<%d>", level);
10633701557SChris Down
10733701557SChris Down seq_printf(s, " %s:%d %s \"", entry->file, entry->line, entry->func);
10833701557SChris Down if (entry->subsys_fmt_prefix)
10933701557SChris Down seq_escape_printf_format(s, entry->subsys_fmt_prefix);
11033701557SChris Down seq_escape_printf_format(s, entry->fmt + prefix_len);
11133701557SChris Down seq_puts(s, "\"\n");
11233701557SChris Down
11333701557SChris Down return 0;
11433701557SChris Down }
11533701557SChris Down
pi_stop(struct seq_file * p,void * v)11633701557SChris Down static void pi_stop(struct seq_file *p, void *v) { }
11733701557SChris Down
11833701557SChris Down static const struct seq_operations dfs_index_sops = {
11933701557SChris Down .start = pi_start,
12033701557SChris Down .next = pi_next,
12133701557SChris Down .show = pi_show,
12233701557SChris Down .stop = pi_stop,
12333701557SChris Down };
12433701557SChris Down
12533701557SChris Down DEFINE_SEQ_ATTRIBUTE(dfs_index);
12633701557SChris Down
12733701557SChris Down #ifdef CONFIG_MODULES
pi_get_module_name(struct module * mod)12833701557SChris Down static const char *pi_get_module_name(struct module *mod)
12933701557SChris Down {
13033701557SChris Down return mod ? mod->name : "vmlinux";
13133701557SChris Down }
13233701557SChris Down #else
pi_get_module_name(struct module * mod)13333701557SChris Down static const char *pi_get_module_name(struct module *mod)
13433701557SChris Down {
13533701557SChris Down return "vmlinux";
13633701557SChris Down }
13733701557SChris Down #endif
13833701557SChris Down
pi_create_file(struct module * mod)1390f0aa848SPetr Mladek static void pi_create_file(struct module *mod)
14033701557SChris Down {
14133701557SChris Down debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index,
14233701557SChris Down mod, &dfs_index_fops);
14333701557SChris Down }
14433701557SChris Down
145bc17bed5SYueHaibing #ifdef CONFIG_MODULES
pi_remove_file(struct module * mod)1460f0aa848SPetr Mladek static void pi_remove_file(struct module *mod)
14733701557SChris Down {
148*55bf243cSGreg Kroah-Hartman debugfs_lookup_and_remove(pi_get_module_name(mod), dfs_index);
14933701557SChris Down }
15033701557SChris Down
pi_module_notify(struct notifier_block * nb,unsigned long op,void * data)15133701557SChris Down static int pi_module_notify(struct notifier_block *nb, unsigned long op,
15233701557SChris Down void *data)
15333701557SChris Down {
15433701557SChris Down struct module *mod = data;
15533701557SChris Down
15633701557SChris Down switch (op) {
15733701557SChris Down case MODULE_STATE_COMING:
15833701557SChris Down pi_create_file(mod);
15933701557SChris Down break;
16033701557SChris Down case MODULE_STATE_GOING:
16133701557SChris Down pi_remove_file(mod);
16233701557SChris Down break;
16333701557SChris Down default: /* we don't care about other module states */
16433701557SChris Down break;
16533701557SChris Down }
16633701557SChris Down
16733701557SChris Down return NOTIFY_OK;
16833701557SChris Down }
16933701557SChris Down
17033701557SChris Down static struct notifier_block module_printk_fmts_nb = {
17133701557SChris Down .notifier_call = pi_module_notify,
17233701557SChris Down };
17333701557SChris Down
pi_setup_module_notifier(void)17433701557SChris Down static void __init pi_setup_module_notifier(void)
17533701557SChris Down {
17633701557SChris Down register_module_notifier(&module_printk_fmts_nb);
17733701557SChris Down }
17833701557SChris Down #else
pi_setup_module_notifier(void)17933701557SChris Down static inline void __init pi_setup_module_notifier(void) { }
18033701557SChris Down #endif
18133701557SChris Down
pi_init(void)18233701557SChris Down static int __init pi_init(void)
18333701557SChris Down {
18433701557SChris Down struct dentry *dfs_root = debugfs_create_dir("printk", NULL);
18533701557SChris Down
18633701557SChris Down dfs_index = debugfs_create_dir("index", dfs_root);
18733701557SChris Down pi_setup_module_notifier();
18833701557SChris Down pi_create_file(NULL);
18933701557SChris Down
19033701557SChris Down return 0;
19133701557SChris Down }
19233701557SChris Down
19333701557SChris Down /* debugfs comes up on core and must be initialised first */
19433701557SChris Down postcore_initcall(pi_init);
195