split dev_queue
[cor.git] / kernel / trace / trace_events_inject.c
blobd43710718ee592a660ef679f48a75c0ffe4ecd81
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * trace_events_inject - trace event injection
5 * Copyright (C) 2019 Cong Wang <cwang@twitter.com>
6 */
8 #include <linux/module.h>
9 #include <linux/ctype.h>
10 #include <linux/mutex.h>
11 #include <linux/slab.h>
12 #include <linux/rculist.h>
14 #include "trace.h"
16 static int
17 trace_inject_entry(struct trace_event_file *file, void *rec, int len)
19 struct trace_event_buffer fbuffer;
20 struct ring_buffer *buffer;
21 int written = 0;
22 void *entry;
24 rcu_read_lock_sched();
25 buffer = file->tr->trace_buffer.buffer;
26 entry = trace_event_buffer_reserve(&fbuffer, file, len);
27 if (entry) {
28 memcpy(entry, rec, len);
29 written = len;
30 trace_event_buffer_commit(&fbuffer);
32 rcu_read_unlock_sched();
34 return written;
37 static int
38 parse_field(char *str, struct trace_event_call *call,
39 struct ftrace_event_field **pf, u64 *pv)
41 struct ftrace_event_field *field;
42 char *field_name;
43 int s, i = 0;
44 int len;
45 u64 val;
47 if (!str[i])
48 return 0;
49 /* First find the field to associate to */
50 while (isspace(str[i]))
51 i++;
52 s = i;
53 while (isalnum(str[i]) || str[i] == '_')
54 i++;
55 len = i - s;
56 if (!len)
57 return -EINVAL;
59 field_name = kmemdup_nul(str + s, len, GFP_KERNEL);
60 if (!field_name)
61 return -ENOMEM;
62 field = trace_find_event_field(call, field_name);
63 kfree(field_name);
64 if (!field)
65 return -ENOENT;
67 *pf = field;
68 while (isspace(str[i]))
69 i++;
70 if (str[i] != '=')
71 return -EINVAL;
72 i++;
73 while (isspace(str[i]))
74 i++;
75 s = i;
76 if (isdigit(str[i]) || str[i] == '-') {
77 char *num, c;
78 int ret;
80 /* Make sure the field is not a string */
81 if (is_string_field(field))
82 return -EINVAL;
84 if (str[i] == '-')
85 i++;
87 /* We allow 0xDEADBEEF */
88 while (isalnum(str[i]))
89 i++;
90 num = str + s;
91 c = str[i];
92 if (c != '\0' && !isspace(c))
93 return -EINVAL;
94 str[i] = '\0';
95 /* Make sure it is a value */
96 if (field->is_signed)
97 ret = kstrtoll(num, 0, &val);
98 else
99 ret = kstrtoull(num, 0, &val);
100 str[i] = c;
101 if (ret)
102 return ret;
104 *pv = val;
105 return i;
106 } else if (str[i] == '\'' || str[i] == '"') {
107 char q = str[i];
109 /* Make sure the field is OK for strings */
110 if (!is_string_field(field))
111 return -EINVAL;
113 for (i++; str[i]; i++) {
114 if (str[i] == '\\' && str[i + 1]) {
115 i++;
116 continue;
118 if (str[i] == q)
119 break;
121 if (!str[i])
122 return -EINVAL;
124 /* Skip quotes */
125 s++;
126 len = i - s;
127 if (len >= MAX_FILTER_STR_VAL)
128 return -EINVAL;
130 *pv = (unsigned long)(str + s);
131 str[i] = 0;
132 /* go past the last quote */
133 i++;
134 return i;
137 return -EINVAL;
140 static int trace_get_entry_size(struct trace_event_call *call)
142 struct ftrace_event_field *field;
143 struct list_head *head;
144 int size = 0;
146 head = trace_get_fields(call);
147 list_for_each_entry(field, head, link) {
148 if (field->size + field->offset > size)
149 size = field->size + field->offset;
152 return size;
155 static void *trace_alloc_entry(struct trace_event_call *call, int *size)
157 int entry_size = trace_get_entry_size(call);
158 struct ftrace_event_field *field;
159 struct list_head *head;
160 void *entry = NULL;
162 /* We need an extra '\0' at the end. */
163 entry = kzalloc(entry_size + 1, GFP_KERNEL);
164 if (!entry)
165 return NULL;
167 head = trace_get_fields(call);
168 list_for_each_entry(field, head, link) {
169 if (!is_string_field(field))
170 continue;
171 if (field->filter_type == FILTER_STATIC_STRING)
172 continue;
173 if (field->filter_type == FILTER_DYN_STRING) {
174 u32 *str_item;
175 int str_loc = entry_size & 0xffff;
177 str_item = (u32 *)(entry + field->offset);
178 *str_item = str_loc; /* string length is 0. */
179 } else {
180 char **paddr;
182 paddr = (char **)(entry + field->offset);
183 *paddr = "";
187 *size = entry_size + 1;
188 return entry;
191 #define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
193 /* Caller is responsible to free the *pentry. */
194 static int parse_entry(char *str, struct trace_event_call *call, void **pentry)
196 struct ftrace_event_field *field;
197 unsigned long irq_flags;
198 void *entry = NULL;
199 int entry_size;
200 u64 val;
201 int len;
203 entry = trace_alloc_entry(call, &entry_size);
204 *pentry = entry;
205 if (!entry)
206 return -ENOMEM;
208 local_save_flags(irq_flags);
209 tracing_generic_entry_update(entry, call->event.type, irq_flags,
210 preempt_count());
212 while ((len = parse_field(str, call, &field, &val)) > 0) {
213 if (is_function_field(field))
214 return -EINVAL;
216 if (is_string_field(field)) {
217 char *addr = (char *)(unsigned long) val;
219 if (field->filter_type == FILTER_STATIC_STRING) {
220 strlcpy(entry + field->offset, addr, field->size);
221 } else if (field->filter_type == FILTER_DYN_STRING) {
222 int str_len = strlen(addr) + 1;
223 int str_loc = entry_size & 0xffff;
224 u32 *str_item;
226 entry_size += str_len;
227 *pentry = krealloc(entry, entry_size, GFP_KERNEL);
228 if (!*pentry) {
229 kfree(entry);
230 return -ENOMEM;
232 entry = *pentry;
234 strlcpy(entry + (entry_size - str_len), addr, str_len);
235 str_item = (u32 *)(entry + field->offset);
236 *str_item = (str_len << 16) | str_loc;
237 } else {
238 char **paddr;
240 paddr = (char **)(entry + field->offset);
241 *paddr = INJECT_STRING;
243 } else {
244 switch (field->size) {
245 case 1: {
246 u8 tmp = (u8) val;
248 memcpy(entry + field->offset, &tmp, 1);
249 break;
251 case 2: {
252 u16 tmp = (u16) val;
254 memcpy(entry + field->offset, &tmp, 2);
255 break;
257 case 4: {
258 u32 tmp = (u32) val;
260 memcpy(entry + field->offset, &tmp, 4);
261 break;
263 case 8:
264 memcpy(entry + field->offset, &val, 8);
265 break;
266 default:
267 return -EINVAL;
271 str += len;
274 if (len < 0)
275 return len;
277 return entry_size;
280 static ssize_t
281 event_inject_write(struct file *filp, const char __user *ubuf, size_t cnt,
282 loff_t *ppos)
284 struct trace_event_call *call;
285 struct trace_event_file *file;
286 int err = -ENODEV, size;
287 void *entry = NULL;
288 char *buf;
290 if (cnt >= PAGE_SIZE)
291 return -EINVAL;
293 buf = memdup_user_nul(ubuf, cnt);
294 if (IS_ERR(buf))
295 return PTR_ERR(buf);
296 strim(buf);
298 mutex_lock(&event_mutex);
299 file = event_file_data(filp);
300 if (file) {
301 call = file->event_call;
302 size = parse_entry(buf, call, &entry);
303 if (size < 0)
304 err = size;
305 else
306 err = trace_inject_entry(file, entry, size);
308 mutex_unlock(&event_mutex);
310 kfree(entry);
311 kfree(buf);
313 if (err < 0)
314 return err;
316 *ppos += err;
317 return cnt;
320 static ssize_t
321 event_inject_read(struct file *file, char __user *buf, size_t size,
322 loff_t *ppos)
324 return -EPERM;
327 const struct file_operations event_inject_fops = {
328 .open = tracing_open_generic,
329 .read = event_inject_read,
330 .write = event_inject_write,