LCOV - code coverage report
Current view: top level - kernel/trace - trace_printk.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 8 87 9.2 %
Date: 2021-04-22 12:43:58 Functions: 2 12 16.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * trace binary printk
       4             :  *
       5             :  * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
       6             :  *
       7             :  */
       8             : #include <linux/seq_file.h>
       9             : #include <linux/security.h>
      10             : #include <linux/uaccess.h>
      11             : #include <linux/kernel.h>
      12             : #include <linux/ftrace.h>
      13             : #include <linux/string.h>
      14             : #include <linux/module.h>
      15             : #include <linux/mutex.h>
      16             : #include <linux/ctype.h>
      17             : #include <linux/list.h>
      18             : #include <linux/slab.h>
      19             : 
      20             : #include "trace.h"
      21             : 
      22             : #ifdef CONFIG_MODULES
      23             : 
      24             : /*
      25             :  * modules trace_printk()'s formats are autosaved in struct trace_bprintk_fmt
      26             :  * which are queued on trace_bprintk_fmt_list.
      27             :  */
      28             : static LIST_HEAD(trace_bprintk_fmt_list);
      29             : 
      30             : /* serialize accesses to trace_bprintk_fmt_list */
      31             : static DEFINE_MUTEX(btrace_mutex);
      32             : 
      33             : struct trace_bprintk_fmt {
      34             :         struct list_head list;
      35             :         const char *fmt;
      36             : };
      37             : 
      38             : static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
      39             : {
      40             :         struct trace_bprintk_fmt *pos;
      41             : 
      42             :         if (!fmt)
      43             :                 return ERR_PTR(-EINVAL);
      44             : 
      45             :         list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
      46             :                 if (!strcmp(pos->fmt, fmt))
      47             :                         return pos;
      48             :         }
      49             :         return NULL;
      50             : }
      51             : 
      52             : static
      53             : void hold_module_trace_bprintk_format(const char **start, const char **end)
      54             : {
      55             :         const char **iter;
      56             :         char *fmt;
      57             : 
      58             :         /* allocate the trace_printk per cpu buffers */
      59             :         if (start != end)
      60             :                 trace_printk_init_buffers();
      61             : 
      62             :         mutex_lock(&btrace_mutex);
      63             :         for (iter = start; iter < end; iter++) {
      64             :                 struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
      65             :                 if (tb_fmt) {
      66             :                         if (!IS_ERR(tb_fmt))
      67             :                                 *iter = tb_fmt->fmt;
      68             :                         continue;
      69             :                 }
      70             : 
      71             :                 fmt = NULL;
      72             :                 tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
      73             :                 if (tb_fmt) {
      74             :                         fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
      75             :                         if (fmt) {
      76             :                                 list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
      77             :                                 strcpy(fmt, *iter);
      78             :                                 tb_fmt->fmt = fmt;
      79             :                         } else
      80             :                                 kfree(tb_fmt);
      81             :                 }
      82             :                 *iter = fmt;
      83             : 
      84             :         }
      85             :         mutex_unlock(&btrace_mutex);
      86             : }
      87             : 
      88             : static int module_trace_bprintk_format_notify(struct notifier_block *self,
      89             :                 unsigned long val, void *data)
      90             : {
      91             :         struct module *mod = data;
      92             :         if (mod->num_trace_bprintk_fmt) {
      93             :                 const char **start = mod->trace_bprintk_fmt_start;
      94             :                 const char **end = start + mod->num_trace_bprintk_fmt;
      95             : 
      96             :                 if (val == MODULE_STATE_COMING)
      97             :                         hold_module_trace_bprintk_format(start, end);
      98             :         }
      99             :         return NOTIFY_OK;
     100             : }
     101             : 
     102             : /*
     103             :  * The debugfs/tracing/printk_formats file maps the addresses with
     104             :  * the ASCII formats that are used in the bprintk events in the
     105             :  * buffer. For userspace tools to be able to decode the events from
     106             :  * the buffer, they need to be able to map the address with the format.
     107             :  *
     108             :  * The addresses of the bprintk formats are in their own section
     109             :  * __trace_printk_fmt. But for modules we copy them into a link list.
     110             :  * The code to print the formats and their addresses passes around the
     111             :  * address of the fmt string. If the fmt address passed into the seq
     112             :  * functions is within the kernel core __trace_printk_fmt section, then
     113             :  * it simply uses the next pointer in the list.
     114             :  *
     115             :  * When the fmt pointer is outside the kernel core __trace_printk_fmt
     116             :  * section, then we need to read the link list pointers. The trick is
     117             :  * we pass the address of the string to the seq function just like
     118             :  * we do for the kernel core formats. To get back the structure that
     119             :  * holds the format, we simply use container_of() and then go to the
     120             :  * next format in the list.
     121             :  */
     122             : static const char **
     123             : find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
     124             : {
     125             :         struct trace_bprintk_fmt *mod_fmt;
     126             : 
     127             :         if (list_empty(&trace_bprintk_fmt_list))
     128             :                 return NULL;
     129             : 
     130             :         /*
     131             :          * v will point to the address of the fmt record from t_next
     132             :          * v will be NULL from t_start.
     133             :          * If this is the first pointer or called from start
     134             :          * then we need to walk the list.
     135             :          */
     136             :         if (!v || start_index == *pos) {
     137             :                 struct trace_bprintk_fmt *p;
     138             : 
     139             :                 /* search the module list */
     140             :                 list_for_each_entry(p, &trace_bprintk_fmt_list, list) {
     141             :                         if (start_index == *pos)
     142             :                                 return &p->fmt;
     143             :                         start_index++;
     144             :                 }
     145             :                 /* pos > index */
     146             :                 return NULL;
     147             :         }
     148             : 
     149             :         /*
     150             :          * v points to the address of the fmt field in the mod list
     151             :          * structure that holds the module print format.
     152             :          */
     153             :         mod_fmt = container_of(v, typeof(*mod_fmt), fmt);
     154             :         if (mod_fmt->list.next == &trace_bprintk_fmt_list)
     155             :                 return NULL;
     156             : 
     157             :         mod_fmt = container_of(mod_fmt->list.next, typeof(*mod_fmt), list);
     158             : 
     159             :         return &mod_fmt->fmt;
     160             : }
     161             : 
     162             : static void format_mod_start(void)
     163             : {
     164             :         mutex_lock(&btrace_mutex);
     165             : }
     166             : 
     167             : static void format_mod_stop(void)
     168             : {
     169             :         mutex_unlock(&btrace_mutex);
     170             : }
     171             : 
     172             : #else /* !CONFIG_MODULES */
     173             : __init static int
     174             : module_trace_bprintk_format_notify(struct notifier_block *self,
     175             :                 unsigned long val, void *data)
     176             : {
     177             :         return NOTIFY_OK;
     178             : }
     179             : static inline const char **
     180             : find_next_mod_format(int start_index, void *v, const char **fmt, loff_t *pos)
     181             : {
     182             :         return NULL;
     183             : }
     184           0 : static inline void format_mod_start(void) { }
     185           0 : static inline void format_mod_stop(void) { }
     186             : #endif /* CONFIG_MODULES */
     187             : 
     188             : static bool __read_mostly trace_printk_enabled = true;
     189             : 
     190           0 : void trace_printk_control(bool enabled)
     191             : {
     192           0 :         trace_printk_enabled = enabled;
     193           0 : }
     194             : 
     195             : __initdata_or_module static
     196             : struct notifier_block module_trace_bprintk_format_nb = {
     197             :         .notifier_call = module_trace_bprintk_format_notify,
     198             : };
     199             : 
     200           0 : int __trace_bprintk(unsigned long ip, const char *fmt, ...)
     201             : {
     202           0 :         int ret;
     203           0 :         va_list ap;
     204             : 
     205           0 :         if (unlikely(!fmt))
     206             :                 return 0;
     207             : 
     208           0 :         if (!trace_printk_enabled)
     209             :                 return 0;
     210             : 
     211           0 :         va_start(ap, fmt);
     212           0 :         ret = trace_vbprintk(ip, fmt, ap);
     213           0 :         va_end(ap);
     214           0 :         return ret;
     215             : }
     216             : EXPORT_SYMBOL_GPL(__trace_bprintk);
     217             : 
     218           0 : int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
     219             : {
     220           0 :         if (unlikely(!fmt))
     221             :                 return 0;
     222             : 
     223           0 :         if (!trace_printk_enabled)
     224             :                 return 0;
     225             : 
     226           0 :         return trace_vbprintk(ip, fmt, ap);
     227             : }
     228             : EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
     229             : 
     230           0 : int __trace_printk(unsigned long ip, const char *fmt, ...)
     231             : {
     232           0 :         int ret;
     233           0 :         va_list ap;
     234             : 
     235           0 :         if (!trace_printk_enabled)
     236             :                 return 0;
     237             : 
     238           0 :         va_start(ap, fmt);
     239           0 :         ret = trace_vprintk(ip, fmt, ap);
     240           0 :         va_end(ap);
     241           0 :         return ret;
     242             : }
     243             : EXPORT_SYMBOL_GPL(__trace_printk);
     244             : 
     245           0 : int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
     246             : {
     247           0 :         if (!trace_printk_enabled)
     248             :                 return 0;
     249             : 
     250           0 :         return trace_vprintk(ip, fmt, ap);
     251             : }
     252             : EXPORT_SYMBOL_GPL(__ftrace_vprintk);
     253             : 
     254           0 : static const char **find_next(void *v, loff_t *pos)
     255             : {
     256           0 :         const char **fmt = v;
     257           0 :         int start_index;
     258           0 :         int last_index;
     259             : 
     260           0 :         start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
     261             : 
     262           0 :         if (*pos < start_index)
     263           0 :                 return __start___trace_bprintk_fmt + *pos;
     264             : 
     265             :         /*
     266             :          * The __tracepoint_str section is treated the same as the
     267             :          * __trace_printk_fmt section. The difference is that the
     268             :          * __trace_printk_fmt section should only be used by trace_printk()
     269             :          * in a debugging environment, as if anything exists in that section
     270             :          * the trace_prink() helper buffers are allocated, which would just
     271             :          * waste space in a production environment.
     272             :          *
     273             :          * The __tracepoint_str sections on the other hand are used by
     274             :          * tracepoints which need to map pointers to their strings to
     275             :          * the ASCII text for userspace.
     276             :          */
     277           0 :         last_index = start_index;
     278           0 :         start_index = __stop___tracepoint_str - __start___tracepoint_str;
     279             : 
     280           0 :         if (*pos < last_index + start_index)
     281           0 :                 return __start___tracepoint_str + (*pos - last_index);
     282             : 
     283             :         start_index += last_index;
     284           0 :         return find_next_mod_format(start_index, v, fmt, pos);
     285             : }
     286             : 
     287             : static void *
     288           0 : t_start(struct seq_file *m, loff_t *pos)
     289             : {
     290           0 :         format_mod_start();
     291           0 :         return find_next(NULL, pos);
     292             : }
     293             : 
     294           0 : static void *t_next(struct seq_file *m, void * v, loff_t *pos)
     295             : {
     296           0 :         (*pos)++;
     297           0 :         return find_next(v, pos);
     298             : }
     299             : 
     300           0 : static int t_show(struct seq_file *m, void *v)
     301             : {
     302           0 :         const char **fmt = v;
     303           0 :         const char *str = *fmt;
     304           0 :         int i;
     305             : 
     306           0 :         if (!*fmt)
     307             :                 return 0;
     308             : 
     309           0 :         seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
     310             : 
     311             :         /*
     312             :          * Tabs and new lines need to be converted.
     313             :          */
     314           0 :         for (i = 0; str[i]; i++) {
     315           0 :                 switch (str[i]) {
     316           0 :                 case '\n':
     317           0 :                         seq_puts(m, "\\n");
     318           0 :                         break;
     319           0 :                 case '\t':
     320           0 :                         seq_puts(m, "\\t");
     321           0 :                         break;
     322           0 :                 case '\\':
     323           0 :                         seq_putc(m, '\\');
     324           0 :                         break;
     325           0 :                 case '"':
     326           0 :                         seq_puts(m, "\\\"");
     327           0 :                         break;
     328           0 :                 default:
     329           0 :                         seq_putc(m, str[i]);
     330             :                 }
     331             :         }
     332           0 :         seq_puts(m, "\"\n");
     333             : 
     334           0 :         return 0;
     335             : }
     336             : 
     337           0 : static void t_stop(struct seq_file *m, void *p)
     338             : {
     339           0 :         format_mod_stop();
     340           0 : }
     341             : 
     342             : static const struct seq_operations show_format_seq_ops = {
     343             :         .start = t_start,
     344             :         .next = t_next,
     345             :         .show = t_show,
     346             :         .stop = t_stop,
     347             : };
     348             : 
     349             : static int
     350           0 : ftrace_formats_open(struct inode *inode, struct file *file)
     351             : {
     352           0 :         int ret;
     353             : 
     354           0 :         ret = security_locked_down(LOCKDOWN_TRACEFS);
     355           0 :         if (ret)
     356             :                 return ret;
     357             : 
     358           0 :         return seq_open(file, &show_format_seq_ops);
     359             : }
     360             : 
     361             : static const struct file_operations ftrace_formats_fops = {
     362             :         .open = ftrace_formats_open,
     363             :         .read = seq_read,
     364             :         .llseek = seq_lseek,
     365             :         .release = seq_release,
     366             : };
     367             : 
     368           1 : static __init int init_trace_printk_function_export(void)
     369             : {
     370           1 :         int ret;
     371             : 
     372           1 :         ret = tracing_init_dentry();
     373           1 :         if (ret)
     374             :                 return 0;
     375             : 
     376           1 :         trace_create_file("printk_formats", 0444, NULL,
     377             :                                     NULL, &ftrace_formats_fops);
     378             : 
     379           1 :         return 0;
     380             : }
     381             : 
     382             : fs_initcall(init_trace_printk_function_export);
     383             : 
     384           1 : static __init int init_trace_printk(void)
     385             : {
     386           1 :         return register_module_notifier(&module_trace_bprintk_format_nb);
     387             : }
     388             : 
     389             : early_initcall(init_trace_printk);

Generated by: LCOV version 1.14