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
;
32 /* vmlinux, comes from linker symbols */
33 entries
= __start_printk_index
;
34 nr_entries
= __stop_printk_index
- __start_printk_index
;
37 if (pos
>= nr_entries
)
43 static void *pi_next(struct seq_file
*s
, void *v
, loff_t
*pos
)
45 const struct module
*mod
= s
->file
->f_inode
->i_private
;
46 struct pi_entry
*entry
= pi_get_entry(mod
, *pos
);
53 static void *pi_start(struct seq_file
*s
, loff_t
*pos
)
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.
60 return SEQ_START_TOKEN
;
62 return pi_next(s
, NULL
, pos
);
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.
70 #define seq_escape_printf_format(s, src) \
71 seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
73 static int pi_show(struct seq_file
*s
, void *v
)
75 const struct pi_entry
*entry
= v
;
76 int level
= LOGLEVEL_DEFAULT
;
77 enum printk_info_flags flags
= 0;
80 if (v
== SEQ_START_TOKEN
) {
81 seq_puts(s
, "# <level/flags> filename:line function \"format\"\n");
89 printk_parse_prefix(entry
->level
, &level
, &flags
);
91 prefix_len
= printk_parse_prefix(entry
->fmt
, &level
, &flags
);
94 if (flags
& LOG_CONT
) {
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.
100 if (level
== LOGLEVEL_DEFAULT
)
103 seq_printf(s
, "<%d,c>", level
);
105 seq_printf(s
, "<%d>", level
);
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
);
116 static void pi_stop(struct seq_file
*p
, void *v
) { }
118 static const struct seq_operations dfs_index_sops
= {
125 DEFINE_SEQ_ATTRIBUTE(dfs_index
);
127 #ifdef CONFIG_MODULES
128 static const char *pi_get_module_name(struct module
*mod
)
130 return mod
? mod
->name
: "vmlinux";
133 static const char *pi_get_module_name(struct module
*mod
)
139 static void pi_create_file(struct module
*mod
)
141 debugfs_create_file(pi_get_module_name(mod
), 0444, dfs_index
,
142 mod
, &dfs_index_fops
);
145 #ifdef CONFIG_MODULES
146 static void pi_remove_file(struct module
*mod
)
148 debugfs_lookup_and_remove(pi_get_module_name(mod
), dfs_index
);
151 static int pi_module_notify(struct notifier_block
*nb
, unsigned long op
,
154 struct module
*mod
= data
;
157 case MODULE_STATE_COMING
:
160 case MODULE_STATE_GOING
:
163 default: /* we don't care about other module states */
170 static struct notifier_block module_printk_fmts_nb
= {
171 .notifier_call
= pi_module_notify
,
174 static void __init
pi_setup_module_notifier(void)
176 register_module_notifier(&module_printk_fmts_nb
);
179 static inline void __init
pi_setup_module_notifier(void) { }
182 static int __init
pi_init(void)
184 struct dentry
*dfs_root
= debugfs_create_dir("printk", NULL
);
186 dfs_index
= debugfs_create_dir("index", dfs_root
);
187 pi_setup_module_notifier();
188 pi_create_file(NULL
);
193 /* debugfs comes up on core and must be initialised first */
194 postcore_initcall(pi_init
);