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/ftrace.h> 10 #include <linux/init.h> 11 #include <linux/bootconfig.h> 12 13 #include "trace.h" 14 15 #define MAX_BUF_LEN 256 16 17 extern int trace_set_options(struct trace_array *tr, char *option); 18 extern int tracing_set_tracer(struct trace_array *tr, const char *buf); 19 extern ssize_t tracing_resize_ring_buffer(struct trace_array *tr, 20 unsigned long size, int cpu_id); 21 extern int tracing_set_cpumask(struct trace_array *tr, 22 cpumask_var_t tracing_cpumask_new); 23 24 static void __init 25 trace_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 72 extern int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set); 73 extern int trigger_process_regex(struct trace_event_file *file, char *buff); 74 75 static void __init 76 trace_boot_enable_events(struct trace_array *tr, struct xbc_node *node) 77 { 78 struct xbc_node *anode; 79 char buf[MAX_BUF_LEN]; 80 const char *p; 81 82 xbc_node_for_each_array_value(node, "events", anode, p) { 83 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) { 84 pr_err("String is too long: %s\n", p); 85 continue; 86 } 87 88 if (ftrace_set_clr_event(tr, buf, 1) < 0) 89 pr_err("Failed to enable event: %s\n", p); 90 } 91 } 92 93 #ifdef CONFIG_KPROBE_EVENTS 94 extern int trace_kprobe_run_command(const char *command); 95 96 static int __init 97 trace_boot_add_kprobe_event(struct xbc_node *node, const char *event) 98 { 99 struct xbc_node *anode; 100 char buf[MAX_BUF_LEN]; 101 const char *val; 102 char *p; 103 int len; 104 105 len = snprintf(buf, ARRAY_SIZE(buf) - 1, "p:kprobes/%s ", event); 106 if (len >= ARRAY_SIZE(buf)) { 107 pr_err("Event name is too long: %s\n", event); 108 return -E2BIG; 109 } 110 p = buf + len; 111 len = ARRAY_SIZE(buf) - len; 112 113 xbc_node_for_each_array_value(node, "probes", anode, val) { 114 if (strlcpy(p, val, len) >= len) { 115 pr_err("Probe definition is too long: %s\n", val); 116 return -E2BIG; 117 } 118 if (trace_kprobe_run_command(buf) < 0) { 119 pr_err("Failed to add probe: %s\n", buf); 120 return -EINVAL; 121 } 122 } 123 124 return 0; 125 } 126 #else 127 static inline int __init 128 trace_boot_add_kprobe_event(struct xbc_node *node, const char *event) 129 { 130 pr_err("Kprobe event is not supported.\n"); 131 return -ENOTSUPP; 132 } 133 #endif 134 135 #ifdef CONFIG_HIST_TRIGGERS 136 extern int synth_event_run_command(const char *command); 137 138 static int __init 139 trace_boot_add_synth_event(struct xbc_node *node, const char *event) 140 { 141 struct xbc_node *anode; 142 char buf[MAX_BUF_LEN], *q; 143 const char *p; 144 int len, delta, ret; 145 146 len = ARRAY_SIZE(buf); 147 delta = snprintf(buf, len, "%s", event); 148 if (delta >= len) { 149 pr_err("Event name is too long: %s\n", event); 150 return -E2BIG; 151 } 152 len -= delta; q = buf + delta; 153 154 xbc_node_for_each_array_value(node, "fields", anode, p) { 155 delta = snprintf(q, len, " %s;", p); 156 if (delta >= len) { 157 pr_err("fields string is too long: %s\n", p); 158 return -E2BIG; 159 } 160 len -= delta; q += delta; 161 } 162 163 ret = synth_event_run_command(buf); 164 if (ret < 0) 165 pr_err("Failed to add synthetic event: %s\n", buf); 166 167 168 return ret; 169 } 170 #else 171 static inline int __init 172 trace_boot_add_synth_event(struct xbc_node *node, const char *event) 173 { 174 pr_err("Synthetic event is not supported.\n"); 175 return -ENOTSUPP; 176 } 177 #endif 178 179 static void __init 180 trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode, 181 struct xbc_node *enode) 182 { 183 struct trace_event_file *file; 184 struct xbc_node *anode; 185 char buf[MAX_BUF_LEN]; 186 const char *p, *group, *event; 187 188 group = xbc_node_get_data(gnode); 189 event = xbc_node_get_data(enode); 190 191 if (!strcmp(group, "kprobes")) 192 if (trace_boot_add_kprobe_event(enode, event) < 0) 193 return; 194 if (!strcmp(group, "synthetic")) 195 if (trace_boot_add_synth_event(enode, event) < 0) 196 return; 197 198 mutex_lock(&event_mutex); 199 file = find_event_file(tr, group, event); 200 if (!file) { 201 pr_err("Failed to find event: %s:%s\n", group, event); 202 goto out; 203 } 204 205 p = xbc_node_find_value(enode, "filter", NULL); 206 if (p && *p != '\0') { 207 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) 208 pr_err("filter string is too long: %s\n", p); 209 else if (apply_event_filter(file, buf) < 0) 210 pr_err("Failed to apply filter: %s\n", buf); 211 } 212 213 xbc_node_for_each_array_value(enode, "actions", anode, p) { 214 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) 215 pr_err("action string is too long: %s\n", p); 216 else if (trigger_process_regex(file, buf) < 0) 217 pr_err("Failed to apply an action: %s\n", buf); 218 } 219 220 if (xbc_node_find_value(enode, "enable", NULL)) { 221 if (trace_event_enable_disable(file, 1, 0) < 0) 222 pr_err("Failed to enable event node: %s:%s\n", 223 group, event); 224 } 225 out: 226 mutex_unlock(&event_mutex); 227 } 228 229 static void __init 230 trace_boot_init_events(struct trace_array *tr, struct xbc_node *node) 231 { 232 struct xbc_node *gnode, *enode; 233 234 node = xbc_node_find_child(node, "event"); 235 if (!node) 236 return; 237 /* per-event key starts with "event.GROUP.EVENT" */ 238 xbc_node_for_each_child(node, gnode) 239 xbc_node_for_each_child(gnode, enode) 240 trace_boot_init_one_event(tr, gnode, enode); 241 } 242 #else 243 #define trace_boot_enable_events(tr, node) do {} while (0) 244 #define trace_boot_init_events(tr, node) do {} while (0) 245 #endif 246 247 #ifdef CONFIG_DYNAMIC_FTRACE 248 extern bool ftrace_filter_param __initdata; 249 extern int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, 250 int len, int reset); 251 extern int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, 252 int len, int reset); 253 static void __init 254 trace_boot_set_ftrace_filter(struct trace_array *tr, struct xbc_node *node) 255 { 256 struct xbc_node *anode; 257 const char *p; 258 char *q; 259 260 xbc_node_for_each_array_value(node, "ftrace.filters", anode, p) { 261 q = kstrdup(p, GFP_KERNEL); 262 if (!q) 263 return; 264 if (ftrace_set_filter(tr->ops, q, strlen(q), 0) < 0) 265 pr_err("Failed to add %s to ftrace filter\n", p); 266 else 267 ftrace_filter_param = true; 268 kfree(q); 269 } 270 xbc_node_for_each_array_value(node, "ftrace.notraces", anode, p) { 271 q = kstrdup(p, GFP_KERNEL); 272 if (!q) 273 return; 274 if (ftrace_set_notrace(tr->ops, q, strlen(q), 0) < 0) 275 pr_err("Failed to add %s to ftrace filter\n", p); 276 else 277 ftrace_filter_param = true; 278 kfree(q); 279 } 280 } 281 #else 282 #define trace_boot_set_ftrace_filter(tr, node) do {} while (0) 283 #endif 284 285 static void __init 286 trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node) 287 { 288 const char *p; 289 290 trace_boot_set_ftrace_filter(tr, node); 291 292 p = xbc_node_find_value(node, "tracer", NULL); 293 if (p && *p != '\0') { 294 if (tracing_set_tracer(tr, p) < 0) 295 pr_err("Failed to set given tracer: %s\n", p); 296 } 297 } 298 299 static void __init 300 trace_boot_init_one_instance(struct trace_array *tr, struct xbc_node *node) 301 { 302 trace_boot_set_instance_options(tr, node); 303 trace_boot_init_events(tr, node); 304 trace_boot_enable_events(tr, node); 305 trace_boot_enable_tracer(tr, node); 306 } 307 308 static void __init 309 trace_boot_init_instances(struct xbc_node *node) 310 { 311 struct xbc_node *inode; 312 struct trace_array *tr; 313 const char *p; 314 315 node = xbc_node_find_child(node, "instance"); 316 if (!node) 317 return; 318 319 xbc_node_for_each_child(node, inode) { 320 p = xbc_node_get_data(inode); 321 if (!p || *p == '\0') 322 continue; 323 324 tr = trace_array_get_by_name(p); 325 if (!tr) { 326 pr_err("Failed to get trace instance %s\n", p); 327 continue; 328 } 329 trace_boot_init_one_instance(tr, inode); 330 trace_array_put(tr); 331 } 332 } 333 334 static int __init trace_boot_init(void) 335 { 336 struct xbc_node *trace_node; 337 struct trace_array *tr; 338 339 trace_node = xbc_find_node("ftrace"); 340 if (!trace_node) 341 return 0; 342 343 tr = top_trace_array(); 344 if (!tr) 345 return 0; 346 347 /* Global trace array is also one instance */ 348 trace_boot_init_one_instance(tr, trace_node); 349 trace_boot_init_instances(trace_node); 350 351 return 0; 352 } 353 354 fs_initcall(trace_boot_init); 355