cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

index.c (4405B)


      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
     14extern struct pi_entry *__start_printk_index[];
     15extern struct pi_entry *__stop_printk_index[];
     16
     17/* The base dir for module formats, typically debugfs/printk/index/ */
     18static struct dentry *dfs_index;
     19
     20static 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
     43static 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
     53static 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
     73static 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
    116static void pi_stop(struct seq_file *p, void *v) { }
    117
    118static 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
    125DEFINE_SEQ_ATTRIBUTE(dfs_index);
    126
    127#ifdef CONFIG_MODULES
    128static const char *pi_get_module_name(struct module *mod)
    129{
    130	return mod ? mod->name : "vmlinux";
    131}
    132#else
    133static const char *pi_get_module_name(struct module *mod)
    134{
    135	return "vmlinux";
    136}
    137#endif
    138
    139static 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
    146static void pi_remove_file(struct module *mod)
    147{
    148	debugfs_remove(debugfs_lookup(pi_get_module_name(mod), dfs_index));
    149}
    150
    151static 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
    170static struct notifier_block module_printk_fmts_nb = {
    171	.notifier_call = pi_module_notify,
    172};
    173
    174static void __init pi_setup_module_notifier(void)
    175{
    176	register_module_notifier(&module_printk_fmts_nb);
    177}
    178#else
    179static inline void __init pi_setup_module_notifier(void) { }
    180#endif
    181
    182static 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 */
    194postcore_initcall(pi_init);