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 14 extern struct pi_entry *__start_printk_index[]; 15 extern struct pi_entry *__stop_printk_index[]; 16 17 /* The base dir for module formats, typically debugfs/printk/index/ */ 18 static struct dentry *dfs_index; 19 20 static 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 } 30 #endif 31 32 if (!mod) { 33 /* vmlinux, comes from linker symbols */ 34 entries = __start_printk_index; 35 nr_entries = __stop_printk_index - __start_printk_index; 36 } 37 38 if (pos >= nr_entries) 39 return NULL; 40 41 return entries[pos]; 42 } 43 44 static void *pi_next(struct seq_file *s, void *v, loff_t *pos) 45 { 46 const struct module *mod = s->file->f_inode->i_private; 47 struct pi_entry *entry = pi_get_entry(mod, *pos); 48 49 (*pos)++; 50 51 return entry; 52 } 53 54 static void *pi_start(struct seq_file *s, loff_t *pos) 55 { 56 /* 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. 59 */ 60 if (*pos == 0) 61 return SEQ_START_TOKEN; 62 63 return pi_next(s, NULL, pos); 64 } 65 66 /* 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. 70 */ 71 #define seq_escape_printf_format(s, src) \ 72 seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\") 73 74 static int pi_show(struct seq_file *s, void *v) 75 { 76 const struct pi_entry *entry = v; 77 int level = LOGLEVEL_DEFAULT; 78 enum printk_info_flags flags = 0; 79 u16 prefix_len = 0; 80 81 if (v == SEQ_START_TOKEN) { 82 seq_puts(s, "# <level/flags> filename:line function \"format\"\n"); 83 return 0; 84 } 85 86 if (!entry->fmt) 87 return 0; 88 89 if (entry->level) 90 printk_parse_prefix(entry->level, &level, &flags); 91 else 92 prefix_len = printk_parse_prefix(entry->fmt, &level, &flags); 93 94 95 if (flags & LOG_CONT) { 96 /* 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. 100 */ 101 if (level == LOGLEVEL_DEFAULT) 102 seq_puts(s, "<c>"); 103 else 104 seq_printf(s, "<%d,c>", level); 105 } else 106 seq_printf(s, "<%d>", level); 107 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); 112 seq_puts(s, "\"\n"); 113 114 return 0; 115 } 116 117 static void pi_stop(struct seq_file *p, void *v) { } 118 119 static const struct seq_operations dfs_index_sops = { 120 .start = pi_start, 121 .next = pi_next, 122 .show = pi_show, 123 .stop = pi_stop, 124 }; 125 126 DEFINE_SEQ_ATTRIBUTE(dfs_index); 127 128 #ifdef CONFIG_MODULES 129 static const char *pi_get_module_name(struct module *mod) 130 { 131 return mod ? mod->name : "vmlinux"; 132 } 133 #else 134 static const char *pi_get_module_name(struct module *mod) 135 { 136 return "vmlinux"; 137 } 138 #endif 139 140 static void pi_create_file(struct module *mod) 141 { 142 debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index, 143 mod, &dfs_index_fops); 144 } 145 146 #ifdef CONFIG_MODULES 147 static void pi_remove_file(struct module *mod) 148 { 149 debugfs_remove(debugfs_lookup(pi_get_module_name(mod), dfs_index)); 150 } 151 152 static int pi_module_notify(struct notifier_block *nb, unsigned long op, 153 void *data) 154 { 155 struct module *mod = data; 156 157 switch (op) { 158 case MODULE_STATE_COMING: 159 pi_create_file(mod); 160 break; 161 case MODULE_STATE_GOING: 162 pi_remove_file(mod); 163 break; 164 default: /* we don't care about other module states */ 165 break; 166 } 167 168 return NOTIFY_OK; 169 } 170 171 static struct notifier_block module_printk_fmts_nb = { 172 .notifier_call = pi_module_notify, 173 }; 174 175 static void __init pi_setup_module_notifier(void) 176 { 177 register_module_notifier(&module_printk_fmts_nb); 178 } 179 #else 180 static inline void __init pi_setup_module_notifier(void) { } 181 #endif 182 183 static int __init pi_init(void) 184 { 185 struct dentry *dfs_root = debugfs_create_dir("printk", NULL); 186 187 dfs_index = debugfs_create_dir("index", dfs_root); 188 pi_setup_module_notifier(); 189 pi_create_file(NULL); 190 191 return 0; 192 } 193 194 /* debugfs comes up on core and must be initialised first */ 195 postcore_initcall(pi_init); 196