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