LCOV - code coverage report
Current view: top level - kernel/trace - trace_printk.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 12 115 10.4 %
Date: 2022-04-01 14:58:12 Functions: 3 15 20.0 %
Branches: 2 49 4.1 %

           Branch data     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                 :          0 : static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
      39                 :            : {
      40                 :          0 :         struct trace_bprintk_fmt *pos;
      41                 :            : 
      42         [ #  # ]:          0 :         if (!fmt)
      43                 :            :                 return ERR_PTR(-EINVAL);
      44                 :            : 
      45         [ #  # ]:          0 :         list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
      46         [ #  # ]:          0 :                 if (!strcmp(pos->fmt, fmt))
      47                 :          0 :                         return pos;
      48                 :            :         }
      49                 :            :         return NULL;
      50                 :            : }
      51                 :            : 
      52                 :            : static
      53                 :          0 : void hold_module_trace_bprintk_format(const char **start, const char **end)
      54                 :            : {
      55                 :          0 :         const char **iter;
      56                 :          0 :         char *fmt;
      57                 :            : 
      58                 :            :         /* allocate the trace_printk per cpu buffers */
      59         [ #  # ]:          0 :         if (start != end)
      60                 :          0 :                 trace_printk_init_buffers();
      61                 :            : 
      62                 :          0 :         mutex_lock(&btrace_mutex);
      63         [ #  # ]:          0 :         for (iter = start; iter < end; iter++) {
      64                 :          0 :                 struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
      65         [ #  # ]:          0 :                 if (tb_fmt) {
      66         [ #  # ]:          0 :                         if (!IS_ERR(tb_fmt))
      67                 :          0 :                                 *iter = tb_fmt->fmt;
      68                 :          0 :                         continue;
      69                 :            :                 }
      70                 :            : 
      71                 :          0 :                 fmt = NULL;
      72                 :          0 :                 tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
      73         [ #  # ]:          0 :                 if (tb_fmt) {
      74         [ #  # ]:          0 :                         fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
      75         [ #  # ]:          0 :                         if (fmt) {
      76                 :          0 :                                 list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
      77                 :          0 :                                 strcpy(fmt, *iter);
      78                 :          0 :                                 tb_fmt->fmt = fmt;
      79                 :            :                         } else
      80                 :          0 :                                 kfree(tb_fmt);
      81                 :            :                 }
      82                 :          0 :                 *iter = fmt;
      83                 :            : 
      84                 :            :         }
      85                 :          0 :         mutex_unlock(&btrace_mutex);
      86                 :          0 : }
      87                 :            : 
      88                 :         18 : static int module_trace_bprintk_format_notify(struct notifier_block *self,
      89                 :            :                 unsigned long val, void *data)
      90                 :            : {
      91                 :         18 :         struct module *mod = data;
      92         [ -  + ]:         18 :         if (mod->num_trace_bprintk_fmt) {
      93                 :          0 :                 const char **start = mod->trace_bprintk_fmt_start;
      94                 :          0 :                 const char **end = start + mod->num_trace_bprintk_fmt;
      95                 :            : 
      96         [ #  # ]:          0 :                 if (val == MODULE_STATE_COMING)
      97                 :          0 :                         hold_module_trace_bprintk_format(start, end);
      98                 :            :         }
      99                 :         18 :         return 0;
     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                 :          0 : static void format_mod_start(void)
     163                 :            : {
     164                 :          0 :         mutex_lock(&btrace_mutex);
     165                 :            : }
     166                 :            : 
     167                 :          0 : static void format_mod_stop(void)
     168                 :            : {
     169                 :          0 :         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 0;
     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                 :            : static inline void format_mod_start(void) { }
     185                 :            : 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                 :            : static const char **find_next(void *v, loff_t *pos)
     255                 :            : {
     256                 :            :         const char **fmt = v;
     257                 :            :         int start_index;
     258                 :            :         int last_index;
     259                 :            : 
     260                 :            :         start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
     261                 :            : 
     262                 :            :         if (*pos < start_index)
     263                 :            :                 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                 :            :         last_index = start_index;
     278                 :            :         start_index = __stop___tracepoint_str - __start___tracepoint_str;
     279                 :            : 
     280                 :            :         if (*pos < last_index + start_index)
     281                 :            :                 return __start___tracepoint_str + (*pos - last_index);
     282                 :            : 
     283                 :            :         start_index += last_index;
     284                 :            :         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                 :          3 : static __init int init_trace_printk_function_export(void)
     369                 :            : {
     370                 :          3 :         struct dentry *d_tracer;
     371                 :            : 
     372                 :          3 :         d_tracer = tracing_init_dentry();
     373         [ +  - ]:          3 :         if (IS_ERR(d_tracer))
     374                 :            :                 return 0;
     375                 :            : 
     376                 :          3 :         trace_create_file("printk_formats", 0444, d_tracer,
     377                 :            :                                     NULL, &ftrace_formats_fops);
     378                 :            : 
     379                 :          3 :         return 0;
     380                 :            : }
     381                 :            : 
     382                 :            : fs_initcall(init_trace_printk_function_export);
     383                 :            : 
     384                 :          3 : static __init int init_trace_printk(void)
     385                 :            : {
     386                 :          3 :         return register_module_notifier(&module_trace_bprintk_format_nb);
     387                 :            : }
     388                 :            : 
     389                 :            : early_initcall(init_trace_printk);

Generated by: LCOV version 1.14