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