linux/kernel/trace/trace_boot.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * trace_boot.c
   4 * Tracing kernel boot-time
   5 */
   6
   7#define pr_fmt(fmt)     "trace_boot: " fmt
   8
   9#include <linux/bootconfig.h>
  10#include <linux/cpumask.h>
  11#include <linux/ftrace.h>
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/mutex.h>
  15#include <linux/string.h>
  16#include <linux/slab.h>
  17#include <linux/trace.h>
  18#include <linux/trace_events.h>
  19
  20#include "trace.h"
  21
  22#define MAX_BUF_LEN 256
  23
  24static void __init
  25trace_boot_set_instance_options(struct trace_array *tr, struct xbc_node *node)
  26{
  27        struct xbc_node *anode;
  28        const char *p;
  29        char buf[MAX_BUF_LEN];
  30        unsigned long v = 0;
  31
  32        /* Common ftrace options */
  33        xbc_node_for_each_array_value(node, "options", anode, p) {
  34                if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) {
  35                        pr_err("String is too long: %s\n", p);
  36                        continue;
  37                }
  38
  39                if (trace_set_options(tr, buf) < 0)
  40                        pr_err("Failed to set option: %s\n", buf);
  41        }
  42
  43        p = xbc_node_find_value(node, "trace_clock", NULL);
  44        if (p && *p != '\0') {
  45                if (tracing_set_clock(tr, p) < 0)
  46                        pr_err("Failed to set trace clock: %s\n", p);
  47        }
  48
  49        p = xbc_node_find_value(node, "buffer_size", NULL);
  50        if (p && *p != '\0') {
  51                v = memparse(p, NULL);
  52                if (v < PAGE_SIZE)
  53                        pr_err("Buffer size is too small: %s\n", p);
  54                if (tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
  55                        pr_err("Failed to resize trace buffer to %s\n", p);
  56        }
  57
  58        p = xbc_node_find_value(node, "cpumask", NULL);
  59        if (p && *p != '\0') {
  60                cpumask_var_t new_mask;
  61
  62                if (alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
  63                        if (cpumask_parse(p, new_mask) < 0 ||
  64                            tracing_set_cpumask(tr, new_mask) < 0)
  65                                pr_err("Failed to set new CPU mask %s\n", p);
  66                        free_cpumask_var(new_mask);
  67                }
  68        }
  69}
  70
  71#ifdef CONFIG_EVENT_TRACING
  72static void __init
  73trace_boot_enable_events(struct trace_array *tr, struct xbc_node *node)
  74{
  75        struct xbc_node *anode;
  76        char buf[MAX_BUF_LEN];
  77        const char *p;
  78
  79        xbc_node_for_each_array_value(node, "events", anode, p) {
  80                if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) {
  81                        pr_err("String is too long: %s\n", p);
  82                        continue;
  83                }
  84
  85                if (ftrace_set_clr_event(tr, buf, 1) < 0)
  86                        pr_err("Failed to enable event: %s\n", p);
  87        }
  88}
  89
  90#ifdef CONFIG_KPROBE_EVENTS
  91static int __init
  92trace_boot_add_kprobe_event(struct xbc_node *node, const char *event)
  93{
  94        struct dynevent_cmd cmd;
  95        struct xbc_node *anode;
  96        char buf[MAX_BUF_LEN];
  97        const char *val;
  98        int ret = 0;
  99
 100        xbc_node_for_each_array_value(node, "probes", anode, val) {
 101                kprobe_event_cmd_init(&cmd, buf, MAX_BUF_LEN);
 102
 103                ret = kprobe_event_gen_cmd_start(&cmd, event, val);
 104                if (ret) {
 105                        pr_err("Failed to generate probe: %s\n", buf);
 106                        break;
 107                }
 108
 109                ret = kprobe_event_gen_cmd_end(&cmd);
 110                if (ret) {
 111                        pr_err("Failed to add probe: %s\n", buf);
 112                        break;
 113                }
 114        }
 115
 116        return ret;
 117}
 118#else
 119static inline int __init
 120trace_boot_add_kprobe_event(struct xbc_node *node, const char *event)
 121{
 122        pr_err("Kprobe event is not supported.\n");
 123        return -ENOTSUPP;
 124}
 125#endif
 126
 127#ifdef CONFIG_SYNTH_EVENTS
 128static int __init
 129trace_boot_add_synth_event(struct xbc_node *node, const char *event)
 130{
 131        struct dynevent_cmd cmd;
 132        struct xbc_node *anode;
 133        char buf[MAX_BUF_LEN];
 134        const char *p;
 135        int ret;
 136
 137        synth_event_cmd_init(&cmd, buf, MAX_BUF_LEN);
 138
 139        ret = synth_event_gen_cmd_start(&cmd, event, NULL);
 140        if (ret)
 141                return ret;
 142
 143        xbc_node_for_each_array_value(node, "fields", anode, p) {
 144                ret = synth_event_add_field_str(&cmd, p);
 145                if (ret)
 146                        return ret;
 147        }
 148
 149        ret = synth_event_gen_cmd_end(&cmd);
 150        if (ret < 0)
 151                pr_err("Failed to add synthetic event: %s\n", buf);
 152
 153        return ret;
 154}
 155#else
 156static inline int __init
 157trace_boot_add_synth_event(struct xbc_node *node, const char *event)
 158{
 159        pr_err("Synthetic event is not supported.\n");
 160        return -ENOTSUPP;
 161}
 162#endif
 163
 164static void __init
 165trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode,
 166                          struct xbc_node *enode)
 167{
 168        struct trace_event_file *file;
 169        struct xbc_node *anode;
 170        char buf[MAX_BUF_LEN];
 171        const char *p, *group, *event;
 172
 173        group = xbc_node_get_data(gnode);
 174        event = xbc_node_get_data(enode);
 175
 176        if (!strcmp(group, "kprobes"))
 177                if (trace_boot_add_kprobe_event(enode, event) < 0)
 178                        return;
 179        if (!strcmp(group, "synthetic"))
 180                if (trace_boot_add_synth_event(enode, event) < 0)
 181                        return;
 182
 183        mutex_lock(&event_mutex);
 184        file = find_event_file(tr, group, event);
 185        if (!file) {
 186                pr_err("Failed to find event: %s:%s\n", group, event);
 187                goto out;
 188        }
 189
 190        p = xbc_node_find_value(enode, "filter", NULL);
 191        if (p && *p != '\0') {
 192                if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf))
 193                        pr_err("filter string is too long: %s\n", p);
 194                else if (apply_event_filter(file, buf) < 0)
 195                        pr_err("Failed to apply filter: %s\n", buf);
 196        }
 197
 198        xbc_node_for_each_array_value(enode, "actions", anode, p) {
 199                if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf))
 200                        pr_err("action string is too long: %s\n", p);
 201                else if (trigger_process_regex(file, buf) < 0)
 202                        pr_err("Failed to apply an action: %s\n", buf);
 203        }
 204
 205        if (xbc_node_find_value(enode, "enable", NULL)) {
 206                if (trace_event_enable_disable(file, 1, 0) < 0)
 207                        pr_err("Failed to enable event node: %s:%s\n",
 208                                group, event);
 209        }
 210out:
 211        mutex_unlock(&event_mutex);
 212}
 213
 214static void __init
 215trace_boot_init_events(struct trace_array *tr, struct xbc_node *node)
 216{
 217        struct xbc_node *gnode, *enode;
 218
 219        node = xbc_node_find_child(node, "event");
 220        if (!node)
 221                return;
 222        /* per-event key starts with "event.GROUP.EVENT" */
 223        xbc_node_for_each_child(node, gnode)
 224                xbc_node_for_each_child(gnode, enode)
 225                        trace_boot_init_one_event(tr, gnode, enode);
 226}
 227#else
 228#define trace_boot_enable_events(tr, node) do {} while (0)
 229#define trace_boot_init_events(tr, node) do {} while (0)
 230#endif
 231
 232#ifdef CONFIG_DYNAMIC_FTRACE
 233static void __init
 234trace_boot_set_ftrace_filter(struct trace_array *tr, struct xbc_node *node)
 235{
 236        struct xbc_node *anode;
 237        const char *p;
 238        char *q;
 239
 240        xbc_node_for_each_array_value(node, "ftrace.filters", anode, p) {
 241                q = kstrdup(p, GFP_KERNEL);
 242                if (!q)
 243                        return;
 244                if (ftrace_set_filter(tr->ops, q, strlen(q), 0) < 0)
 245                        pr_err("Failed to add %s to ftrace filter\n", p);
 246                else
 247                        ftrace_filter_param = true;
 248                kfree(q);
 249        }
 250        xbc_node_for_each_array_value(node, "ftrace.notraces", anode, p) {
 251                q = kstrdup(p, GFP_KERNEL);
 252                if (!q)
 253                        return;
 254                if (ftrace_set_notrace(tr->ops, q, strlen(q), 0) < 0)
 255                        pr_err("Failed to add %s to ftrace filter\n", p);
 256                else
 257                        ftrace_filter_param = true;
 258                kfree(q);
 259        }
 260}
 261#else
 262#define trace_boot_set_ftrace_filter(tr, node) do {} while (0)
 263#endif
 264
 265static void __init
 266trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node)
 267{
 268        const char *p;
 269
 270        trace_boot_set_ftrace_filter(tr, node);
 271
 272        p = xbc_node_find_value(node, "tracer", NULL);
 273        if (p && *p != '\0') {
 274                if (tracing_set_tracer(tr, p) < 0)
 275                        pr_err("Failed to set given tracer: %s\n", p);
 276        }
 277}
 278
 279static void __init
 280trace_boot_init_one_instance(struct trace_array *tr, struct xbc_node *node)
 281{
 282        trace_boot_set_instance_options(tr, node);
 283        trace_boot_init_events(tr, node);
 284        trace_boot_enable_events(tr, node);
 285        trace_boot_enable_tracer(tr, node);
 286}
 287
 288static void __init
 289trace_boot_init_instances(struct xbc_node *node)
 290{
 291        struct xbc_node *inode;
 292        struct trace_array *tr;
 293        const char *p;
 294
 295        node = xbc_node_find_child(node, "instance");
 296        if (!node)
 297                return;
 298
 299        xbc_node_for_each_child(node, inode) {
 300                p = xbc_node_get_data(inode);
 301                if (!p || *p == '\0')
 302                        continue;
 303
 304                tr = trace_array_get_by_name(p);
 305                if (!tr) {
 306                        pr_err("Failed to get trace instance %s\n", p);
 307                        continue;
 308                }
 309                trace_boot_init_one_instance(tr, inode);
 310                trace_array_put(tr);
 311        }
 312}
 313
 314static int __init trace_boot_init(void)
 315{
 316        struct xbc_node *trace_node;
 317        struct trace_array *tr;
 318
 319        trace_node = xbc_find_node("ftrace");
 320        if (!trace_node)
 321                return 0;
 322
 323        tr = top_trace_array();
 324        if (!tr)
 325                return 0;
 326
 327        /* Global trace array is also one instance */
 328        trace_boot_init_one_instance(tr, trace_node);
 329        trace_boot_init_instances(trace_node);
 330
 331        return 0;
 332}
 333
 334fs_initcall(trace_boot_init);
 335