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 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 119 static inline int __init 120 trace_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 128 static int __init 129 trace_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 156 static inline int __init 157 trace_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 164 static void __init 165 trace_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 } 210 out: 211 mutex_unlock(&event_mutex); 212 } 213 214 static void __init 215 trace_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 233 static void __init 234 trace_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 265 static void __init 266 trace_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 279 static void __init 280 trace_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 288 static void __init 289 trace_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 314 static 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 334 fs_initcall(trace_boot_init); 335