1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> |
4 | */ |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | #include <errno.h> |
9 | |
10 | #include "debug.h" |
11 | #include "trace-event.h" |
12 | |
13 | #include <linux/ctype.h> |
14 | #include <linux/kernel.h> |
15 | #include <traceevent/event-parse.h> |
16 | |
17 | static int get_common_field(struct scripting_context *context, |
18 | int *offset, int *size, const char *type) |
19 | { |
20 | struct tep_handle *pevent = context->pevent; |
21 | struct tep_event *event; |
22 | struct tep_format_field *field; |
23 | |
24 | if (!*size) { |
25 | |
26 | event = tep_get_first_event(pevent); |
27 | if (!event) |
28 | return 0; |
29 | |
30 | field = tep_find_common_field(event, type); |
31 | if (!field) |
32 | return 0; |
33 | *offset = field->offset; |
34 | *size = field->size; |
35 | } |
36 | |
37 | return tep_read_number(pevent, context->event_data + *offset, *size); |
38 | } |
39 | |
40 | int common_lock_depth(struct scripting_context *context) |
41 | { |
42 | static int offset; |
43 | static int size; |
44 | int ret; |
45 | |
46 | ret = get_common_field(context, offset: &size, size: &offset, |
47 | type: "common_lock_depth" ); |
48 | if (ret < 0) |
49 | return -1; |
50 | |
51 | return ret; |
52 | } |
53 | |
54 | int common_flags(struct scripting_context *context) |
55 | { |
56 | static int offset; |
57 | static int size; |
58 | int ret; |
59 | |
60 | ret = get_common_field(context, offset: &size, size: &offset, |
61 | type: "common_flags" ); |
62 | if (ret < 0) |
63 | return -1; |
64 | |
65 | return ret; |
66 | } |
67 | |
68 | int common_pc(struct scripting_context *context) |
69 | { |
70 | static int offset; |
71 | static int size; |
72 | int ret; |
73 | |
74 | ret = get_common_field(context, offset: &size, size: &offset, |
75 | type: "common_preempt_count" ); |
76 | if (ret < 0) |
77 | return -1; |
78 | |
79 | return ret; |
80 | } |
81 | |
82 | unsigned long long |
83 | raw_field_value(struct tep_event *event, const char *name, void *data) |
84 | { |
85 | struct tep_format_field *field; |
86 | unsigned long long val; |
87 | |
88 | field = tep_find_any_field(event, name); |
89 | if (!field) |
90 | return 0ULL; |
91 | |
92 | tep_read_number_field(field, data, &val); |
93 | |
94 | return val; |
95 | } |
96 | |
97 | unsigned long long read_size(struct tep_event *event, void *ptr, int size) |
98 | { |
99 | return tep_read_number(event->tep, ptr, size); |
100 | } |
101 | |
102 | void event_format__fprintf(struct tep_event *event, |
103 | int cpu, void *data, int size, FILE *fp) |
104 | { |
105 | struct tep_record record; |
106 | struct trace_seq s; |
107 | |
108 | memset(&record, 0, sizeof(record)); |
109 | record.cpu = cpu; |
110 | record.size = size; |
111 | record.data = data; |
112 | |
113 | trace_seq_init(&s); |
114 | tep_print_event(event->tep, &s, &record, "%s" , TEP_PRINT_INFO); |
115 | trace_seq_do_fprintf(&s, fp); |
116 | trace_seq_destroy(&s); |
117 | } |
118 | |
119 | void event_format__print(struct tep_event *event, |
120 | int cpu, void *data, int size) |
121 | { |
122 | return event_format__fprintf(event, cpu, data, size, stdout); |
123 | } |
124 | |
125 | /* |
126 | * prev_state is of size long, which is 32 bits on 32 bit architectures. |
127 | * As it needs to have the same bits for both 32 bit and 64 bit architectures |
128 | * we can just assume that the flags we care about will all be within |
129 | * the 32 bits. |
130 | */ |
131 | #define MAX_STATE_BITS 32 |
132 | |
133 | static const char *convert_sym(struct tep_print_flag_sym *sym) |
134 | { |
135 | static char save_states[MAX_STATE_BITS + 1]; |
136 | |
137 | memset(save_states, 0, sizeof(save_states)); |
138 | |
139 | /* This is the flags for the prev_state_field, now make them into a string */ |
140 | for (; sym; sym = sym->next) { |
141 | long bitmask = strtoul(sym->value, NULL, 0); |
142 | int i; |
143 | |
144 | for (i = 0; !(bitmask & 1); i++) |
145 | bitmask >>= 1; |
146 | |
147 | if (i >= MAX_STATE_BITS) |
148 | continue; |
149 | |
150 | save_states[i] = sym->str[0]; |
151 | } |
152 | |
153 | return save_states; |
154 | } |
155 | |
156 | static struct tep_print_arg_field * |
157 | find_arg_field(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) |
158 | { |
159 | struct tep_print_arg_field *field; |
160 | |
161 | if (!arg) |
162 | return NULL; |
163 | |
164 | if (arg->type == TEP_PRINT_FIELD) |
165 | return &arg->field; |
166 | |
167 | if (arg->type == TEP_PRINT_OP) { |
168 | field = find_arg_field(prev_state_field, arg: arg->op.left); |
169 | if (field && field->field == prev_state_field) |
170 | return field; |
171 | field = find_arg_field(prev_state_field, arg: arg->op.right); |
172 | if (field && field->field == prev_state_field) |
173 | return field; |
174 | } |
175 | return NULL; |
176 | } |
177 | |
178 | static struct tep_print_flag_sym * |
179 | test_flags(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) |
180 | { |
181 | struct tep_print_arg_field *field; |
182 | |
183 | field = find_arg_field(prev_state_field, arg: arg->flags.field); |
184 | if (!field) |
185 | return NULL; |
186 | |
187 | return arg->flags.flags; |
188 | } |
189 | |
190 | static struct tep_print_flag_sym * |
191 | search_op(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) |
192 | { |
193 | struct tep_print_flag_sym *sym = NULL; |
194 | |
195 | if (!arg) |
196 | return NULL; |
197 | |
198 | if (arg->type == TEP_PRINT_OP) { |
199 | sym = search_op(prev_state_field, arg: arg->op.left); |
200 | if (sym) |
201 | return sym; |
202 | |
203 | sym = search_op(prev_state_field, arg: arg->op.right); |
204 | if (sym) |
205 | return sym; |
206 | } else if (arg->type == TEP_PRINT_FLAGS) { |
207 | sym = test_flags(prev_state_field, arg); |
208 | } |
209 | |
210 | return sym; |
211 | } |
212 | |
213 | const char *parse_task_states(struct tep_format_field *state_field) |
214 | { |
215 | struct tep_print_flag_sym *sym; |
216 | struct tep_print_arg *arg; |
217 | struct tep_event *event; |
218 | |
219 | event = state_field->event; |
220 | |
221 | /* |
222 | * Look at the event format fields, and search for where |
223 | * the prev_state is parsed via the format flags. |
224 | */ |
225 | for (arg = event->print_fmt.args; arg; arg = arg->next) { |
226 | /* |
227 | * Currently, the __print_flags() for the prev_state |
228 | * is embedded in operations, so they too must be |
229 | * searched. |
230 | */ |
231 | sym = search_op(prev_state_field: state_field, arg); |
232 | if (sym) |
233 | return convert_sym(sym); |
234 | } |
235 | return NULL; |
236 | } |
237 | |
238 | void parse_ftrace_printk(struct tep_handle *pevent, |
239 | char *file, unsigned int size __maybe_unused) |
240 | { |
241 | unsigned long long addr; |
242 | char *printk; |
243 | char *line; |
244 | char *next = NULL; |
245 | char *addr_str; |
246 | char *fmt = NULL; |
247 | |
248 | line = strtok_r(file, "\n" , &next); |
249 | while (line) { |
250 | addr_str = strtok_r(line, ":" , &fmt); |
251 | if (!addr_str) { |
252 | pr_warning("printk format with empty entry" ); |
253 | break; |
254 | } |
255 | addr = strtoull(addr_str, NULL, 16); |
256 | /* fmt still has a space, skip it */ |
257 | printk = strdup(fmt+1); |
258 | line = strtok_r(NULL, "\n" , &next); |
259 | tep_register_print_string(pevent, printk, addr); |
260 | free(printk); |
261 | } |
262 | } |
263 | |
264 | void parse_saved_cmdline(struct tep_handle *pevent, |
265 | char *file, unsigned int size __maybe_unused) |
266 | { |
267 | char comm[17]; /* Max comm length in the kernel is 16. */ |
268 | char *line; |
269 | char *next = NULL; |
270 | int pid; |
271 | |
272 | line = strtok_r(file, "\n" , &next); |
273 | while (line) { |
274 | if (sscanf(line, "%d %16s" , &pid, comm) == 2) |
275 | tep_register_comm(pevent, comm, pid); |
276 | line = strtok_r(NULL, "\n" , &next); |
277 | } |
278 | } |
279 | |
280 | int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) |
281 | { |
282 | return tep_parse_event(pevent, buf, size, "ftrace" ); |
283 | } |
284 | |
285 | int parse_event_file(struct tep_handle *pevent, |
286 | char *buf, unsigned long size, char *sys) |
287 | { |
288 | return tep_parse_event(pevent, buf, size, sys); |
289 | } |
290 | |
291 | struct flag { |
292 | const char *name; |
293 | unsigned long long value; |
294 | }; |
295 | |
296 | static const struct flag flags[] = { |
297 | { "HI_SOFTIRQ" , 0 }, |
298 | { "TIMER_SOFTIRQ" , 1 }, |
299 | { "NET_TX_SOFTIRQ" , 2 }, |
300 | { "NET_RX_SOFTIRQ" , 3 }, |
301 | { "BLOCK_SOFTIRQ" , 4 }, |
302 | { "IRQ_POLL_SOFTIRQ" , 5 }, |
303 | { "TASKLET_SOFTIRQ" , 6 }, |
304 | { "SCHED_SOFTIRQ" , 7 }, |
305 | { "HRTIMER_SOFTIRQ" , 8 }, |
306 | { "RCU_SOFTIRQ" , 9 }, |
307 | |
308 | { "HRTIMER_NORESTART" , 0 }, |
309 | { "HRTIMER_RESTART" , 1 }, |
310 | }; |
311 | |
312 | unsigned long long eval_flag(const char *flag) |
313 | { |
314 | int i; |
315 | |
316 | /* |
317 | * Some flags in the format files do not get converted. |
318 | * If the flag is not numeric, see if it is something that |
319 | * we already know about. |
320 | */ |
321 | if (isdigit(c: flag[0])) |
322 | return strtoull(flag, NULL, 0); |
323 | |
324 | for (i = 0; i < (int)(ARRAY_SIZE(flags)); i++) |
325 | if (strcmp(flags[i].name, flag) == 0) |
326 | return flags[i].value; |
327 | |
328 | return 0; |
329 | } |
330 | |