xref: /openbmc/linux/kernel/printk/index.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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