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 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 static void __init 73 trace_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 91 static int __init 92 trace_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 break; 106 107 ret = kprobe_event_gen_cmd_end(&cmd); 108 if (ret) 109 pr_err("Failed to add probe: %s\n", buf); 110 } 111 112 return ret; 113 } 114 #else 115 static inline int __init 116 trace_boot_add_kprobe_event(struct xbc_node *node, const char *event) 117 { 118 pr_err("Kprobe event is not supported.\n"); 119 return -ENOTSUPP; 120 } 121 #endif 122 123 #ifdef CONFIG_HIST_TRIGGERS 124 static int __init 125 trace_boot_add_synth_event(struct xbc_node *node, const char *event) 126 { 127 struct dynevent_cmd cmd; 128 struct xbc_node *anode; 129 char buf[MAX_BUF_LEN]; 130 const char *p; 131 int ret; 132 133 synth_event_cmd_init(&cmd, buf, MAX_BUF_LEN); 134 135 ret = synth_event_gen_cmd_start(&cmd, event, NULL); 136 if (ret) 137 return ret; 138 139 xbc_node_for_each_array_value(node, "fields", anode, p) { 140 ret = synth_event_add_field_str(&cmd, p); 141 if (ret) 142 return ret; 143 } 144 145 ret = synth_event_gen_cmd_end(&cmd); 146 if (ret < 0) 147 pr_err("Failed to add synthetic event: %s\n", buf); 148 149 return ret; 150 } 151 #else 152 static inline int __init 153 trace_boot_add_synth_event(struct xbc_node *node, const char *event) 154 { 155 pr_err("Synthetic event is not supported.\n"); 156 return -ENOTSUPP; 157 } 158 #endif 159 160 static void __init 161 trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode, 162 struct xbc_node *enode) 163 { 164 struct trace_event_file *file; 165 struct xbc_node *anode; 166 char buf[MAX_BUF_LEN]; 167 const char *p, *group, *event; 168 169 group = xbc_node_get_data(gnode); 170 event = xbc_node_get_data(enode); 171 172 if (!strcmp(group, "kprobes")) 173 if (trace_boot_add_kprobe_event(enode, event) < 0) 174 return; 175 if (!strcmp(group, "synthetic")) 176 if (trace_boot_add_synth_event(enode, event) < 0) 177 return; 178 179 mutex_lock(&event_mutex); 180 file = find_event_file(tr, group, event); 181 if (!file) { 182 pr_err("Failed to find event: %s:%s\n", group, event); 183 goto out; 184 } 185 186 p = xbc_node_find_value(enode, "filter", NULL); 187 if (p && *p != '\0') { 188 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) 189 pr_err("filter string is too long: %s\n", p); 190 else if (apply_event_filter(file, buf) < 0) 191 pr_err("Failed to apply filter: %s\n", buf); 192 } 193 194 xbc_node_for_each_array_value(enode, "actions", anode, p) { 195 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) 196 pr_err("action string is too long: %s\n", p); 197 else if (trigger_process_regex(file, buf) < 0) 198 pr_err("Failed to apply an action: %s\n", buf); 199 } 200 201 if (xbc_node_find_value(enode, "enable", NULL)) { 202 if (trace_event_enable_disable(file, 1, 0) < 0) 203 pr_err("Failed to enable event node: %s:%s\n", 204 group, event); 205 } 206 out: 207 mutex_unlock(&event_mutex); 208 } 209 210 static void __init 211 trace_boot_init_events(struct trace_array *tr, struct xbc_node *node) 212 { 213 struct xbc_node *gnode, *enode; 214 215 node = xbc_node_find_child(node, "event"); 216 if (!node) 217 return; 218 /* per-event key starts with "event.GROUP.EVENT" */ 219 xbc_node_for_each_child(node, gnode) 220 xbc_node_for_each_child(gnode, enode) 221 trace_boot_init_one_event(tr, gnode, enode); 222 } 223 #else 224 #define trace_boot_enable_events(tr, node) do {} while (0) 225 #define trace_boot_init_events(tr, node) do {} while (0) 226 #endif 227 228 #ifdef CONFIG_DYNAMIC_FTRACE 229 static void __init 230 trace_boot_set_ftrace_filter(struct trace_array *tr, struct xbc_node *node) 231 { 232 struct xbc_node *anode; 233 const char *p; 234 char *q; 235 236 xbc_node_for_each_array_value(node, "ftrace.filters", anode, p) { 237 q = kstrdup(p, GFP_KERNEL); 238 if (!q) 239 return; 240 if (ftrace_set_filter(tr->ops, q, strlen(q), 0) < 0) 241 pr_err("Failed to add %s to ftrace filter\n", p); 242 else 243 ftrace_filter_param = true; 244 kfree(q); 245 } 246 xbc_node_for_each_array_value(node, "ftrace.notraces", anode, p) { 247 q = kstrdup(p, GFP_KERNEL); 248 if (!q) 249 return; 250 if (ftrace_set_notrace(tr->ops, q, strlen(q), 0) < 0) 251 pr_err("Failed to add %s to ftrace filter\n", p); 252 else 253 ftrace_filter_param = true; 254 kfree(q); 255 } 256 } 257 #else 258 #define trace_boot_set_ftrace_filter(tr, node) do {} while (0) 259 #endif 260 261 static void __init 262 trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node) 263 { 264 const char *p; 265 266 trace_boot_set_ftrace_filter(tr, node); 267 268 p = xbc_node_find_value(node, "tracer", NULL); 269 if (p && *p != '\0') { 270 if (tracing_set_tracer(tr, p) < 0) 271 pr_err("Failed to set given tracer: %s\n", p); 272 } 273 } 274 275 static void __init 276 trace_boot_init_one_instance(struct trace_array *tr, struct xbc_node *node) 277 { 278 trace_boot_set_instance_options(tr, node); 279 trace_boot_init_events(tr, node); 280 trace_boot_enable_events(tr, node); 281 trace_boot_enable_tracer(tr, node); 282 } 283 284 static void __init 285 trace_boot_init_instances(struct xbc_node *node) 286 { 287 struct xbc_node *inode; 288 struct trace_array *tr; 289 const char *p; 290 291 node = xbc_node_find_child(node, "instance"); 292 if (!node) 293 return; 294 295 xbc_node_for_each_child(node, inode) { 296 p = xbc_node_get_data(inode); 297 if (!p || *p == '\0') 298 continue; 299 300 tr = trace_array_get_by_name(p); 301 if (!tr) { 302 pr_err("Failed to get trace instance %s\n", p); 303 continue; 304 } 305 trace_boot_init_one_instance(tr, inode); 306 trace_array_put(tr); 307 } 308 } 309 310 static int __init trace_boot_init(void) 311 { 312 struct xbc_node *trace_node; 313 struct trace_array *tr; 314 315 trace_node = xbc_find_node("ftrace"); 316 if (!trace_node) 317 return 0; 318 319 tr = top_trace_array(); 320 if (!tr) 321 return 0; 322 323 /* Global trace array is also one instance */ 324 trace_boot_init_one_instance(tr, trace_node); 325 trace_boot_init_instances(trace_node); 326 327 return 0; 328 } 329 330 fs_initcall(trace_boot_init); 331