1*436bf2bcSAndroid Build Coastguard Worker // SPDX-License-Identifier: LGPL-2.1
2*436bf2bcSAndroid Build Coastguard Worker /*
3*436bf2bcSAndroid Build Coastguard Worker * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4*436bf2bcSAndroid Build Coastguard Worker */
5*436bf2bcSAndroid Build Coastguard Worker #include <stdio.h>
6*436bf2bcSAndroid Build Coastguard Worker #include <stdlib.h>
7*436bf2bcSAndroid Build Coastguard Worker #include <string.h>
8*436bf2bcSAndroid Build Coastguard Worker
9*436bf2bcSAndroid Build Coastguard Worker #include "event-parse.h"
10*436bf2bcSAndroid Build Coastguard Worker #include "trace-seq.h"
11*436bf2bcSAndroid Build Coastguard Worker
12*436bf2bcSAndroid Build Coastguard Worker /*
13*436bf2bcSAndroid Build Coastguard Worker * prev_state is of size long, which is 32 bits on 32 bit architectures.
14*436bf2bcSAndroid Build Coastguard Worker * As it needs to have the same bits for both 32 bit and 64 bit architectures
15*436bf2bcSAndroid Build Coastguard Worker * we can just assume that the flags we care about will all be within
16*436bf2bcSAndroid Build Coastguard Worker * the 32 bits.
17*436bf2bcSAndroid Build Coastguard Worker */
18*436bf2bcSAndroid Build Coastguard Worker #define MAX_STATE_BITS 32
19*436bf2bcSAndroid Build Coastguard Worker
convert_sym(struct tep_print_flag_sym * sym)20*436bf2bcSAndroid Build Coastguard Worker static const char *convert_sym(struct tep_print_flag_sym *sym)
21*436bf2bcSAndroid Build Coastguard Worker {
22*436bf2bcSAndroid Build Coastguard Worker static char save_states[MAX_STATE_BITS + 1];
23*436bf2bcSAndroid Build Coastguard Worker
24*436bf2bcSAndroid Build Coastguard Worker memset(save_states, 0, sizeof(save_states));
25*436bf2bcSAndroid Build Coastguard Worker
26*436bf2bcSAndroid Build Coastguard Worker /* This is the flags for the prev_state_field, now make them into a string */
27*436bf2bcSAndroid Build Coastguard Worker for (; sym; sym = sym->next) {
28*436bf2bcSAndroid Build Coastguard Worker long bitmask = strtoul(sym->value, NULL, 0);
29*436bf2bcSAndroid Build Coastguard Worker int i;
30*436bf2bcSAndroid Build Coastguard Worker
31*436bf2bcSAndroid Build Coastguard Worker for (i = 0; !(bitmask & 1); i++)
32*436bf2bcSAndroid Build Coastguard Worker bitmask >>= 1;
33*436bf2bcSAndroid Build Coastguard Worker
34*436bf2bcSAndroid Build Coastguard Worker if (i >= MAX_STATE_BITS)
35*436bf2bcSAndroid Build Coastguard Worker continue;
36*436bf2bcSAndroid Build Coastguard Worker
37*436bf2bcSAndroid Build Coastguard Worker save_states[i] = sym->str[0];
38*436bf2bcSAndroid Build Coastguard Worker }
39*436bf2bcSAndroid Build Coastguard Worker
40*436bf2bcSAndroid Build Coastguard Worker return save_states;
41*436bf2bcSAndroid Build Coastguard Worker }
42*436bf2bcSAndroid Build Coastguard Worker
43*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_arg_field *
find_arg_field(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)44*436bf2bcSAndroid Build Coastguard Worker find_arg_field(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
45*436bf2bcSAndroid Build Coastguard Worker {
46*436bf2bcSAndroid Build Coastguard Worker struct tep_print_arg_field *field;
47*436bf2bcSAndroid Build Coastguard Worker
48*436bf2bcSAndroid Build Coastguard Worker if (!arg)
49*436bf2bcSAndroid Build Coastguard Worker return NULL;
50*436bf2bcSAndroid Build Coastguard Worker
51*436bf2bcSAndroid Build Coastguard Worker if (arg->type == TEP_PRINT_FIELD)
52*436bf2bcSAndroid Build Coastguard Worker return &arg->field;
53*436bf2bcSAndroid Build Coastguard Worker
54*436bf2bcSAndroid Build Coastguard Worker if (arg->type == TEP_PRINT_OP) {
55*436bf2bcSAndroid Build Coastguard Worker field = find_arg_field(prev_state_field, arg->op.left);
56*436bf2bcSAndroid Build Coastguard Worker if (field && field->field == prev_state_field)
57*436bf2bcSAndroid Build Coastguard Worker return field;
58*436bf2bcSAndroid Build Coastguard Worker field = find_arg_field(prev_state_field, arg->op.right);
59*436bf2bcSAndroid Build Coastguard Worker if (field && field->field == prev_state_field)
60*436bf2bcSAndroid Build Coastguard Worker return field;
61*436bf2bcSAndroid Build Coastguard Worker }
62*436bf2bcSAndroid Build Coastguard Worker return NULL;
63*436bf2bcSAndroid Build Coastguard Worker }
64*436bf2bcSAndroid Build Coastguard Worker
65*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_flag_sym *
test_flags(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)66*436bf2bcSAndroid Build Coastguard Worker test_flags(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
67*436bf2bcSAndroid Build Coastguard Worker {
68*436bf2bcSAndroid Build Coastguard Worker struct tep_print_arg_field *field;
69*436bf2bcSAndroid Build Coastguard Worker
70*436bf2bcSAndroid Build Coastguard Worker field = find_arg_field(prev_state_field, arg->flags.field);
71*436bf2bcSAndroid Build Coastguard Worker if (!field)
72*436bf2bcSAndroid Build Coastguard Worker return NULL;
73*436bf2bcSAndroid Build Coastguard Worker
74*436bf2bcSAndroid Build Coastguard Worker return arg->flags.flags;
75*436bf2bcSAndroid Build Coastguard Worker }
76*436bf2bcSAndroid Build Coastguard Worker
77*436bf2bcSAndroid Build Coastguard Worker static struct tep_print_flag_sym *
search_op(struct tep_format_field * prev_state_field,struct tep_print_arg * arg)78*436bf2bcSAndroid Build Coastguard Worker search_op(struct tep_format_field *prev_state_field, struct tep_print_arg *arg)
79*436bf2bcSAndroid Build Coastguard Worker {
80*436bf2bcSAndroid Build Coastguard Worker struct tep_print_flag_sym *sym = NULL;
81*436bf2bcSAndroid Build Coastguard Worker
82*436bf2bcSAndroid Build Coastguard Worker if (!arg)
83*436bf2bcSAndroid Build Coastguard Worker return NULL;
84*436bf2bcSAndroid Build Coastguard Worker
85*436bf2bcSAndroid Build Coastguard Worker if (arg->type == TEP_PRINT_OP) {
86*436bf2bcSAndroid Build Coastguard Worker sym = search_op(prev_state_field, arg->op.left);
87*436bf2bcSAndroid Build Coastguard Worker if (sym)
88*436bf2bcSAndroid Build Coastguard Worker return sym;
89*436bf2bcSAndroid Build Coastguard Worker
90*436bf2bcSAndroid Build Coastguard Worker sym = search_op(prev_state_field, arg->op.right);
91*436bf2bcSAndroid Build Coastguard Worker if (sym)
92*436bf2bcSAndroid Build Coastguard Worker return sym;
93*436bf2bcSAndroid Build Coastguard Worker } else if (arg->type == TEP_PRINT_FLAGS) {
94*436bf2bcSAndroid Build Coastguard Worker sym = test_flags(prev_state_field, arg);
95*436bf2bcSAndroid Build Coastguard Worker }
96*436bf2bcSAndroid Build Coastguard Worker
97*436bf2bcSAndroid Build Coastguard Worker return sym;
98*436bf2bcSAndroid Build Coastguard Worker }
99*436bf2bcSAndroid Build Coastguard Worker
get_states(struct tep_format_field * prev_state_field)100*436bf2bcSAndroid Build Coastguard Worker static const char *get_states(struct tep_format_field *prev_state_field)
101*436bf2bcSAndroid Build Coastguard Worker {
102*436bf2bcSAndroid Build Coastguard Worker struct tep_print_flag_sym *sym;
103*436bf2bcSAndroid Build Coastguard Worker struct tep_print_arg *arg;
104*436bf2bcSAndroid Build Coastguard Worker struct tep_event *event;
105*436bf2bcSAndroid Build Coastguard Worker
106*436bf2bcSAndroid Build Coastguard Worker event = prev_state_field->event;
107*436bf2bcSAndroid Build Coastguard Worker
108*436bf2bcSAndroid Build Coastguard Worker /*
109*436bf2bcSAndroid Build Coastguard Worker * Look at the event format fields, and search for where
110*436bf2bcSAndroid Build Coastguard Worker * the prev_state is parsed via the format flags.
111*436bf2bcSAndroid Build Coastguard Worker */
112*436bf2bcSAndroid Build Coastguard Worker for (arg = event->print_fmt.args; arg; arg = arg->next) {
113*436bf2bcSAndroid Build Coastguard Worker /*
114*436bf2bcSAndroid Build Coastguard Worker * Currently, the __print_flags() for the prev_state
115*436bf2bcSAndroid Build Coastguard Worker * is embedded in operations, so they too must be
116*436bf2bcSAndroid Build Coastguard Worker * searched.
117*436bf2bcSAndroid Build Coastguard Worker */
118*436bf2bcSAndroid Build Coastguard Worker sym = search_op(prev_state_field, arg);
119*436bf2bcSAndroid Build Coastguard Worker if (sym)
120*436bf2bcSAndroid Build Coastguard Worker return convert_sym(sym);
121*436bf2bcSAndroid Build Coastguard Worker }
122*436bf2bcSAndroid Build Coastguard Worker return NULL;
123*436bf2bcSAndroid Build Coastguard Worker }
124*436bf2bcSAndroid Build Coastguard Worker
write_state(struct trace_seq * s,struct tep_format_field * field,struct tep_record * record)125*436bf2bcSAndroid Build Coastguard Worker static void write_state(struct trace_seq *s, struct tep_format_field *field,
126*436bf2bcSAndroid Build Coastguard Worker struct tep_record *record)
127*436bf2bcSAndroid Build Coastguard Worker {
128*436bf2bcSAndroid Build Coastguard Worker static struct tep_format_field *prev_state_field;
129*436bf2bcSAndroid Build Coastguard Worker static const char *states;
130*436bf2bcSAndroid Build Coastguard Worker unsigned long long val;
131*436bf2bcSAndroid Build Coastguard Worker int found = 0;
132*436bf2bcSAndroid Build Coastguard Worker int len;
133*436bf2bcSAndroid Build Coastguard Worker int i;
134*436bf2bcSAndroid Build Coastguard Worker
135*436bf2bcSAndroid Build Coastguard Worker if (!field)
136*436bf2bcSAndroid Build Coastguard Worker return;
137*436bf2bcSAndroid Build Coastguard Worker
138*436bf2bcSAndroid Build Coastguard Worker if (!states || field != prev_state_field) {
139*436bf2bcSAndroid Build Coastguard Worker states = get_states(field);
140*436bf2bcSAndroid Build Coastguard Worker if (!states)
141*436bf2bcSAndroid Build Coastguard Worker states = "SDTtXZPI";
142*436bf2bcSAndroid Build Coastguard Worker prev_state_field = field;
143*436bf2bcSAndroid Build Coastguard Worker }
144*436bf2bcSAndroid Build Coastguard Worker
145*436bf2bcSAndroid Build Coastguard Worker tep_read_number_field(field, record->data, &val);
146*436bf2bcSAndroid Build Coastguard Worker
147*436bf2bcSAndroid Build Coastguard Worker len = strlen(states);
148*436bf2bcSAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
149*436bf2bcSAndroid Build Coastguard Worker if (!(val & (1 << i)))
150*436bf2bcSAndroid Build Coastguard Worker continue;
151*436bf2bcSAndroid Build Coastguard Worker
152*436bf2bcSAndroid Build Coastguard Worker if (found)
153*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, '|');
154*436bf2bcSAndroid Build Coastguard Worker
155*436bf2bcSAndroid Build Coastguard Worker found = 1;
156*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, states[i]);
157*436bf2bcSAndroid Build Coastguard Worker }
158*436bf2bcSAndroid Build Coastguard Worker
159*436bf2bcSAndroid Build Coastguard Worker if (!found)
160*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, 'R');
161*436bf2bcSAndroid Build Coastguard Worker }
162*436bf2bcSAndroid Build Coastguard Worker
write_and_save_comm(struct tep_format_field * field,struct tep_record * record,struct trace_seq * s,int pid)163*436bf2bcSAndroid Build Coastguard Worker static void write_and_save_comm(struct tep_format_field *field,
164*436bf2bcSAndroid Build Coastguard Worker struct tep_record *record,
165*436bf2bcSAndroid Build Coastguard Worker struct trace_seq *s, int pid)
166*436bf2bcSAndroid Build Coastguard Worker {
167*436bf2bcSAndroid Build Coastguard Worker const char *comm;
168*436bf2bcSAndroid Build Coastguard Worker int len;
169*436bf2bcSAndroid Build Coastguard Worker
170*436bf2bcSAndroid Build Coastguard Worker comm = (char *)(record->data + field->offset);
171*436bf2bcSAndroid Build Coastguard Worker len = s->len;
172*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, "%.*s",
173*436bf2bcSAndroid Build Coastguard Worker field->size, comm);
174*436bf2bcSAndroid Build Coastguard Worker
175*436bf2bcSAndroid Build Coastguard Worker /* make sure the comm has a \0 at the end. */
176*436bf2bcSAndroid Build Coastguard Worker trace_seq_terminate(s);
177*436bf2bcSAndroid Build Coastguard Worker comm = &s->buffer[len];
178*436bf2bcSAndroid Build Coastguard Worker
179*436bf2bcSAndroid Build Coastguard Worker /* Help out the comm to ids. This will handle dups */
180*436bf2bcSAndroid Build Coastguard Worker tep_register_comm(field->event->tep, comm, pid);
181*436bf2bcSAndroid Build Coastguard Worker }
182*436bf2bcSAndroid Build Coastguard Worker
sched_wakeup_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)183*436bf2bcSAndroid Build Coastguard Worker static int sched_wakeup_handler(struct trace_seq *s,
184*436bf2bcSAndroid Build Coastguard Worker struct tep_record *record,
185*436bf2bcSAndroid Build Coastguard Worker struct tep_event *event, void *context)
186*436bf2bcSAndroid Build Coastguard Worker {
187*436bf2bcSAndroid Build Coastguard Worker struct tep_format_field *field;
188*436bf2bcSAndroid Build Coastguard Worker unsigned long long val;
189*436bf2bcSAndroid Build Coastguard Worker
190*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "pid", record, &val, 1))
191*436bf2bcSAndroid Build Coastguard Worker return trace_seq_putc(s, '!');
192*436bf2bcSAndroid Build Coastguard Worker
193*436bf2bcSAndroid Build Coastguard Worker field = tep_find_any_field(event, "comm");
194*436bf2bcSAndroid Build Coastguard Worker if (field) {
195*436bf2bcSAndroid Build Coastguard Worker write_and_save_comm(field, record, s, val);
196*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, ':');
197*436bf2bcSAndroid Build Coastguard Worker }
198*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, "%lld", val);
199*436bf2bcSAndroid Build Coastguard Worker
200*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "prio", record, &val, 1) == 0)
201*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, " [%lld]", val);
202*436bf2bcSAndroid Build Coastguard Worker
203*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "success", record, &val, 0) == 0)
204*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, " success=%lld", val);
205*436bf2bcSAndroid Build Coastguard Worker
206*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
207*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, " CPU:%03llu", val);
208*436bf2bcSAndroid Build Coastguard Worker
209*436bf2bcSAndroid Build Coastguard Worker return 0;
210*436bf2bcSAndroid Build Coastguard Worker }
211*436bf2bcSAndroid Build Coastguard Worker
sched_switch_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)212*436bf2bcSAndroid Build Coastguard Worker static int sched_switch_handler(struct trace_seq *s,
213*436bf2bcSAndroid Build Coastguard Worker struct tep_record *record,
214*436bf2bcSAndroid Build Coastguard Worker struct tep_event *event, void *context)
215*436bf2bcSAndroid Build Coastguard Worker {
216*436bf2bcSAndroid Build Coastguard Worker struct tep_format_field *field;
217*436bf2bcSAndroid Build Coastguard Worker unsigned long long val;
218*436bf2bcSAndroid Build Coastguard Worker
219*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))
220*436bf2bcSAndroid Build Coastguard Worker return trace_seq_putc(s, '!');
221*436bf2bcSAndroid Build Coastguard Worker
222*436bf2bcSAndroid Build Coastguard Worker field = tep_find_any_field(event, "prev_comm");
223*436bf2bcSAndroid Build Coastguard Worker if (field) {
224*436bf2bcSAndroid Build Coastguard Worker write_and_save_comm(field, record, s, val);
225*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, ':');
226*436bf2bcSAndroid Build Coastguard Worker }
227*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, "%lld ", val);
228*436bf2bcSAndroid Build Coastguard Worker
229*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "prev_prio", record, &val, 1) == 0)
230*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, "[%d] ", (int) val);
231*436bf2bcSAndroid Build Coastguard Worker
232*436bf2bcSAndroid Build Coastguard Worker field = tep_find_any_field(event, "prev_state");
233*436bf2bcSAndroid Build Coastguard Worker write_state(s, field, record);
234*436bf2bcSAndroid Build Coastguard Worker
235*436bf2bcSAndroid Build Coastguard Worker trace_seq_puts(s, " ==> ");
236*436bf2bcSAndroid Build Coastguard Worker
237*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "next_pid", record, &val, 1))
238*436bf2bcSAndroid Build Coastguard Worker return trace_seq_putc(s, '!');
239*436bf2bcSAndroid Build Coastguard Worker
240*436bf2bcSAndroid Build Coastguard Worker field = tep_find_any_field(event, "next_comm");
241*436bf2bcSAndroid Build Coastguard Worker if (field) {
242*436bf2bcSAndroid Build Coastguard Worker write_and_save_comm(field, record, s, val);
243*436bf2bcSAndroid Build Coastguard Worker trace_seq_putc(s, ':');
244*436bf2bcSAndroid Build Coastguard Worker }
245*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, "%lld", val);
246*436bf2bcSAndroid Build Coastguard Worker
247*436bf2bcSAndroid Build Coastguard Worker if (tep_get_field_val(s, event, "next_prio", record, &val, 1) == 0)
248*436bf2bcSAndroid Build Coastguard Worker trace_seq_printf(s, " [%d]", (int) val);
249*436bf2bcSAndroid Build Coastguard Worker
250*436bf2bcSAndroid Build Coastguard Worker return 0;
251*436bf2bcSAndroid Build Coastguard Worker }
252*436bf2bcSAndroid Build Coastguard Worker
TEP_PLUGIN_LOADER(struct tep_handle * tep)253*436bf2bcSAndroid Build Coastguard Worker int TEP_PLUGIN_LOADER(struct tep_handle *tep)
254*436bf2bcSAndroid Build Coastguard Worker {
255*436bf2bcSAndroid Build Coastguard Worker tep_register_event_handler(tep, -1, "sched", "sched_switch",
256*436bf2bcSAndroid Build Coastguard Worker sched_switch_handler, NULL);
257*436bf2bcSAndroid Build Coastguard Worker
258*436bf2bcSAndroid Build Coastguard Worker tep_register_event_handler(tep, -1, "sched", "sched_wakeup",
259*436bf2bcSAndroid Build Coastguard Worker sched_wakeup_handler, NULL);
260*436bf2bcSAndroid Build Coastguard Worker
261*436bf2bcSAndroid Build Coastguard Worker tep_register_event_handler(tep, -1, "sched", "sched_wakeup_new",
262*436bf2bcSAndroid Build Coastguard Worker sched_wakeup_handler, NULL);
263*436bf2bcSAndroid Build Coastguard Worker return 0;
264*436bf2bcSAndroid Build Coastguard Worker }
265*436bf2bcSAndroid Build Coastguard Worker
TEP_PLUGIN_UNLOADER(struct tep_handle * tep)266*436bf2bcSAndroid Build Coastguard Worker void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
267*436bf2bcSAndroid Build Coastguard Worker {
268*436bf2bcSAndroid Build Coastguard Worker tep_unregister_event_handler(tep, -1, "sched", "sched_switch",
269*436bf2bcSAndroid Build Coastguard Worker sched_switch_handler, NULL);
270*436bf2bcSAndroid Build Coastguard Worker
271*436bf2bcSAndroid Build Coastguard Worker tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup",
272*436bf2bcSAndroid Build Coastguard Worker sched_wakeup_handler, NULL);
273*436bf2bcSAndroid Build Coastguard Worker
274*436bf2bcSAndroid Build Coastguard Worker tep_unregister_event_handler(tep, -1, "sched", "sched_wakeup_new",
275*436bf2bcSAndroid Build Coastguard Worker sched_wakeup_handler, NULL);
276*436bf2bcSAndroid Build Coastguard Worker }
277