Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Userspace indexing of printk formats
0004  */
0005 
0006 #include <linux/debugfs.h>
0007 #include <linux/module.h>
0008 #include <linux/printk.h>
0009 #include <linux/slab.h>
0010 #include <linux/string_helpers.h>
0011 
0012 #include "internal.h"
0013 
0014 extern struct pi_entry *__start_printk_index[];
0015 extern struct pi_entry *__stop_printk_index[];
0016 
0017 /* The base dir for module formats, typically debugfs/printk/index/ */
0018 static struct dentry *dfs_index;
0019 
0020 static struct pi_entry *pi_get_entry(const struct module *mod, loff_t pos)
0021 {
0022     struct pi_entry **entries;
0023     unsigned int nr_entries;
0024 
0025 #ifdef CONFIG_MODULES
0026     if (mod) {
0027         entries = mod->printk_index_start;
0028         nr_entries = mod->printk_index_size;
0029     } else
0030 #endif
0031     {
0032         /* vmlinux, comes from linker symbols */
0033         entries = __start_printk_index;
0034         nr_entries = __stop_printk_index - __start_printk_index;
0035     }
0036 
0037     if (pos >= nr_entries)
0038         return NULL;
0039 
0040     return entries[pos];
0041 }
0042 
0043 static void *pi_next(struct seq_file *s, void *v, loff_t *pos)
0044 {
0045     const struct module *mod = s->file->f_inode->i_private;
0046     struct pi_entry *entry = pi_get_entry(mod, *pos);
0047 
0048     (*pos)++;
0049 
0050     return entry;
0051 }
0052 
0053 static void *pi_start(struct seq_file *s, loff_t *pos)
0054 {
0055     /*
0056      * Make show() print the header line. Do not update *pos because
0057      * pi_next() still has to return the entry at index 0 later.
0058      */
0059     if (*pos == 0)
0060         return SEQ_START_TOKEN;
0061 
0062     return pi_next(s, NULL, pos);
0063 }
0064 
0065 /*
0066  * We need both ESCAPE_ANY and explicit characters from ESCAPE_SPECIAL in @only
0067  * because otherwise ESCAPE_NAP will cause double quotes and backslashes to be
0068  * ignored for quoting.
0069  */
0070 #define seq_escape_printf_format(s, src) \
0071     seq_escape_str(s, src, ESCAPE_ANY | ESCAPE_NAP | ESCAPE_APPEND, "\"\\")
0072 
0073 static int pi_show(struct seq_file *s, void *v)
0074 {
0075     const struct pi_entry *entry = v;
0076     int level = LOGLEVEL_DEFAULT;
0077     enum printk_info_flags flags = 0;
0078     u16 prefix_len = 0;
0079 
0080     if (v == SEQ_START_TOKEN) {
0081         seq_puts(s, "# <level/flags> filename:line function \"format\"\n");
0082         return 0;
0083     }
0084 
0085     if (!entry->fmt)
0086         return 0;
0087 
0088     if (entry->level)
0089         printk_parse_prefix(entry->level, &level, &flags);
0090     else
0091         prefix_len = printk_parse_prefix(entry->fmt, &level, &flags);
0092 
0093 
0094     if (flags & LOG_CONT) {
0095         /*
0096          * LOGLEVEL_DEFAULT here means "use the same level as the
0097          * message we're continuing from", not the default message
0098          * loglevel, so don't display it as such.
0099          */
0100         if (level == LOGLEVEL_DEFAULT)
0101             seq_puts(s, "<c>");
0102         else
0103             seq_printf(s, "<%d,c>", level);
0104     } else
0105         seq_printf(s, "<%d>", level);
0106 
0107     seq_printf(s, " %s:%d %s \"", entry->file, entry->line, entry->func);
0108     if (entry->subsys_fmt_prefix)
0109         seq_escape_printf_format(s, entry->subsys_fmt_prefix);
0110     seq_escape_printf_format(s, entry->fmt + prefix_len);
0111     seq_puts(s, "\"\n");
0112 
0113     return 0;
0114 }
0115 
0116 static void pi_stop(struct seq_file *p, void *v) { }
0117 
0118 static const struct seq_operations dfs_index_sops = {
0119     .start = pi_start,
0120     .next  = pi_next,
0121     .show  = pi_show,
0122     .stop  = pi_stop,
0123 };
0124 
0125 DEFINE_SEQ_ATTRIBUTE(dfs_index);
0126 
0127 #ifdef CONFIG_MODULES
0128 static const char *pi_get_module_name(struct module *mod)
0129 {
0130     return mod ? mod->name : "vmlinux";
0131 }
0132 #else
0133 static const char *pi_get_module_name(struct module *mod)
0134 {
0135     return "vmlinux";
0136 }
0137 #endif
0138 
0139 static void pi_create_file(struct module *mod)
0140 {
0141     debugfs_create_file(pi_get_module_name(mod), 0444, dfs_index,
0142                        mod, &dfs_index_fops);
0143 }
0144 
0145 #ifdef CONFIG_MODULES
0146 static void pi_remove_file(struct module *mod)
0147 {
0148     debugfs_remove(debugfs_lookup(pi_get_module_name(mod), dfs_index));
0149 }
0150 
0151 static int pi_module_notify(struct notifier_block *nb, unsigned long op,
0152                 void *data)
0153 {
0154     struct module *mod = data;
0155 
0156     switch (op) {
0157     case MODULE_STATE_COMING:
0158         pi_create_file(mod);
0159         break;
0160     case MODULE_STATE_GOING:
0161         pi_remove_file(mod);
0162         break;
0163     default: /* we don't care about other module states */
0164         break;
0165     }
0166 
0167     return NOTIFY_OK;
0168 }
0169 
0170 static struct notifier_block module_printk_fmts_nb = {
0171     .notifier_call = pi_module_notify,
0172 };
0173 
0174 static void __init pi_setup_module_notifier(void)
0175 {
0176     register_module_notifier(&module_printk_fmts_nb);
0177 }
0178 #else
0179 static inline void __init pi_setup_module_notifier(void) { }
0180 #endif
0181 
0182 static int __init pi_init(void)
0183 {
0184     struct dentry *dfs_root = debugfs_create_dir("printk", NULL);
0185 
0186     dfs_index = debugfs_create_dir("index", dfs_root);
0187     pi_setup_module_notifier();
0188     pi_create_file(NULL);
0189 
0190     return 0;
0191 }
0192 
0193 /* debugfs comes up on core and must be initialised first */
0194 postcore_initcall(pi_init);