xref: /OK3568_Linux_fs/kernel/tools/lib/traceevent/event-parse.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: LGPL-2.1
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  The parts for function graph printing was taken and modified from the
7*4882a593Smuzhiyun  *  Linux Kernel that were written by
8*4882a593Smuzhiyun  *    - Copyright (C) 2009  Frederic Weisbecker,
9*4882a593Smuzhiyun  *  Frederic Weisbecker gave his permission to relicense the code to
10*4882a593Smuzhiyun  *  the Lesser General Public License.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun #include <inttypes.h>
13*4882a593Smuzhiyun #include <stdio.h>
14*4882a593Smuzhiyun #include <stdlib.h>
15*4882a593Smuzhiyun #include <string.h>
16*4882a593Smuzhiyun #include <stdarg.h>
17*4882a593Smuzhiyun #include <ctype.h>
18*4882a593Smuzhiyun #include <errno.h>
19*4882a593Smuzhiyun #include <stdint.h>
20*4882a593Smuzhiyun #include <limits.h>
21*4882a593Smuzhiyun #include <linux/time64.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include <netinet/in.h>
24*4882a593Smuzhiyun #include "event-parse.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "event-parse-local.h"
27*4882a593Smuzhiyun #include "event-utils.h"
28*4882a593Smuzhiyun #include "trace-seq.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static const char *input_buf;
31*4882a593Smuzhiyun static unsigned long long input_buf_ptr;
32*4882a593Smuzhiyun static unsigned long long input_buf_siz;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun static int is_flag_field;
35*4882a593Smuzhiyun static int is_symbolic_field;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun static int show_warning = 1;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define do_warning(fmt, ...)				\
40*4882a593Smuzhiyun 	do {						\
41*4882a593Smuzhiyun 		if (show_warning)			\
42*4882a593Smuzhiyun 			warning(fmt, ##__VA_ARGS__);	\
43*4882a593Smuzhiyun 	} while (0)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define do_warning_event(event, fmt, ...)			\
46*4882a593Smuzhiyun 	do {							\
47*4882a593Smuzhiyun 		if (!show_warning)				\
48*4882a593Smuzhiyun 			continue;				\
49*4882a593Smuzhiyun 								\
50*4882a593Smuzhiyun 		if (event)					\
51*4882a593Smuzhiyun 			warning("[%s:%s] " fmt, event->system,	\
52*4882a593Smuzhiyun 				event->name, ##__VA_ARGS__);	\
53*4882a593Smuzhiyun 		else						\
54*4882a593Smuzhiyun 			warning(fmt, ##__VA_ARGS__);		\
55*4882a593Smuzhiyun 	} while (0)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun  * init_input_buf - init buffer for parsing
59*4882a593Smuzhiyun  * @buf: buffer to parse
60*4882a593Smuzhiyun  * @size: the size of the buffer
61*4882a593Smuzhiyun  *
62*4882a593Smuzhiyun  * Initializes the internal buffer that tep_read_token() will parse.
63*4882a593Smuzhiyun  */
init_input_buf(const char * buf,unsigned long long size)64*4882a593Smuzhiyun __hidden void init_input_buf(const char *buf, unsigned long long size)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	input_buf = buf;
67*4882a593Smuzhiyun 	input_buf_siz = size;
68*4882a593Smuzhiyun 	input_buf_ptr = 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
get_input_buf(void)71*4882a593Smuzhiyun __hidden const char *get_input_buf(void)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	return input_buf;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
get_input_buf_ptr(void)76*4882a593Smuzhiyun __hidden unsigned long long get_input_buf_ptr(void)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	return input_buf_ptr;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun struct event_handler {
82*4882a593Smuzhiyun 	struct event_handler		*next;
83*4882a593Smuzhiyun 	int				id;
84*4882a593Smuzhiyun 	const char			*sys_name;
85*4882a593Smuzhiyun 	const char			*event_name;
86*4882a593Smuzhiyun 	tep_event_handler_func		func;
87*4882a593Smuzhiyun 	void				*context;
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun struct func_params {
91*4882a593Smuzhiyun 	struct func_params	*next;
92*4882a593Smuzhiyun 	enum tep_func_arg_type	type;
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun struct tep_function_handler {
96*4882a593Smuzhiyun 	struct tep_function_handler	*next;
97*4882a593Smuzhiyun 	enum tep_func_arg_type		ret_type;
98*4882a593Smuzhiyun 	char				*name;
99*4882a593Smuzhiyun 	tep_func_handler		func;
100*4882a593Smuzhiyun 	struct func_params		*params;
101*4882a593Smuzhiyun 	int				nr_args;
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun static unsigned long long
105*4882a593Smuzhiyun process_defined_func(struct trace_seq *s, void *data, int size,
106*4882a593Smuzhiyun 		     struct tep_event *event, struct tep_print_arg *arg);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static void free_func_handle(struct tep_function_handler *func);
109*4882a593Smuzhiyun 
breakpoint(void)110*4882a593Smuzhiyun void breakpoint(void)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	static int x;
113*4882a593Smuzhiyun 	x++;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
alloc_arg(void)116*4882a593Smuzhiyun static struct tep_print_arg *alloc_arg(void)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	return calloc(1, sizeof(struct tep_print_arg));
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun struct tep_cmdline {
122*4882a593Smuzhiyun 	char *comm;
123*4882a593Smuzhiyun 	int pid;
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun 
cmdline_cmp(const void * a,const void * b)126*4882a593Smuzhiyun static int cmdline_cmp(const void *a, const void *b)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	const struct tep_cmdline *ca = a;
129*4882a593Smuzhiyun 	const struct tep_cmdline *cb = b;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (ca->pid < cb->pid)
132*4882a593Smuzhiyun 		return -1;
133*4882a593Smuzhiyun 	if (ca->pid > cb->pid)
134*4882a593Smuzhiyun 		return 1;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* Looking for where to place the key */
cmdline_slot_cmp(const void * a,const void * b)140*4882a593Smuzhiyun static int cmdline_slot_cmp(const void *a, const void *b)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	const struct tep_cmdline *ca = a;
143*4882a593Smuzhiyun 	const struct tep_cmdline *cb = b;
144*4882a593Smuzhiyun 	const struct tep_cmdline *cb1 = cb + 1;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if (ca->pid < cb->pid)
147*4882a593Smuzhiyun 		return -1;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (ca->pid > cb->pid) {
150*4882a593Smuzhiyun 		if (ca->pid <= cb1->pid)
151*4882a593Smuzhiyun 			return 0;
152*4882a593Smuzhiyun 		return 1;
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun struct cmdline_list {
159*4882a593Smuzhiyun 	struct cmdline_list	*next;
160*4882a593Smuzhiyun 	char			*comm;
161*4882a593Smuzhiyun 	int			pid;
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun 
cmdline_init(struct tep_handle * tep)164*4882a593Smuzhiyun static int cmdline_init(struct tep_handle *tep)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct cmdline_list *cmdlist = tep->cmdlist;
167*4882a593Smuzhiyun 	struct cmdline_list *item;
168*4882a593Smuzhiyun 	struct tep_cmdline *cmdlines;
169*4882a593Smuzhiyun 	int i;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	cmdlines = malloc(sizeof(*cmdlines) * tep->cmdline_count);
172*4882a593Smuzhiyun 	if (!cmdlines)
173*4882a593Smuzhiyun 		return -1;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	i = 0;
176*4882a593Smuzhiyun 	while (cmdlist) {
177*4882a593Smuzhiyun 		cmdlines[i].pid = cmdlist->pid;
178*4882a593Smuzhiyun 		cmdlines[i].comm = cmdlist->comm;
179*4882a593Smuzhiyun 		i++;
180*4882a593Smuzhiyun 		item = cmdlist;
181*4882a593Smuzhiyun 		cmdlist = cmdlist->next;
182*4882a593Smuzhiyun 		free(item);
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	tep->cmdlines = cmdlines;
188*4882a593Smuzhiyun 	tep->cmdlist = NULL;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return 0;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
find_cmdline(struct tep_handle * tep,int pid)193*4882a593Smuzhiyun static const char *find_cmdline(struct tep_handle *tep, int pid)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	const struct tep_cmdline *comm;
196*4882a593Smuzhiyun 	struct tep_cmdline key;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (!pid)
199*4882a593Smuzhiyun 		return "<idle>";
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (!tep->cmdlines && cmdline_init(tep))
202*4882a593Smuzhiyun 		return "<not enough memory for cmdlines!>";
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	key.pid = pid;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	comm = bsearch(&key, tep->cmdlines, tep->cmdline_count,
207*4882a593Smuzhiyun 		       sizeof(*tep->cmdlines), cmdline_cmp);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (comm)
210*4882a593Smuzhiyun 		return comm->comm;
211*4882a593Smuzhiyun 	return "<...>";
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /**
215*4882a593Smuzhiyun  * tep_is_pid_registered - return if a pid has a cmdline registered
216*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
217*4882a593Smuzhiyun  * @pid: The pid to check if it has a cmdline registered with.
218*4882a593Smuzhiyun  *
219*4882a593Smuzhiyun  * Returns true if the pid has a cmdline mapped to it
220*4882a593Smuzhiyun  * false otherwise.
221*4882a593Smuzhiyun  */
tep_is_pid_registered(struct tep_handle * tep,int pid)222*4882a593Smuzhiyun bool tep_is_pid_registered(struct tep_handle *tep, int pid)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	const struct tep_cmdline *comm;
225*4882a593Smuzhiyun 	struct tep_cmdline key;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	if (!pid)
228*4882a593Smuzhiyun 		return true;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (!tep->cmdlines && cmdline_init(tep))
231*4882a593Smuzhiyun 		return false;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	key.pid = pid;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	comm = bsearch(&key, tep->cmdlines, tep->cmdline_count,
236*4882a593Smuzhiyun 		       sizeof(*tep->cmdlines), cmdline_cmp);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (comm)
239*4882a593Smuzhiyun 		return true;
240*4882a593Smuzhiyun 	return false;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun /*
244*4882a593Smuzhiyun  * If the command lines have been converted to an array, then
245*4882a593Smuzhiyun  * we must add this pid. This is much slower than when cmdlines
246*4882a593Smuzhiyun  * are added before the array is initialized.
247*4882a593Smuzhiyun  */
add_new_comm(struct tep_handle * tep,const char * comm,int pid,bool override)248*4882a593Smuzhiyun static int add_new_comm(struct tep_handle *tep,
249*4882a593Smuzhiyun 			const char *comm, int pid, bool override)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct tep_cmdline *cmdlines = tep->cmdlines;
252*4882a593Smuzhiyun 	struct tep_cmdline *cmdline;
253*4882a593Smuzhiyun 	struct tep_cmdline key;
254*4882a593Smuzhiyun 	char *new_comm;
255*4882a593Smuzhiyun 	int cnt;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	if (!pid)
258*4882a593Smuzhiyun 		return 0;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* avoid duplicates */
261*4882a593Smuzhiyun 	key.pid = pid;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count,
264*4882a593Smuzhiyun 			  sizeof(*tep->cmdlines), cmdline_cmp);
265*4882a593Smuzhiyun 	if (cmdline) {
266*4882a593Smuzhiyun 		if (!override) {
267*4882a593Smuzhiyun 			errno = EEXIST;
268*4882a593Smuzhiyun 			return -1;
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 		new_comm = strdup(comm);
271*4882a593Smuzhiyun 		if (!new_comm) {
272*4882a593Smuzhiyun 			errno = ENOMEM;
273*4882a593Smuzhiyun 			return -1;
274*4882a593Smuzhiyun 		}
275*4882a593Smuzhiyun 		free(cmdline->comm);
276*4882a593Smuzhiyun 		cmdline->comm = new_comm;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		return 0;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (tep->cmdline_count + 1));
282*4882a593Smuzhiyun 	if (!cmdlines) {
283*4882a593Smuzhiyun 		errno = ENOMEM;
284*4882a593Smuzhiyun 		return -1;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 	tep->cmdlines = cmdlines;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	key.comm = strdup(comm);
289*4882a593Smuzhiyun 	if (!key.comm) {
290*4882a593Smuzhiyun 		errno = ENOMEM;
291*4882a593Smuzhiyun 		return -1;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (!tep->cmdline_count) {
295*4882a593Smuzhiyun 		/* no entries yet */
296*4882a593Smuzhiyun 		tep->cmdlines[0] = key;
297*4882a593Smuzhiyun 		tep->cmdline_count++;
298*4882a593Smuzhiyun 		return 0;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/* Now find where we want to store the new cmdline */
302*4882a593Smuzhiyun 	cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1,
303*4882a593Smuzhiyun 			  sizeof(*tep->cmdlines), cmdline_slot_cmp);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	cnt = tep->cmdline_count;
306*4882a593Smuzhiyun 	if (cmdline) {
307*4882a593Smuzhiyun 		/* cmdline points to the one before the spot we want */
308*4882a593Smuzhiyun 		cmdline++;
309*4882a593Smuzhiyun 		cnt -= cmdline - tep->cmdlines;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	} else {
312*4882a593Smuzhiyun 		/* The new entry is either before or after the list */
313*4882a593Smuzhiyun 		if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) {
314*4882a593Smuzhiyun 			tep->cmdlines[tep->cmdline_count++] = key;
315*4882a593Smuzhiyun 			return 0;
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 		cmdline = &tep->cmdlines[0];
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 	memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline)));
320*4882a593Smuzhiyun 	*cmdline = key;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	tep->cmdline_count++;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	return 0;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
_tep_register_comm(struct tep_handle * tep,const char * comm,int pid,bool override)327*4882a593Smuzhiyun static int _tep_register_comm(struct tep_handle *tep,
328*4882a593Smuzhiyun 			      const char *comm, int pid, bool override)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	struct cmdline_list *item;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (tep->cmdlines)
333*4882a593Smuzhiyun 		return add_new_comm(tep, comm, pid, override);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	item = malloc(sizeof(*item));
336*4882a593Smuzhiyun 	if (!item)
337*4882a593Smuzhiyun 		return -1;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (comm)
340*4882a593Smuzhiyun 		item->comm = strdup(comm);
341*4882a593Smuzhiyun 	else
342*4882a593Smuzhiyun 		item->comm = strdup("<...>");
343*4882a593Smuzhiyun 	if (!item->comm) {
344*4882a593Smuzhiyun 		free(item);
345*4882a593Smuzhiyun 		return -1;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 	item->pid = pid;
348*4882a593Smuzhiyun 	item->next = tep->cmdlist;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	tep->cmdlist = item;
351*4882a593Smuzhiyun 	tep->cmdline_count++;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return 0;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun /**
357*4882a593Smuzhiyun  * tep_register_comm - register a pid / comm mapping
358*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
359*4882a593Smuzhiyun  * @comm: the command line to register
360*4882a593Smuzhiyun  * @pid: the pid to map the command line to
361*4882a593Smuzhiyun  *
362*4882a593Smuzhiyun  * This adds a mapping to search for command line names with
363*4882a593Smuzhiyun  * a given pid. The comm is duplicated. If a command with the same pid
364*4882a593Smuzhiyun  * already exist, -1 is returned and errno is set to EEXIST
365*4882a593Smuzhiyun  */
tep_register_comm(struct tep_handle * tep,const char * comm,int pid)366*4882a593Smuzhiyun int tep_register_comm(struct tep_handle *tep, const char *comm, int pid)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	return _tep_register_comm(tep, comm, pid, false);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun /**
372*4882a593Smuzhiyun  * tep_override_comm - register a pid / comm mapping
373*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
374*4882a593Smuzhiyun  * @comm: the command line to register
375*4882a593Smuzhiyun  * @pid: the pid to map the command line to
376*4882a593Smuzhiyun  *
377*4882a593Smuzhiyun  * This adds a mapping to search for command line names with
378*4882a593Smuzhiyun  * a given pid. The comm is duplicated. If a command with the same pid
379*4882a593Smuzhiyun  * already exist, the command string is udapted with the new one
380*4882a593Smuzhiyun  */
tep_override_comm(struct tep_handle * tep,const char * comm,int pid)381*4882a593Smuzhiyun int tep_override_comm(struct tep_handle *tep, const char *comm, int pid)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	if (!tep->cmdlines && cmdline_init(tep)) {
384*4882a593Smuzhiyun 		errno = ENOMEM;
385*4882a593Smuzhiyun 		return -1;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 	return _tep_register_comm(tep, comm, pid, true);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun struct func_map {
391*4882a593Smuzhiyun 	unsigned long long		addr;
392*4882a593Smuzhiyun 	char				*func;
393*4882a593Smuzhiyun 	char				*mod;
394*4882a593Smuzhiyun };
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun struct func_list {
397*4882a593Smuzhiyun 	struct func_list	*next;
398*4882a593Smuzhiyun 	unsigned long long	addr;
399*4882a593Smuzhiyun 	char			*func;
400*4882a593Smuzhiyun 	char			*mod;
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun 
func_cmp(const void * a,const void * b)403*4882a593Smuzhiyun static int func_cmp(const void *a, const void *b)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	const struct func_map *fa = a;
406*4882a593Smuzhiyun 	const struct func_map *fb = b;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (fa->addr < fb->addr)
409*4882a593Smuzhiyun 		return -1;
410*4882a593Smuzhiyun 	if (fa->addr > fb->addr)
411*4882a593Smuzhiyun 		return 1;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	return 0;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun  * We are searching for a record in between, not an exact
418*4882a593Smuzhiyun  * match.
419*4882a593Smuzhiyun  */
func_bcmp(const void * a,const void * b)420*4882a593Smuzhiyun static int func_bcmp(const void *a, const void *b)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	const struct func_map *fa = a;
423*4882a593Smuzhiyun 	const struct func_map *fb = b;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if ((fa->addr == fb->addr) ||
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	    (fa->addr > fb->addr &&
428*4882a593Smuzhiyun 	     fa->addr < (fb+1)->addr))
429*4882a593Smuzhiyun 		return 0;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (fa->addr < fb->addr)
432*4882a593Smuzhiyun 		return -1;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	return 1;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
func_map_init(struct tep_handle * tep)437*4882a593Smuzhiyun static int func_map_init(struct tep_handle *tep)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct func_list *funclist;
440*4882a593Smuzhiyun 	struct func_list *item;
441*4882a593Smuzhiyun 	struct func_map *func_map;
442*4882a593Smuzhiyun 	int i;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	func_map = malloc(sizeof(*func_map) * (tep->func_count + 1));
445*4882a593Smuzhiyun 	if (!func_map)
446*4882a593Smuzhiyun 		return -1;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	funclist = tep->funclist;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	i = 0;
451*4882a593Smuzhiyun 	while (funclist) {
452*4882a593Smuzhiyun 		func_map[i].func = funclist->func;
453*4882a593Smuzhiyun 		func_map[i].addr = funclist->addr;
454*4882a593Smuzhiyun 		func_map[i].mod = funclist->mod;
455*4882a593Smuzhiyun 		i++;
456*4882a593Smuzhiyun 		item = funclist;
457*4882a593Smuzhiyun 		funclist = funclist->next;
458*4882a593Smuzhiyun 		free(item);
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	qsort(func_map, tep->func_count, sizeof(*func_map), func_cmp);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/*
464*4882a593Smuzhiyun 	 * Add a special record at the end.
465*4882a593Smuzhiyun 	 */
466*4882a593Smuzhiyun 	func_map[tep->func_count].func = NULL;
467*4882a593Smuzhiyun 	func_map[tep->func_count].addr = 0;
468*4882a593Smuzhiyun 	func_map[tep->func_count].mod = NULL;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	tep->func_map = func_map;
471*4882a593Smuzhiyun 	tep->funclist = NULL;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun static struct func_map *
__find_func(struct tep_handle * tep,unsigned long long addr)477*4882a593Smuzhiyun __find_func(struct tep_handle *tep, unsigned long long addr)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	struct func_map *func;
480*4882a593Smuzhiyun 	struct func_map key;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	if (!tep->func_map)
483*4882a593Smuzhiyun 		func_map_init(tep);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	key.addr = addr;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	func = bsearch(&key, tep->func_map, tep->func_count,
488*4882a593Smuzhiyun 		       sizeof(*tep->func_map), func_bcmp);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	return func;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun struct func_resolver {
494*4882a593Smuzhiyun 	tep_func_resolver_t	*func;
495*4882a593Smuzhiyun 	void			*priv;
496*4882a593Smuzhiyun 	struct func_map		map;
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun /**
500*4882a593Smuzhiyun  * tep_set_function_resolver - set an alternative function resolver
501*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
502*4882a593Smuzhiyun  * @resolver: function to be used
503*4882a593Smuzhiyun  * @priv: resolver function private state.
504*4882a593Smuzhiyun  *
505*4882a593Smuzhiyun  * Some tools may have already a way to resolve kernel functions, allow them to
506*4882a593Smuzhiyun  * keep using it instead of duplicating all the entries inside tep->funclist.
507*4882a593Smuzhiyun  */
tep_set_function_resolver(struct tep_handle * tep,tep_func_resolver_t * func,void * priv)508*4882a593Smuzhiyun int tep_set_function_resolver(struct tep_handle *tep,
509*4882a593Smuzhiyun 			      tep_func_resolver_t *func, void *priv)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct func_resolver *resolver = malloc(sizeof(*resolver));
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	if (resolver == NULL)
514*4882a593Smuzhiyun 		return -1;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	resolver->func = func;
517*4882a593Smuzhiyun 	resolver->priv = priv;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	free(tep->func_resolver);
520*4882a593Smuzhiyun 	tep->func_resolver = resolver;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	return 0;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun /**
526*4882a593Smuzhiyun  * tep_reset_function_resolver - reset alternative function resolver
527*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
528*4882a593Smuzhiyun  *
529*4882a593Smuzhiyun  * Stop using whatever alternative resolver was set, use the default
530*4882a593Smuzhiyun  * one instead.
531*4882a593Smuzhiyun  */
tep_reset_function_resolver(struct tep_handle * tep)532*4882a593Smuzhiyun void tep_reset_function_resolver(struct tep_handle *tep)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	free(tep->func_resolver);
535*4882a593Smuzhiyun 	tep->func_resolver = NULL;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun static struct func_map *
find_func(struct tep_handle * tep,unsigned long long addr)539*4882a593Smuzhiyun find_func(struct tep_handle *tep, unsigned long long addr)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	struct func_map *map;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	if (!tep->func_resolver)
544*4882a593Smuzhiyun 		return __find_func(tep, addr);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	map = &tep->func_resolver->map;
547*4882a593Smuzhiyun 	map->mod  = NULL;
548*4882a593Smuzhiyun 	map->addr = addr;
549*4882a593Smuzhiyun 	map->func = tep->func_resolver->func(tep->func_resolver->priv,
550*4882a593Smuzhiyun 					     &map->addr, &map->mod);
551*4882a593Smuzhiyun 	if (map->func == NULL)
552*4882a593Smuzhiyun 		return NULL;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return map;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun /**
558*4882a593Smuzhiyun  * tep_find_function - find a function by a given address
559*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
560*4882a593Smuzhiyun  * @addr: the address to find the function with
561*4882a593Smuzhiyun  *
562*4882a593Smuzhiyun  * Returns a pointer to the function stored that has the given
563*4882a593Smuzhiyun  * address. Note, the address does not have to be exact, it
564*4882a593Smuzhiyun  * will select the function that would contain the address.
565*4882a593Smuzhiyun  */
tep_find_function(struct tep_handle * tep,unsigned long long addr)566*4882a593Smuzhiyun const char *tep_find_function(struct tep_handle *tep, unsigned long long addr)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun 	struct func_map *map;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	map = find_func(tep, addr);
571*4882a593Smuzhiyun 	if (!map)
572*4882a593Smuzhiyun 		return NULL;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	return map->func;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun /**
578*4882a593Smuzhiyun  * tep_find_function_address - find a function address by a given address
579*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
580*4882a593Smuzhiyun  * @addr: the address to find the function with
581*4882a593Smuzhiyun  *
582*4882a593Smuzhiyun  * Returns the address the function starts at. This can be used in
583*4882a593Smuzhiyun  * conjunction with tep_find_function to print both the function
584*4882a593Smuzhiyun  * name and the function offset.
585*4882a593Smuzhiyun  */
586*4882a593Smuzhiyun unsigned long long
tep_find_function_address(struct tep_handle * tep,unsigned long long addr)587*4882a593Smuzhiyun tep_find_function_address(struct tep_handle *tep, unsigned long long addr)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct func_map *map;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	map = find_func(tep, addr);
592*4882a593Smuzhiyun 	if (!map)
593*4882a593Smuzhiyun 		return 0;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	return map->addr;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun /**
599*4882a593Smuzhiyun  * tep_register_function - register a function with a given address
600*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
601*4882a593Smuzhiyun  * @function: the function name to register
602*4882a593Smuzhiyun  * @addr: the address the function starts at
603*4882a593Smuzhiyun  * @mod: the kernel module the function may be in (NULL for none)
604*4882a593Smuzhiyun  *
605*4882a593Smuzhiyun  * This registers a function name with an address and module.
606*4882a593Smuzhiyun  * The @func passed in is duplicated.
607*4882a593Smuzhiyun  */
tep_register_function(struct tep_handle * tep,char * func,unsigned long long addr,char * mod)608*4882a593Smuzhiyun int tep_register_function(struct tep_handle *tep, char *func,
609*4882a593Smuzhiyun 			  unsigned long long addr, char *mod)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	struct func_list *item = malloc(sizeof(*item));
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	if (!item)
614*4882a593Smuzhiyun 		return -1;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	item->next = tep->funclist;
617*4882a593Smuzhiyun 	item->func = strdup(func);
618*4882a593Smuzhiyun 	if (!item->func)
619*4882a593Smuzhiyun 		goto out_free;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	if (mod) {
622*4882a593Smuzhiyun 		item->mod = strdup(mod);
623*4882a593Smuzhiyun 		if (!item->mod)
624*4882a593Smuzhiyun 			goto out_free_func;
625*4882a593Smuzhiyun 	} else
626*4882a593Smuzhiyun 		item->mod = NULL;
627*4882a593Smuzhiyun 	item->addr = addr;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	tep->funclist = item;
630*4882a593Smuzhiyun 	tep->func_count++;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	return 0;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun out_free_func:
635*4882a593Smuzhiyun 	free(item->func);
636*4882a593Smuzhiyun 	item->func = NULL;
637*4882a593Smuzhiyun out_free:
638*4882a593Smuzhiyun 	free(item);
639*4882a593Smuzhiyun 	errno = ENOMEM;
640*4882a593Smuzhiyun 	return -1;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun /**
644*4882a593Smuzhiyun  * tep_print_funcs - print out the stored functions
645*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
646*4882a593Smuzhiyun  *
647*4882a593Smuzhiyun  * This prints out the stored functions.
648*4882a593Smuzhiyun  */
tep_print_funcs(struct tep_handle * tep)649*4882a593Smuzhiyun void tep_print_funcs(struct tep_handle *tep)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	int i;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	if (!tep->func_map)
654*4882a593Smuzhiyun 		func_map_init(tep);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	for (i = 0; i < (int)tep->func_count; i++) {
657*4882a593Smuzhiyun 		printf("%016llx %s",
658*4882a593Smuzhiyun 		       tep->func_map[i].addr,
659*4882a593Smuzhiyun 		       tep->func_map[i].func);
660*4882a593Smuzhiyun 		if (tep->func_map[i].mod)
661*4882a593Smuzhiyun 			printf(" [%s]\n", tep->func_map[i].mod);
662*4882a593Smuzhiyun 		else
663*4882a593Smuzhiyun 			printf("\n");
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun struct printk_map {
668*4882a593Smuzhiyun 	unsigned long long		addr;
669*4882a593Smuzhiyun 	char				*printk;
670*4882a593Smuzhiyun };
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun struct printk_list {
673*4882a593Smuzhiyun 	struct printk_list	*next;
674*4882a593Smuzhiyun 	unsigned long long	addr;
675*4882a593Smuzhiyun 	char			*printk;
676*4882a593Smuzhiyun };
677*4882a593Smuzhiyun 
printk_cmp(const void * a,const void * b)678*4882a593Smuzhiyun static int printk_cmp(const void *a, const void *b)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	const struct printk_map *pa = a;
681*4882a593Smuzhiyun 	const struct printk_map *pb = b;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (pa->addr < pb->addr)
684*4882a593Smuzhiyun 		return -1;
685*4882a593Smuzhiyun 	if (pa->addr > pb->addr)
686*4882a593Smuzhiyun 		return 1;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
printk_map_init(struct tep_handle * tep)691*4882a593Smuzhiyun static int printk_map_init(struct tep_handle *tep)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun 	struct printk_list *printklist;
694*4882a593Smuzhiyun 	struct printk_list *item;
695*4882a593Smuzhiyun 	struct printk_map *printk_map;
696*4882a593Smuzhiyun 	int i;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	printk_map = malloc(sizeof(*printk_map) * (tep->printk_count + 1));
699*4882a593Smuzhiyun 	if (!printk_map)
700*4882a593Smuzhiyun 		return -1;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	printklist = tep->printklist;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	i = 0;
705*4882a593Smuzhiyun 	while (printklist) {
706*4882a593Smuzhiyun 		printk_map[i].printk = printklist->printk;
707*4882a593Smuzhiyun 		printk_map[i].addr = printklist->addr;
708*4882a593Smuzhiyun 		i++;
709*4882a593Smuzhiyun 		item = printklist;
710*4882a593Smuzhiyun 		printklist = printklist->next;
711*4882a593Smuzhiyun 		free(item);
712*4882a593Smuzhiyun 	}
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	qsort(printk_map, tep->printk_count, sizeof(*printk_map), printk_cmp);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	tep->printk_map = printk_map;
717*4882a593Smuzhiyun 	tep->printklist = NULL;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	return 0;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun static struct printk_map *
find_printk(struct tep_handle * tep,unsigned long long addr)723*4882a593Smuzhiyun find_printk(struct tep_handle *tep, unsigned long long addr)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun 	struct printk_map *printk;
726*4882a593Smuzhiyun 	struct printk_map key;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	if (!tep->printk_map && printk_map_init(tep))
729*4882a593Smuzhiyun 		return NULL;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	key.addr = addr;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	printk = bsearch(&key, tep->printk_map, tep->printk_count,
734*4882a593Smuzhiyun 			 sizeof(*tep->printk_map), printk_cmp);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	return printk;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun /**
740*4882a593Smuzhiyun  * tep_register_print_string - register a string by its address
741*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
742*4882a593Smuzhiyun  * @fmt: the string format to register
743*4882a593Smuzhiyun  * @addr: the address the string was located at
744*4882a593Smuzhiyun  *
745*4882a593Smuzhiyun  * This registers a string by the address it was stored in the kernel.
746*4882a593Smuzhiyun  * The @fmt passed in is duplicated.
747*4882a593Smuzhiyun  */
tep_register_print_string(struct tep_handle * tep,const char * fmt,unsigned long long addr)748*4882a593Smuzhiyun int tep_register_print_string(struct tep_handle *tep, const char *fmt,
749*4882a593Smuzhiyun 			      unsigned long long addr)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun 	struct printk_list *item = malloc(sizeof(*item));
752*4882a593Smuzhiyun 	char *p;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	if (!item)
755*4882a593Smuzhiyun 		return -1;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	item->next = tep->printklist;
758*4882a593Smuzhiyun 	item->addr = addr;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	/* Strip off quotes and '\n' from the end */
761*4882a593Smuzhiyun 	if (fmt[0] == '"')
762*4882a593Smuzhiyun 		fmt++;
763*4882a593Smuzhiyun 	item->printk = strdup(fmt);
764*4882a593Smuzhiyun 	if (!item->printk)
765*4882a593Smuzhiyun 		goto out_free;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	p = item->printk + strlen(item->printk) - 1;
768*4882a593Smuzhiyun 	if (*p == '"')
769*4882a593Smuzhiyun 		*p = 0;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	p -= 2;
772*4882a593Smuzhiyun 	if (strcmp(p, "\\n") == 0)
773*4882a593Smuzhiyun 		*p = 0;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	tep->printklist = item;
776*4882a593Smuzhiyun 	tep->printk_count++;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	return 0;
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun out_free:
781*4882a593Smuzhiyun 	free(item);
782*4882a593Smuzhiyun 	errno = ENOMEM;
783*4882a593Smuzhiyun 	return -1;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun /**
787*4882a593Smuzhiyun  * tep_print_printk - print out the stored strings
788*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
789*4882a593Smuzhiyun  *
790*4882a593Smuzhiyun  * This prints the string formats that were stored.
791*4882a593Smuzhiyun  */
tep_print_printk(struct tep_handle * tep)792*4882a593Smuzhiyun void tep_print_printk(struct tep_handle *tep)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun 	int i;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	if (!tep->printk_map)
797*4882a593Smuzhiyun 		printk_map_init(tep);
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	for (i = 0; i < (int)tep->printk_count; i++) {
800*4882a593Smuzhiyun 		printf("%016llx %s\n",
801*4882a593Smuzhiyun 		       tep->printk_map[i].addr,
802*4882a593Smuzhiyun 		       tep->printk_map[i].printk);
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun 
alloc_event(void)806*4882a593Smuzhiyun static struct tep_event *alloc_event(void)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	return calloc(1, sizeof(struct tep_event));
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun 
add_event(struct tep_handle * tep,struct tep_event * event)811*4882a593Smuzhiyun static int add_event(struct tep_handle *tep, struct tep_event *event)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun 	int i;
814*4882a593Smuzhiyun 	struct tep_event **events = realloc(tep->events, sizeof(event) *
815*4882a593Smuzhiyun 					    (tep->nr_events + 1));
816*4882a593Smuzhiyun 	if (!events)
817*4882a593Smuzhiyun 		return -1;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	tep->events = events;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	for (i = 0; i < tep->nr_events; i++) {
822*4882a593Smuzhiyun 		if (tep->events[i]->id > event->id)
823*4882a593Smuzhiyun 			break;
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun 	if (i < tep->nr_events)
826*4882a593Smuzhiyun 		memmove(&tep->events[i + 1],
827*4882a593Smuzhiyun 			&tep->events[i],
828*4882a593Smuzhiyun 			sizeof(event) * (tep->nr_events - i));
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	tep->events[i] = event;
831*4882a593Smuzhiyun 	tep->nr_events++;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	event->tep = tep;
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	return 0;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
event_item_type(enum tep_event_type type)838*4882a593Smuzhiyun static int event_item_type(enum tep_event_type type)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun 	switch (type) {
841*4882a593Smuzhiyun 	case TEP_EVENT_ITEM ... TEP_EVENT_SQUOTE:
842*4882a593Smuzhiyun 		return 1;
843*4882a593Smuzhiyun 	case TEP_EVENT_ERROR ... TEP_EVENT_DELIM:
844*4882a593Smuzhiyun 	default:
845*4882a593Smuzhiyun 		return 0;
846*4882a593Smuzhiyun 	}
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun 
free_flag_sym(struct tep_print_flag_sym * fsym)849*4882a593Smuzhiyun static void free_flag_sym(struct tep_print_flag_sym *fsym)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun 	struct tep_print_flag_sym *next;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	while (fsym) {
854*4882a593Smuzhiyun 		next = fsym->next;
855*4882a593Smuzhiyun 		free(fsym->value);
856*4882a593Smuzhiyun 		free(fsym->str);
857*4882a593Smuzhiyun 		free(fsym);
858*4882a593Smuzhiyun 		fsym = next;
859*4882a593Smuzhiyun 	}
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun 
free_arg(struct tep_print_arg * arg)862*4882a593Smuzhiyun static void free_arg(struct tep_print_arg *arg)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun 	struct tep_print_arg *farg;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	if (!arg)
867*4882a593Smuzhiyun 		return;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	switch (arg->type) {
870*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
871*4882a593Smuzhiyun 		free(arg->atom.atom);
872*4882a593Smuzhiyun 		break;
873*4882a593Smuzhiyun 	case TEP_PRINT_FIELD:
874*4882a593Smuzhiyun 		free(arg->field.name);
875*4882a593Smuzhiyun 		break;
876*4882a593Smuzhiyun 	case TEP_PRINT_FLAGS:
877*4882a593Smuzhiyun 		free_arg(arg->flags.field);
878*4882a593Smuzhiyun 		free(arg->flags.delim);
879*4882a593Smuzhiyun 		free_flag_sym(arg->flags.flags);
880*4882a593Smuzhiyun 		break;
881*4882a593Smuzhiyun 	case TEP_PRINT_SYMBOL:
882*4882a593Smuzhiyun 		free_arg(arg->symbol.field);
883*4882a593Smuzhiyun 		free_flag_sym(arg->symbol.symbols);
884*4882a593Smuzhiyun 		break;
885*4882a593Smuzhiyun 	case TEP_PRINT_HEX:
886*4882a593Smuzhiyun 	case TEP_PRINT_HEX_STR:
887*4882a593Smuzhiyun 		free_arg(arg->hex.field);
888*4882a593Smuzhiyun 		free_arg(arg->hex.size);
889*4882a593Smuzhiyun 		break;
890*4882a593Smuzhiyun 	case TEP_PRINT_INT_ARRAY:
891*4882a593Smuzhiyun 		free_arg(arg->int_array.field);
892*4882a593Smuzhiyun 		free_arg(arg->int_array.count);
893*4882a593Smuzhiyun 		free_arg(arg->int_array.el_size);
894*4882a593Smuzhiyun 		break;
895*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
896*4882a593Smuzhiyun 		free(arg->typecast.type);
897*4882a593Smuzhiyun 		free_arg(arg->typecast.item);
898*4882a593Smuzhiyun 		break;
899*4882a593Smuzhiyun 	case TEP_PRINT_STRING:
900*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
901*4882a593Smuzhiyun 		free(arg->string.string);
902*4882a593Smuzhiyun 		break;
903*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK:
904*4882a593Smuzhiyun 		free(arg->bitmask.bitmask);
905*4882a593Smuzhiyun 		break;
906*4882a593Smuzhiyun 	case TEP_PRINT_DYNAMIC_ARRAY:
907*4882a593Smuzhiyun 	case TEP_PRINT_DYNAMIC_ARRAY_LEN:
908*4882a593Smuzhiyun 		free(arg->dynarray.index);
909*4882a593Smuzhiyun 		break;
910*4882a593Smuzhiyun 	case TEP_PRINT_OP:
911*4882a593Smuzhiyun 		free(arg->op.op);
912*4882a593Smuzhiyun 		free_arg(arg->op.left);
913*4882a593Smuzhiyun 		free_arg(arg->op.right);
914*4882a593Smuzhiyun 		break;
915*4882a593Smuzhiyun 	case TEP_PRINT_FUNC:
916*4882a593Smuzhiyun 		while (arg->func.args) {
917*4882a593Smuzhiyun 			farg = arg->func.args;
918*4882a593Smuzhiyun 			arg->func.args = farg->next;
919*4882a593Smuzhiyun 			free_arg(farg);
920*4882a593Smuzhiyun 		}
921*4882a593Smuzhiyun 		break;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
924*4882a593Smuzhiyun 	default:
925*4882a593Smuzhiyun 		break;
926*4882a593Smuzhiyun 	}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	free(arg);
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun 
get_type(int ch)931*4882a593Smuzhiyun static enum tep_event_type get_type(int ch)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun 	if (ch == '\n')
934*4882a593Smuzhiyun 		return TEP_EVENT_NEWLINE;
935*4882a593Smuzhiyun 	if (isspace(ch))
936*4882a593Smuzhiyun 		return TEP_EVENT_SPACE;
937*4882a593Smuzhiyun 	if (isalnum(ch) || ch == '_')
938*4882a593Smuzhiyun 		return TEP_EVENT_ITEM;
939*4882a593Smuzhiyun 	if (ch == '\'')
940*4882a593Smuzhiyun 		return TEP_EVENT_SQUOTE;
941*4882a593Smuzhiyun 	if (ch == '"')
942*4882a593Smuzhiyun 		return TEP_EVENT_DQUOTE;
943*4882a593Smuzhiyun 	if (!isprint(ch))
944*4882a593Smuzhiyun 		return TEP_EVENT_NONE;
945*4882a593Smuzhiyun 	if (ch == '(' || ch == ')' || ch == ',')
946*4882a593Smuzhiyun 		return TEP_EVENT_DELIM;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	return TEP_EVENT_OP;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun 
__read_char(void)951*4882a593Smuzhiyun static int __read_char(void)
952*4882a593Smuzhiyun {
953*4882a593Smuzhiyun 	if (input_buf_ptr >= input_buf_siz)
954*4882a593Smuzhiyun 		return -1;
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	return input_buf[input_buf_ptr++];
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun /**
960*4882a593Smuzhiyun  * peek_char - peek at the next character that will be read
961*4882a593Smuzhiyun  *
962*4882a593Smuzhiyun  * Returns the next character read, or -1 if end of buffer.
963*4882a593Smuzhiyun  */
peek_char(void)964*4882a593Smuzhiyun __hidden int peek_char(void)
965*4882a593Smuzhiyun {
966*4882a593Smuzhiyun 	if (input_buf_ptr >= input_buf_siz)
967*4882a593Smuzhiyun 		return -1;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	return input_buf[input_buf_ptr];
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun 
extend_token(char ** tok,char * buf,int size)972*4882a593Smuzhiyun static int extend_token(char **tok, char *buf, int size)
973*4882a593Smuzhiyun {
974*4882a593Smuzhiyun 	char *newtok = realloc(*tok, size);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	if (!newtok) {
977*4882a593Smuzhiyun 		free(*tok);
978*4882a593Smuzhiyun 		*tok = NULL;
979*4882a593Smuzhiyun 		return -1;
980*4882a593Smuzhiyun 	}
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	if (!*tok)
983*4882a593Smuzhiyun 		strcpy(newtok, buf);
984*4882a593Smuzhiyun 	else
985*4882a593Smuzhiyun 		strcat(newtok, buf);
986*4882a593Smuzhiyun 	*tok = newtok;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	return 0;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun static enum tep_event_type force_token(const char *str, char **tok);
992*4882a593Smuzhiyun 
__read_token(char ** tok)993*4882a593Smuzhiyun static enum tep_event_type __read_token(char **tok)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun 	char buf[BUFSIZ];
996*4882a593Smuzhiyun 	int ch, last_ch, quote_ch, next_ch;
997*4882a593Smuzhiyun 	int i = 0;
998*4882a593Smuzhiyun 	int tok_size = 0;
999*4882a593Smuzhiyun 	enum tep_event_type type;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	*tok = NULL;
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	ch = __read_char();
1005*4882a593Smuzhiyun 	if (ch < 0)
1006*4882a593Smuzhiyun 		return TEP_EVENT_NONE;
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	type = get_type(ch);
1009*4882a593Smuzhiyun 	if (type == TEP_EVENT_NONE)
1010*4882a593Smuzhiyun 		return type;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	buf[i++] = ch;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	switch (type) {
1015*4882a593Smuzhiyun 	case TEP_EVENT_NEWLINE:
1016*4882a593Smuzhiyun 	case TEP_EVENT_DELIM:
1017*4882a593Smuzhiyun 		if (asprintf(tok, "%c", ch) < 0)
1018*4882a593Smuzhiyun 			return TEP_EVENT_ERROR;
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 		return type;
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	case TEP_EVENT_OP:
1023*4882a593Smuzhiyun 		switch (ch) {
1024*4882a593Smuzhiyun 		case '-':
1025*4882a593Smuzhiyun 			next_ch = peek_char();
1026*4882a593Smuzhiyun 			if (next_ch == '>') {
1027*4882a593Smuzhiyun 				buf[i++] = __read_char();
1028*4882a593Smuzhiyun 				break;
1029*4882a593Smuzhiyun 			}
1030*4882a593Smuzhiyun 			/* fall through */
1031*4882a593Smuzhiyun 		case '+':
1032*4882a593Smuzhiyun 		case '|':
1033*4882a593Smuzhiyun 		case '&':
1034*4882a593Smuzhiyun 		case '>':
1035*4882a593Smuzhiyun 		case '<':
1036*4882a593Smuzhiyun 			last_ch = ch;
1037*4882a593Smuzhiyun 			ch = peek_char();
1038*4882a593Smuzhiyun 			if (ch != last_ch)
1039*4882a593Smuzhiyun 				goto test_equal;
1040*4882a593Smuzhiyun 			buf[i++] = __read_char();
1041*4882a593Smuzhiyun 			switch (last_ch) {
1042*4882a593Smuzhiyun 			case '>':
1043*4882a593Smuzhiyun 			case '<':
1044*4882a593Smuzhiyun 				goto test_equal;
1045*4882a593Smuzhiyun 			default:
1046*4882a593Smuzhiyun 				break;
1047*4882a593Smuzhiyun 			}
1048*4882a593Smuzhiyun 			break;
1049*4882a593Smuzhiyun 		case '!':
1050*4882a593Smuzhiyun 		case '=':
1051*4882a593Smuzhiyun 			goto test_equal;
1052*4882a593Smuzhiyun 		default: /* what should we do instead? */
1053*4882a593Smuzhiyun 			break;
1054*4882a593Smuzhiyun 		}
1055*4882a593Smuzhiyun 		buf[i] = 0;
1056*4882a593Smuzhiyun 		*tok = strdup(buf);
1057*4882a593Smuzhiyun 		return type;
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun  test_equal:
1060*4882a593Smuzhiyun 		ch = peek_char();
1061*4882a593Smuzhiyun 		if (ch == '=')
1062*4882a593Smuzhiyun 			buf[i++] = __read_char();
1063*4882a593Smuzhiyun 		goto out;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	case TEP_EVENT_DQUOTE:
1066*4882a593Smuzhiyun 	case TEP_EVENT_SQUOTE:
1067*4882a593Smuzhiyun 		/* don't keep quotes */
1068*4882a593Smuzhiyun 		i--;
1069*4882a593Smuzhiyun 		quote_ch = ch;
1070*4882a593Smuzhiyun 		last_ch = 0;
1071*4882a593Smuzhiyun  concat:
1072*4882a593Smuzhiyun 		do {
1073*4882a593Smuzhiyun 			if (i == (BUFSIZ - 1)) {
1074*4882a593Smuzhiyun 				buf[i] = 0;
1075*4882a593Smuzhiyun 				tok_size += BUFSIZ;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 				if (extend_token(tok, buf, tok_size) < 0)
1078*4882a593Smuzhiyun 					return TEP_EVENT_NONE;
1079*4882a593Smuzhiyun 				i = 0;
1080*4882a593Smuzhiyun 			}
1081*4882a593Smuzhiyun 			last_ch = ch;
1082*4882a593Smuzhiyun 			ch = __read_char();
1083*4882a593Smuzhiyun 			buf[i++] = ch;
1084*4882a593Smuzhiyun 			/* the '\' '\' will cancel itself */
1085*4882a593Smuzhiyun 			if (ch == '\\' && last_ch == '\\')
1086*4882a593Smuzhiyun 				last_ch = 0;
1087*4882a593Smuzhiyun 		} while (ch != quote_ch || last_ch == '\\');
1088*4882a593Smuzhiyun 		/* remove the last quote */
1089*4882a593Smuzhiyun 		i--;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 		/*
1092*4882a593Smuzhiyun 		 * For strings (double quotes) check the next token.
1093*4882a593Smuzhiyun 		 * If it is another string, concatinate the two.
1094*4882a593Smuzhiyun 		 */
1095*4882a593Smuzhiyun 		if (type == TEP_EVENT_DQUOTE) {
1096*4882a593Smuzhiyun 			unsigned long long save_input_buf_ptr = input_buf_ptr;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 			do {
1099*4882a593Smuzhiyun 				ch = __read_char();
1100*4882a593Smuzhiyun 			} while (isspace(ch));
1101*4882a593Smuzhiyun 			if (ch == '"')
1102*4882a593Smuzhiyun 				goto concat;
1103*4882a593Smuzhiyun 			input_buf_ptr = save_input_buf_ptr;
1104*4882a593Smuzhiyun 		}
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 		goto out;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	case TEP_EVENT_ERROR ... TEP_EVENT_SPACE:
1109*4882a593Smuzhiyun 	case TEP_EVENT_ITEM:
1110*4882a593Smuzhiyun 	default:
1111*4882a593Smuzhiyun 		break;
1112*4882a593Smuzhiyun 	}
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 	while (get_type(peek_char()) == type) {
1115*4882a593Smuzhiyun 		if (i == (BUFSIZ - 1)) {
1116*4882a593Smuzhiyun 			buf[i] = 0;
1117*4882a593Smuzhiyun 			tok_size += BUFSIZ;
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 			if (extend_token(tok, buf, tok_size) < 0)
1120*4882a593Smuzhiyun 				return TEP_EVENT_NONE;
1121*4882a593Smuzhiyun 			i = 0;
1122*4882a593Smuzhiyun 		}
1123*4882a593Smuzhiyun 		ch = __read_char();
1124*4882a593Smuzhiyun 		buf[i++] = ch;
1125*4882a593Smuzhiyun 	}
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun  out:
1128*4882a593Smuzhiyun 	buf[i] = 0;
1129*4882a593Smuzhiyun 	if (extend_token(tok, buf, tok_size + i + 1) < 0)
1130*4882a593Smuzhiyun 		return TEP_EVENT_NONE;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	if (type == TEP_EVENT_ITEM) {
1133*4882a593Smuzhiyun 		/*
1134*4882a593Smuzhiyun 		 * Older versions of the kernel has a bug that
1135*4882a593Smuzhiyun 		 * creates invalid symbols and will break the mac80211
1136*4882a593Smuzhiyun 		 * parsing. This is a work around to that bug.
1137*4882a593Smuzhiyun 		 *
1138*4882a593Smuzhiyun 		 * See Linux kernel commit:
1139*4882a593Smuzhiyun 		 *  811cb50baf63461ce0bdb234927046131fc7fa8b
1140*4882a593Smuzhiyun 		 */
1141*4882a593Smuzhiyun 		if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
1142*4882a593Smuzhiyun 			free(*tok);
1143*4882a593Smuzhiyun 			*tok = NULL;
1144*4882a593Smuzhiyun 			return force_token("\"%s\" ", tok);
1145*4882a593Smuzhiyun 		} else if (strcmp(*tok, "STA_PR_FMT") == 0) {
1146*4882a593Smuzhiyun 			free(*tok);
1147*4882a593Smuzhiyun 			*tok = NULL;
1148*4882a593Smuzhiyun 			return force_token("\" sta:%pM\" ", tok);
1149*4882a593Smuzhiyun 		} else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
1150*4882a593Smuzhiyun 			free(*tok);
1151*4882a593Smuzhiyun 			*tok = NULL;
1152*4882a593Smuzhiyun 			return force_token("\" vif:%p(%d)\" ", tok);
1153*4882a593Smuzhiyun 		}
1154*4882a593Smuzhiyun 	}
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	return type;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
force_token(const char * str,char ** tok)1159*4882a593Smuzhiyun static enum tep_event_type force_token(const char *str, char **tok)
1160*4882a593Smuzhiyun {
1161*4882a593Smuzhiyun 	const char *save_input_buf;
1162*4882a593Smuzhiyun 	unsigned long long save_input_buf_ptr;
1163*4882a593Smuzhiyun 	unsigned long long save_input_buf_siz;
1164*4882a593Smuzhiyun 	enum tep_event_type type;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	/* save off the current input pointers */
1167*4882a593Smuzhiyun 	save_input_buf = input_buf;
1168*4882a593Smuzhiyun 	save_input_buf_ptr = input_buf_ptr;
1169*4882a593Smuzhiyun 	save_input_buf_siz = input_buf_siz;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	init_input_buf(str, strlen(str));
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	type = __read_token(tok);
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	/* reset back to original token */
1176*4882a593Smuzhiyun 	input_buf = save_input_buf;
1177*4882a593Smuzhiyun 	input_buf_ptr = save_input_buf_ptr;
1178*4882a593Smuzhiyun 	input_buf_siz = save_input_buf_siz;
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	return type;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun /**
1184*4882a593Smuzhiyun  * free_token - free a token returned by tep_read_token
1185*4882a593Smuzhiyun  * @token: the token to free
1186*4882a593Smuzhiyun  */
free_token(char * tok)1187*4882a593Smuzhiyun __hidden void free_token(char *tok)
1188*4882a593Smuzhiyun {
1189*4882a593Smuzhiyun 	if (tok)
1190*4882a593Smuzhiyun 		free(tok);
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun /**
1194*4882a593Smuzhiyun  * read_token - access to utilities to use the tep parser
1195*4882a593Smuzhiyun  * @tok: The token to return
1196*4882a593Smuzhiyun  *
1197*4882a593Smuzhiyun  * This will parse tokens from the string given by
1198*4882a593Smuzhiyun  * tep_init_data().
1199*4882a593Smuzhiyun  *
1200*4882a593Smuzhiyun  * Returns the token type.
1201*4882a593Smuzhiyun  */
read_token(char ** tok)1202*4882a593Smuzhiyun __hidden enum tep_event_type read_token(char **tok)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun 	enum tep_event_type type;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	for (;;) {
1207*4882a593Smuzhiyun 		type = __read_token(tok);
1208*4882a593Smuzhiyun 		if (type != TEP_EVENT_SPACE)
1209*4882a593Smuzhiyun 			return type;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 		free_token(*tok);
1212*4882a593Smuzhiyun 	}
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 	/* not reached */
1215*4882a593Smuzhiyun 	*tok = NULL;
1216*4882a593Smuzhiyun 	return TEP_EVENT_NONE;
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun /* no newline */
read_token_item(char ** tok)1220*4882a593Smuzhiyun static enum tep_event_type read_token_item(char **tok)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun 	enum tep_event_type type;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	for (;;) {
1225*4882a593Smuzhiyun 		type = __read_token(tok);
1226*4882a593Smuzhiyun 		if (type != TEP_EVENT_SPACE && type != TEP_EVENT_NEWLINE)
1227*4882a593Smuzhiyun 			return type;
1228*4882a593Smuzhiyun 		free_token(*tok);
1229*4882a593Smuzhiyun 		*tok = NULL;
1230*4882a593Smuzhiyun 	}
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	/* not reached */
1233*4882a593Smuzhiyun 	*tok = NULL;
1234*4882a593Smuzhiyun 	return TEP_EVENT_NONE;
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
test_type(enum tep_event_type type,enum tep_event_type expect)1237*4882a593Smuzhiyun static int test_type(enum tep_event_type type, enum tep_event_type expect)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun 	if (type != expect) {
1240*4882a593Smuzhiyun 		do_warning("Error: expected type %d but read %d",
1241*4882a593Smuzhiyun 		    expect, type);
1242*4882a593Smuzhiyun 		return -1;
1243*4882a593Smuzhiyun 	}
1244*4882a593Smuzhiyun 	return 0;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
test_type_token(enum tep_event_type type,const char * token,enum tep_event_type expect,const char * expect_tok)1247*4882a593Smuzhiyun static int test_type_token(enum tep_event_type type, const char *token,
1248*4882a593Smuzhiyun 		    enum tep_event_type expect, const char *expect_tok)
1249*4882a593Smuzhiyun {
1250*4882a593Smuzhiyun 	if (type != expect) {
1251*4882a593Smuzhiyun 		do_warning("Error: expected type %d but read %d",
1252*4882a593Smuzhiyun 		    expect, type);
1253*4882a593Smuzhiyun 		return -1;
1254*4882a593Smuzhiyun 	}
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	if (strcmp(token, expect_tok) != 0) {
1257*4882a593Smuzhiyun 		do_warning("Error: expected '%s' but read '%s'",
1258*4882a593Smuzhiyun 		    expect_tok, token);
1259*4882a593Smuzhiyun 		return -1;
1260*4882a593Smuzhiyun 	}
1261*4882a593Smuzhiyun 	return 0;
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun 
__read_expect_type(enum tep_event_type expect,char ** tok,int newline_ok)1264*4882a593Smuzhiyun static int __read_expect_type(enum tep_event_type expect, char **tok, int newline_ok)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun 	enum tep_event_type type;
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	if (newline_ok)
1269*4882a593Smuzhiyun 		type = read_token(tok);
1270*4882a593Smuzhiyun 	else
1271*4882a593Smuzhiyun 		type = read_token_item(tok);
1272*4882a593Smuzhiyun 	return test_type(type, expect);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun 
read_expect_type(enum tep_event_type expect,char ** tok)1275*4882a593Smuzhiyun static int read_expect_type(enum tep_event_type expect, char **tok)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun 	return __read_expect_type(expect, tok, 1);
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun 
__read_expected(enum tep_event_type expect,const char * str,int newline_ok)1280*4882a593Smuzhiyun static int __read_expected(enum tep_event_type expect, const char *str,
1281*4882a593Smuzhiyun 			   int newline_ok)
1282*4882a593Smuzhiyun {
1283*4882a593Smuzhiyun 	enum tep_event_type type;
1284*4882a593Smuzhiyun 	char *token;
1285*4882a593Smuzhiyun 	int ret;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	if (newline_ok)
1288*4882a593Smuzhiyun 		type = read_token(&token);
1289*4882a593Smuzhiyun 	else
1290*4882a593Smuzhiyun 		type = read_token_item(&token);
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	ret = test_type_token(type, token, expect, str);
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	free_token(token);
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	return ret;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun 
read_expected(enum tep_event_type expect,const char * str)1299*4882a593Smuzhiyun static int read_expected(enum tep_event_type expect, const char *str)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun 	return __read_expected(expect, str, 1);
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun 
read_expected_item(enum tep_event_type expect,const char * str)1304*4882a593Smuzhiyun static int read_expected_item(enum tep_event_type expect, const char *str)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun 	return __read_expected(expect, str, 0);
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun 
event_read_name(void)1309*4882a593Smuzhiyun static char *event_read_name(void)
1310*4882a593Smuzhiyun {
1311*4882a593Smuzhiyun 	char *token;
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_ITEM, "name") < 0)
1314*4882a593Smuzhiyun 		return NULL;
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
1317*4882a593Smuzhiyun 		return NULL;
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
1320*4882a593Smuzhiyun 		goto fail;
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	return token;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun  fail:
1325*4882a593Smuzhiyun 	free_token(token);
1326*4882a593Smuzhiyun 	return NULL;
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun 
event_read_id(void)1329*4882a593Smuzhiyun static int event_read_id(void)
1330*4882a593Smuzhiyun {
1331*4882a593Smuzhiyun 	char *token;
1332*4882a593Smuzhiyun 	int id;
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	if (read_expected_item(TEP_EVENT_ITEM, "ID") < 0)
1335*4882a593Smuzhiyun 		return -1;
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
1338*4882a593Smuzhiyun 		return -1;
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
1341*4882a593Smuzhiyun 		goto fail;
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 	id = strtoul(token, NULL, 0);
1344*4882a593Smuzhiyun 	free_token(token);
1345*4882a593Smuzhiyun 	return id;
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun  fail:
1348*4882a593Smuzhiyun 	free_token(token);
1349*4882a593Smuzhiyun 	return -1;
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun 
field_is_string(struct tep_format_field * field)1352*4882a593Smuzhiyun static int field_is_string(struct tep_format_field *field)
1353*4882a593Smuzhiyun {
1354*4882a593Smuzhiyun 	if ((field->flags & TEP_FIELD_IS_ARRAY) &&
1355*4882a593Smuzhiyun 	    (strstr(field->type, "char") || strstr(field->type, "u8") ||
1356*4882a593Smuzhiyun 	     strstr(field->type, "s8")))
1357*4882a593Smuzhiyun 		return 1;
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	return 0;
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
field_is_dynamic(struct tep_format_field * field)1362*4882a593Smuzhiyun static int field_is_dynamic(struct tep_format_field *field)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun 	if (strncmp(field->type, "__data_loc", 10) == 0)
1365*4882a593Smuzhiyun 		return 1;
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 	return 0;
1368*4882a593Smuzhiyun }
1369*4882a593Smuzhiyun 
field_is_long(struct tep_format_field * field)1370*4882a593Smuzhiyun static int field_is_long(struct tep_format_field *field)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun 	/* includes long long */
1373*4882a593Smuzhiyun 	if (strstr(field->type, "long"))
1374*4882a593Smuzhiyun 		return 1;
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun 	return 0;
1377*4882a593Smuzhiyun }
1378*4882a593Smuzhiyun 
type_size(const char * name)1379*4882a593Smuzhiyun static unsigned int type_size(const char *name)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun 	/* This covers all TEP_FIELD_IS_STRING types. */
1382*4882a593Smuzhiyun 	static struct {
1383*4882a593Smuzhiyun 		const char *type;
1384*4882a593Smuzhiyun 		unsigned int size;
1385*4882a593Smuzhiyun 	} table[] = {
1386*4882a593Smuzhiyun 		{ "u8",   1 },
1387*4882a593Smuzhiyun 		{ "u16",  2 },
1388*4882a593Smuzhiyun 		{ "u32",  4 },
1389*4882a593Smuzhiyun 		{ "u64",  8 },
1390*4882a593Smuzhiyun 		{ "s8",   1 },
1391*4882a593Smuzhiyun 		{ "s16",  2 },
1392*4882a593Smuzhiyun 		{ "s32",  4 },
1393*4882a593Smuzhiyun 		{ "s64",  8 },
1394*4882a593Smuzhiyun 		{ "char", 1 },
1395*4882a593Smuzhiyun 		{ },
1396*4882a593Smuzhiyun 	};
1397*4882a593Smuzhiyun 	int i;
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun 	for (i = 0; table[i].type; i++) {
1400*4882a593Smuzhiyun 		if (!strcmp(table[i].type, name))
1401*4882a593Smuzhiyun 			return table[i].size;
1402*4882a593Smuzhiyun 	}
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	return 0;
1405*4882a593Smuzhiyun }
1406*4882a593Smuzhiyun 
append(char ** buf,const char * delim,const char * str)1407*4882a593Smuzhiyun static int append(char **buf, const char *delim, const char *str)
1408*4882a593Smuzhiyun {
1409*4882a593Smuzhiyun 	char *new_buf;
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	new_buf = realloc(*buf, strlen(*buf) + strlen(delim) + strlen(str) + 1);
1412*4882a593Smuzhiyun 	if (!new_buf)
1413*4882a593Smuzhiyun 		return -1;
1414*4882a593Smuzhiyun 	strcat(new_buf, delim);
1415*4882a593Smuzhiyun 	strcat(new_buf, str);
1416*4882a593Smuzhiyun 	*buf = new_buf;
1417*4882a593Smuzhiyun 	return 0;
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun 
event_read_fields(struct tep_event * event,struct tep_format_field ** fields)1420*4882a593Smuzhiyun static int event_read_fields(struct tep_event *event, struct tep_format_field **fields)
1421*4882a593Smuzhiyun {
1422*4882a593Smuzhiyun 	struct tep_format_field *field = NULL;
1423*4882a593Smuzhiyun 	enum tep_event_type type;
1424*4882a593Smuzhiyun 	char *token;
1425*4882a593Smuzhiyun 	char *last_token;
1426*4882a593Smuzhiyun 	char *delim = " ";
1427*4882a593Smuzhiyun 	int count = 0;
1428*4882a593Smuzhiyun 	int ret;
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 	do {
1431*4882a593Smuzhiyun 		unsigned int size_dynamic = 0;
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 		type = read_token(&token);
1434*4882a593Smuzhiyun 		if (type == TEP_EVENT_NEWLINE) {
1435*4882a593Smuzhiyun 			free_token(token);
1436*4882a593Smuzhiyun 			return count;
1437*4882a593Smuzhiyun 		}
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 		count++;
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 		if (test_type_token(type, token, TEP_EVENT_ITEM, "field"))
1442*4882a593Smuzhiyun 			goto fail;
1443*4882a593Smuzhiyun 		free_token(token);
1444*4882a593Smuzhiyun 
1445*4882a593Smuzhiyun 		type = read_token(&token);
1446*4882a593Smuzhiyun 		/*
1447*4882a593Smuzhiyun 		 * The ftrace fields may still use the "special" name.
1448*4882a593Smuzhiyun 		 * Just ignore it.
1449*4882a593Smuzhiyun 		 */
1450*4882a593Smuzhiyun 		if (event->flags & TEP_EVENT_FL_ISFTRACE &&
1451*4882a593Smuzhiyun 		    type == TEP_EVENT_ITEM && strcmp(token, "special") == 0) {
1452*4882a593Smuzhiyun 			free_token(token);
1453*4882a593Smuzhiyun 			type = read_token(&token);
1454*4882a593Smuzhiyun 		}
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 		if (test_type_token(type, token, TEP_EVENT_OP, ":") < 0)
1457*4882a593Smuzhiyun 			goto fail;
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 		free_token(token);
1460*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
1461*4882a593Smuzhiyun 			goto fail;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 		last_token = token;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 		field = calloc(1, sizeof(*field));
1466*4882a593Smuzhiyun 		if (!field)
1467*4882a593Smuzhiyun 			goto fail;
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 		field->event = event;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 		/* read the rest of the type */
1472*4882a593Smuzhiyun 		for (;;) {
1473*4882a593Smuzhiyun 			type = read_token(&token);
1474*4882a593Smuzhiyun 			if (type == TEP_EVENT_ITEM ||
1475*4882a593Smuzhiyun 			    (type == TEP_EVENT_OP && strcmp(token, "*") == 0) ||
1476*4882a593Smuzhiyun 			    /*
1477*4882a593Smuzhiyun 			     * Some of the ftrace fields are broken and have
1478*4882a593Smuzhiyun 			     * an illegal "." in them.
1479*4882a593Smuzhiyun 			     */
1480*4882a593Smuzhiyun 			    (event->flags & TEP_EVENT_FL_ISFTRACE &&
1481*4882a593Smuzhiyun 			     type == TEP_EVENT_OP && strcmp(token, ".") == 0)) {
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 				if (strcmp(token, "*") == 0)
1484*4882a593Smuzhiyun 					field->flags |= TEP_FIELD_IS_POINTER;
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun 				if (field->type) {
1487*4882a593Smuzhiyun 					ret = append(&field->type, delim, last_token);
1488*4882a593Smuzhiyun 					free(last_token);
1489*4882a593Smuzhiyun 					if (ret < 0)
1490*4882a593Smuzhiyun 						goto fail;
1491*4882a593Smuzhiyun 				} else
1492*4882a593Smuzhiyun 					field->type = last_token;
1493*4882a593Smuzhiyun 				last_token = token;
1494*4882a593Smuzhiyun 				delim = " ";
1495*4882a593Smuzhiyun 				continue;
1496*4882a593Smuzhiyun 			}
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 			/* Handle __attribute__((user)) */
1499*4882a593Smuzhiyun 			if ((type == TEP_EVENT_DELIM) &&
1500*4882a593Smuzhiyun 			    strcmp("__attribute__", last_token) == 0 &&
1501*4882a593Smuzhiyun 			    token[0] == '(') {
1502*4882a593Smuzhiyun 				int depth = 1;
1503*4882a593Smuzhiyun 				int ret;
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun 				ret = append(&field->type, " ", last_token);
1506*4882a593Smuzhiyun 				ret |= append(&field->type, "", "(");
1507*4882a593Smuzhiyun 				if (ret < 0)
1508*4882a593Smuzhiyun 					goto fail;
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 				delim = " ";
1511*4882a593Smuzhiyun 				while ((type = read_token(&token)) != TEP_EVENT_NONE) {
1512*4882a593Smuzhiyun 					if (type == TEP_EVENT_DELIM) {
1513*4882a593Smuzhiyun 						if (token[0] == '(')
1514*4882a593Smuzhiyun 							depth++;
1515*4882a593Smuzhiyun 						else if (token[0] == ')')
1516*4882a593Smuzhiyun 							depth--;
1517*4882a593Smuzhiyun 						if (!depth)
1518*4882a593Smuzhiyun 							break;
1519*4882a593Smuzhiyun 						ret = append(&field->type, "", token);
1520*4882a593Smuzhiyun 						delim = "";
1521*4882a593Smuzhiyun 					} else {
1522*4882a593Smuzhiyun 						ret = append(&field->type, delim, token);
1523*4882a593Smuzhiyun 						delim = " ";
1524*4882a593Smuzhiyun 					}
1525*4882a593Smuzhiyun 					if (ret < 0)
1526*4882a593Smuzhiyun 						goto fail;
1527*4882a593Smuzhiyun 					free(last_token);
1528*4882a593Smuzhiyun 					last_token = token;
1529*4882a593Smuzhiyun 				}
1530*4882a593Smuzhiyun 				continue;
1531*4882a593Smuzhiyun 			}
1532*4882a593Smuzhiyun 			break;
1533*4882a593Smuzhiyun 		}
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun 		if (!field->type) {
1536*4882a593Smuzhiyun 			do_warning_event(event, "%s: no type found", __func__);
1537*4882a593Smuzhiyun 			goto fail;
1538*4882a593Smuzhiyun 		}
1539*4882a593Smuzhiyun 		field->name = field->alias = last_token;
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 		if (test_type(type, TEP_EVENT_OP))
1542*4882a593Smuzhiyun 			goto fail;
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun 		if (strcmp(token, "[") == 0) {
1545*4882a593Smuzhiyun 			enum tep_event_type last_type = type;
1546*4882a593Smuzhiyun 			char *brackets = token;
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 			field->flags |= TEP_FIELD_IS_ARRAY;
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 			type = read_token(&token);
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 			if (type == TEP_EVENT_ITEM)
1553*4882a593Smuzhiyun 				field->arraylen = strtoul(token, NULL, 0);
1554*4882a593Smuzhiyun 			else
1555*4882a593Smuzhiyun 				field->arraylen = 0;
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 		        while (strcmp(token, "]") != 0) {
1558*4882a593Smuzhiyun 				const char *delim;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 				if (last_type == TEP_EVENT_ITEM &&
1561*4882a593Smuzhiyun 				    type == TEP_EVENT_ITEM)
1562*4882a593Smuzhiyun 					delim = " ";
1563*4882a593Smuzhiyun 				else
1564*4882a593Smuzhiyun 					delim = "";
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 				last_type = type;
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 				ret = append(&brackets, delim, token);
1569*4882a593Smuzhiyun 				if (ret < 0) {
1570*4882a593Smuzhiyun 					free(brackets);
1571*4882a593Smuzhiyun 					goto fail;
1572*4882a593Smuzhiyun 				}
1573*4882a593Smuzhiyun 				/* We only care about the last token */
1574*4882a593Smuzhiyun 				field->arraylen = strtoul(token, NULL, 0);
1575*4882a593Smuzhiyun 				free_token(token);
1576*4882a593Smuzhiyun 				type = read_token(&token);
1577*4882a593Smuzhiyun 				if (type == TEP_EVENT_NONE) {
1578*4882a593Smuzhiyun 					free(brackets);
1579*4882a593Smuzhiyun 					do_warning_event(event, "failed to find token");
1580*4882a593Smuzhiyun 					goto fail;
1581*4882a593Smuzhiyun 				}
1582*4882a593Smuzhiyun 			}
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun 			free_token(token);
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 			ret = append(&brackets, "", "]");
1587*4882a593Smuzhiyun 			if (ret < 0) {
1588*4882a593Smuzhiyun 				free(brackets);
1589*4882a593Smuzhiyun 				goto fail;
1590*4882a593Smuzhiyun 			}
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun 			/* add brackets to type */
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 			type = read_token(&token);
1595*4882a593Smuzhiyun 			/*
1596*4882a593Smuzhiyun 			 * If the next token is not an OP, then it is of
1597*4882a593Smuzhiyun 			 * the format: type [] item;
1598*4882a593Smuzhiyun 			 */
1599*4882a593Smuzhiyun 			if (type == TEP_EVENT_ITEM) {
1600*4882a593Smuzhiyun 				ret = append(&field->type, " ", field->name);
1601*4882a593Smuzhiyun 				if (ret < 0) {
1602*4882a593Smuzhiyun 					free(brackets);
1603*4882a593Smuzhiyun 					goto fail;
1604*4882a593Smuzhiyun 				}
1605*4882a593Smuzhiyun 				ret = append(&field->type, "", brackets);
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun 				size_dynamic = type_size(field->name);
1608*4882a593Smuzhiyun 				free_token(field->name);
1609*4882a593Smuzhiyun 				field->name = field->alias = token;
1610*4882a593Smuzhiyun 				type = read_token(&token);
1611*4882a593Smuzhiyun 			} else {
1612*4882a593Smuzhiyun 				ret = append(&field->type, "", brackets);
1613*4882a593Smuzhiyun 				if (ret < 0) {
1614*4882a593Smuzhiyun 					free(brackets);
1615*4882a593Smuzhiyun 					goto fail;
1616*4882a593Smuzhiyun 				}
1617*4882a593Smuzhiyun 			}
1618*4882a593Smuzhiyun 			free(brackets);
1619*4882a593Smuzhiyun 		}
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 		if (field_is_string(field))
1622*4882a593Smuzhiyun 			field->flags |= TEP_FIELD_IS_STRING;
1623*4882a593Smuzhiyun 		if (field_is_dynamic(field))
1624*4882a593Smuzhiyun 			field->flags |= TEP_FIELD_IS_DYNAMIC;
1625*4882a593Smuzhiyun 		if (field_is_long(field))
1626*4882a593Smuzhiyun 			field->flags |= TEP_FIELD_IS_LONG;
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 		if (test_type_token(type, token,  TEP_EVENT_OP, ";"))
1629*4882a593Smuzhiyun 			goto fail;
1630*4882a593Smuzhiyun 		free_token(token);
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_ITEM, "offset") < 0)
1633*4882a593Smuzhiyun 			goto fail_expect;
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ":") < 0)
1636*4882a593Smuzhiyun 			goto fail_expect;
1637*4882a593Smuzhiyun 
1638*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_ITEM, &token))
1639*4882a593Smuzhiyun 			goto fail;
1640*4882a593Smuzhiyun 		field->offset = strtoul(token, NULL, 0);
1641*4882a593Smuzhiyun 		free_token(token);
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ";") < 0)
1644*4882a593Smuzhiyun 			goto fail_expect;
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_ITEM, "size") < 0)
1647*4882a593Smuzhiyun 			goto fail_expect;
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ":") < 0)
1650*4882a593Smuzhiyun 			goto fail_expect;
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_ITEM, &token))
1653*4882a593Smuzhiyun 			goto fail;
1654*4882a593Smuzhiyun 		field->size = strtoul(token, NULL, 0);
1655*4882a593Smuzhiyun 		free_token(token);
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ";") < 0)
1658*4882a593Smuzhiyun 			goto fail_expect;
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 		type = read_token(&token);
1661*4882a593Smuzhiyun 		if (type != TEP_EVENT_NEWLINE) {
1662*4882a593Smuzhiyun 			/* newer versions of the kernel have a "signed" type */
1663*4882a593Smuzhiyun 			if (test_type_token(type, token, TEP_EVENT_ITEM, "signed"))
1664*4882a593Smuzhiyun 				goto fail;
1665*4882a593Smuzhiyun 
1666*4882a593Smuzhiyun 			free_token(token);
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 			if (read_expected(TEP_EVENT_OP, ":") < 0)
1669*4882a593Smuzhiyun 				goto fail_expect;
1670*4882a593Smuzhiyun 
1671*4882a593Smuzhiyun 			if (read_expect_type(TEP_EVENT_ITEM, &token))
1672*4882a593Smuzhiyun 				goto fail;
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 			if (strtoul(token, NULL, 0))
1675*4882a593Smuzhiyun 				field->flags |= TEP_FIELD_IS_SIGNED;
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 			free_token(token);
1678*4882a593Smuzhiyun 			if (read_expected(TEP_EVENT_OP, ";") < 0)
1679*4882a593Smuzhiyun 				goto fail_expect;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 			if (read_expect_type(TEP_EVENT_NEWLINE, &token))
1682*4882a593Smuzhiyun 				goto fail;
1683*4882a593Smuzhiyun 		}
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 		free_token(token);
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 		if (field->flags & TEP_FIELD_IS_ARRAY) {
1688*4882a593Smuzhiyun 			if (field->arraylen)
1689*4882a593Smuzhiyun 				field->elementsize = field->size / field->arraylen;
1690*4882a593Smuzhiyun 			else if (field->flags & TEP_FIELD_IS_DYNAMIC)
1691*4882a593Smuzhiyun 				field->elementsize = size_dynamic;
1692*4882a593Smuzhiyun 			else if (field->flags & TEP_FIELD_IS_STRING)
1693*4882a593Smuzhiyun 				field->elementsize = 1;
1694*4882a593Smuzhiyun 			else if (field->flags & TEP_FIELD_IS_LONG)
1695*4882a593Smuzhiyun 				field->elementsize = event->tep ?
1696*4882a593Smuzhiyun 						     event->tep->long_size :
1697*4882a593Smuzhiyun 						     sizeof(long);
1698*4882a593Smuzhiyun 		} else
1699*4882a593Smuzhiyun 			field->elementsize = field->size;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 		*fields = field;
1702*4882a593Smuzhiyun 		fields = &field->next;
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	} while (1);
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	return 0;
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun fail:
1709*4882a593Smuzhiyun 	free_token(token);
1710*4882a593Smuzhiyun fail_expect:
1711*4882a593Smuzhiyun 	if (field) {
1712*4882a593Smuzhiyun 		free(field->type);
1713*4882a593Smuzhiyun 		free(field->name);
1714*4882a593Smuzhiyun 		free(field);
1715*4882a593Smuzhiyun 	}
1716*4882a593Smuzhiyun 	return -1;
1717*4882a593Smuzhiyun }
1718*4882a593Smuzhiyun 
event_read_format(struct tep_event * event)1719*4882a593Smuzhiyun static int event_read_format(struct tep_event *event)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun 	char *token;
1722*4882a593Smuzhiyun 	int ret;
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	if (read_expected_item(TEP_EVENT_ITEM, "format") < 0)
1725*4882a593Smuzhiyun 		return -1;
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
1728*4882a593Smuzhiyun 		return -1;
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_NEWLINE, &token))
1731*4882a593Smuzhiyun 		goto fail;
1732*4882a593Smuzhiyun 	free_token(token);
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 	ret = event_read_fields(event, &event->format.common_fields);
1735*4882a593Smuzhiyun 	if (ret < 0)
1736*4882a593Smuzhiyun 		return ret;
1737*4882a593Smuzhiyun 	event->format.nr_common = ret;
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	ret = event_read_fields(event, &event->format.fields);
1740*4882a593Smuzhiyun 	if (ret < 0)
1741*4882a593Smuzhiyun 		return ret;
1742*4882a593Smuzhiyun 	event->format.nr_fields = ret;
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	return 0;
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun  fail:
1747*4882a593Smuzhiyun 	free_token(token);
1748*4882a593Smuzhiyun 	return -1;
1749*4882a593Smuzhiyun }
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun static enum tep_event_type
1752*4882a593Smuzhiyun process_arg_token(struct tep_event *event, struct tep_print_arg *arg,
1753*4882a593Smuzhiyun 		  char **tok, enum tep_event_type type);
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun static enum tep_event_type
process_arg(struct tep_event * event,struct tep_print_arg * arg,char ** tok)1756*4882a593Smuzhiyun process_arg(struct tep_event *event, struct tep_print_arg *arg, char **tok)
1757*4882a593Smuzhiyun {
1758*4882a593Smuzhiyun 	enum tep_event_type type;
1759*4882a593Smuzhiyun 	char *token;
1760*4882a593Smuzhiyun 
1761*4882a593Smuzhiyun 	type = read_token(&token);
1762*4882a593Smuzhiyun 	*tok = token;
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun 	return process_arg_token(event, arg, tok, type);
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun static enum tep_event_type
1768*4882a593Smuzhiyun process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok);
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun /*
1771*4882a593Smuzhiyun  * For __print_symbolic() and __print_flags, we need to completely
1772*4882a593Smuzhiyun  * evaluate the first argument, which defines what to print next.
1773*4882a593Smuzhiyun  */
1774*4882a593Smuzhiyun static enum tep_event_type
process_field_arg(struct tep_event * event,struct tep_print_arg * arg,char ** tok)1775*4882a593Smuzhiyun process_field_arg(struct tep_event *event, struct tep_print_arg *arg, char **tok)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun 	enum tep_event_type type;
1778*4882a593Smuzhiyun 
1779*4882a593Smuzhiyun 	type = process_arg(event, arg, tok);
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	while (type == TEP_EVENT_OP) {
1782*4882a593Smuzhiyun 		type = process_op(event, arg, tok);
1783*4882a593Smuzhiyun 	}
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 	return type;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun static enum tep_event_type
process_cond(struct tep_event * event,struct tep_print_arg * top,char ** tok)1789*4882a593Smuzhiyun process_cond(struct tep_event *event, struct tep_print_arg *top, char **tok)
1790*4882a593Smuzhiyun {
1791*4882a593Smuzhiyun 	struct tep_print_arg *arg, *left, *right;
1792*4882a593Smuzhiyun 	enum tep_event_type type;
1793*4882a593Smuzhiyun 	char *token = NULL;
1794*4882a593Smuzhiyun 
1795*4882a593Smuzhiyun 	arg = alloc_arg();
1796*4882a593Smuzhiyun 	left = alloc_arg();
1797*4882a593Smuzhiyun 	right = alloc_arg();
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	if (!arg || !left || !right) {
1800*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
1801*4882a593Smuzhiyun 		/* arg will be freed at out_free */
1802*4882a593Smuzhiyun 		free_arg(left);
1803*4882a593Smuzhiyun 		free_arg(right);
1804*4882a593Smuzhiyun 		goto out_free;
1805*4882a593Smuzhiyun 	}
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun 	arg->type = TEP_PRINT_OP;
1808*4882a593Smuzhiyun 	arg->op.left = left;
1809*4882a593Smuzhiyun 	arg->op.right = right;
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun 	*tok = NULL;
1812*4882a593Smuzhiyun 	type = process_arg(event, left, &token);
1813*4882a593Smuzhiyun 
1814*4882a593Smuzhiyun  again:
1815*4882a593Smuzhiyun 	if (type == TEP_EVENT_ERROR)
1816*4882a593Smuzhiyun 		goto out_free;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	/* Handle other operations in the arguments */
1819*4882a593Smuzhiyun 	if (type == TEP_EVENT_OP && strcmp(token, ":") != 0) {
1820*4882a593Smuzhiyun 		type = process_op(event, left, &token);
1821*4882a593Smuzhiyun 		goto again;
1822*4882a593Smuzhiyun 	}
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_OP, ":"))
1825*4882a593Smuzhiyun 		goto out_free;
1826*4882a593Smuzhiyun 
1827*4882a593Smuzhiyun 	arg->op.op = token;
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	type = process_arg(event, right, &token);
1830*4882a593Smuzhiyun 
1831*4882a593Smuzhiyun 	top->op.right = arg;
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	*tok = token;
1834*4882a593Smuzhiyun 	return type;
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun out_free:
1837*4882a593Smuzhiyun 	/* Top may point to itself */
1838*4882a593Smuzhiyun 	top->op.right = NULL;
1839*4882a593Smuzhiyun 	free_token(token);
1840*4882a593Smuzhiyun 	free_arg(arg);
1841*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
1842*4882a593Smuzhiyun }
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun static enum tep_event_type
process_array(struct tep_event * event,struct tep_print_arg * top,char ** tok)1845*4882a593Smuzhiyun process_array(struct tep_event *event, struct tep_print_arg *top, char **tok)
1846*4882a593Smuzhiyun {
1847*4882a593Smuzhiyun 	struct tep_print_arg *arg;
1848*4882a593Smuzhiyun 	enum tep_event_type type;
1849*4882a593Smuzhiyun 	char *token = NULL;
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun 	arg = alloc_arg();
1852*4882a593Smuzhiyun 	if (!arg) {
1853*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
1854*4882a593Smuzhiyun 		/* '*tok' is set to top->op.op.  No need to free. */
1855*4882a593Smuzhiyun 		*tok = NULL;
1856*4882a593Smuzhiyun 		return TEP_EVENT_ERROR;
1857*4882a593Smuzhiyun 	}
1858*4882a593Smuzhiyun 
1859*4882a593Smuzhiyun 	*tok = NULL;
1860*4882a593Smuzhiyun 	type = process_arg(event, arg, &token);
1861*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_OP, "]"))
1862*4882a593Smuzhiyun 		goto out_free;
1863*4882a593Smuzhiyun 
1864*4882a593Smuzhiyun 	top->op.right = arg;
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun 	free_token(token);
1867*4882a593Smuzhiyun 	type = read_token_item(&token);
1868*4882a593Smuzhiyun 	*tok = token;
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun 	return type;
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun out_free:
1873*4882a593Smuzhiyun 	free_token(token);
1874*4882a593Smuzhiyun 	free_arg(arg);
1875*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
1876*4882a593Smuzhiyun }
1877*4882a593Smuzhiyun 
get_op_prio(char * op)1878*4882a593Smuzhiyun static int get_op_prio(char *op)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun 	if (!op[1]) {
1881*4882a593Smuzhiyun 		switch (op[0]) {
1882*4882a593Smuzhiyun 		case '~':
1883*4882a593Smuzhiyun 		case '!':
1884*4882a593Smuzhiyun 			return 4;
1885*4882a593Smuzhiyun 		case '*':
1886*4882a593Smuzhiyun 		case '/':
1887*4882a593Smuzhiyun 		case '%':
1888*4882a593Smuzhiyun 			return 6;
1889*4882a593Smuzhiyun 		case '+':
1890*4882a593Smuzhiyun 		case '-':
1891*4882a593Smuzhiyun 			return 7;
1892*4882a593Smuzhiyun 			/* '>>' and '<<' are 8 */
1893*4882a593Smuzhiyun 		case '<':
1894*4882a593Smuzhiyun 		case '>':
1895*4882a593Smuzhiyun 			return 9;
1896*4882a593Smuzhiyun 			/* '==' and '!=' are 10 */
1897*4882a593Smuzhiyun 		case '&':
1898*4882a593Smuzhiyun 			return 11;
1899*4882a593Smuzhiyun 		case '^':
1900*4882a593Smuzhiyun 			return 12;
1901*4882a593Smuzhiyun 		case '|':
1902*4882a593Smuzhiyun 			return 13;
1903*4882a593Smuzhiyun 		case '?':
1904*4882a593Smuzhiyun 			return 16;
1905*4882a593Smuzhiyun 		default:
1906*4882a593Smuzhiyun 			do_warning("unknown op '%c'", op[0]);
1907*4882a593Smuzhiyun 			return -1;
1908*4882a593Smuzhiyun 		}
1909*4882a593Smuzhiyun 	} else {
1910*4882a593Smuzhiyun 		if (strcmp(op, "++") == 0 ||
1911*4882a593Smuzhiyun 		    strcmp(op, "--") == 0) {
1912*4882a593Smuzhiyun 			return 3;
1913*4882a593Smuzhiyun 		} else if (strcmp(op, ">>") == 0 ||
1914*4882a593Smuzhiyun 			   strcmp(op, "<<") == 0) {
1915*4882a593Smuzhiyun 			return 8;
1916*4882a593Smuzhiyun 		} else if (strcmp(op, ">=") == 0 ||
1917*4882a593Smuzhiyun 			   strcmp(op, "<=") == 0) {
1918*4882a593Smuzhiyun 			return 9;
1919*4882a593Smuzhiyun 		} else if (strcmp(op, "==") == 0 ||
1920*4882a593Smuzhiyun 			   strcmp(op, "!=") == 0) {
1921*4882a593Smuzhiyun 			return 10;
1922*4882a593Smuzhiyun 		} else if (strcmp(op, "&&") == 0) {
1923*4882a593Smuzhiyun 			return 14;
1924*4882a593Smuzhiyun 		} else if (strcmp(op, "||") == 0) {
1925*4882a593Smuzhiyun 			return 15;
1926*4882a593Smuzhiyun 		} else {
1927*4882a593Smuzhiyun 			do_warning("unknown op '%s'", op);
1928*4882a593Smuzhiyun 			return -1;
1929*4882a593Smuzhiyun 		}
1930*4882a593Smuzhiyun 	}
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun 
set_op_prio(struct tep_print_arg * arg)1933*4882a593Smuzhiyun static int set_op_prio(struct tep_print_arg *arg)
1934*4882a593Smuzhiyun {
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun 	/* single ops are the greatest */
1937*4882a593Smuzhiyun 	if (!arg->op.left || arg->op.left->type == TEP_PRINT_NULL)
1938*4882a593Smuzhiyun 		arg->op.prio = 0;
1939*4882a593Smuzhiyun 	else
1940*4882a593Smuzhiyun 		arg->op.prio = get_op_prio(arg->op.op);
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	return arg->op.prio;
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun 
1945*4882a593Smuzhiyun /* Note, *tok does not get freed, but will most likely be saved */
1946*4882a593Smuzhiyun static enum tep_event_type
process_op(struct tep_event * event,struct tep_print_arg * arg,char ** tok)1947*4882a593Smuzhiyun process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok)
1948*4882a593Smuzhiyun {
1949*4882a593Smuzhiyun 	struct tep_print_arg *left, *right = NULL;
1950*4882a593Smuzhiyun 	enum tep_event_type type;
1951*4882a593Smuzhiyun 	char *token;
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 	/* the op is passed in via tok */
1954*4882a593Smuzhiyun 	token = *tok;
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_OP && !arg->op.left) {
1957*4882a593Smuzhiyun 		/* handle single op */
1958*4882a593Smuzhiyun 		if (token[1]) {
1959*4882a593Smuzhiyun 			do_warning_event(event, "bad op token %s", token);
1960*4882a593Smuzhiyun 			goto out_free;
1961*4882a593Smuzhiyun 		}
1962*4882a593Smuzhiyun 		switch (token[0]) {
1963*4882a593Smuzhiyun 		case '~':
1964*4882a593Smuzhiyun 		case '!':
1965*4882a593Smuzhiyun 		case '+':
1966*4882a593Smuzhiyun 		case '-':
1967*4882a593Smuzhiyun 			break;
1968*4882a593Smuzhiyun 		default:
1969*4882a593Smuzhiyun 			do_warning_event(event, "bad op token %s", token);
1970*4882a593Smuzhiyun 			goto out_free;
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun 		}
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 		/* make an empty left */
1975*4882a593Smuzhiyun 		left = alloc_arg();
1976*4882a593Smuzhiyun 		if (!left)
1977*4882a593Smuzhiyun 			goto out_warn_free;
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 		left->type = TEP_PRINT_NULL;
1980*4882a593Smuzhiyun 		arg->op.left = left;
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun 		right = alloc_arg();
1983*4882a593Smuzhiyun 		if (!right)
1984*4882a593Smuzhiyun 			goto out_warn_free;
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 		arg->op.right = right;
1987*4882a593Smuzhiyun 
1988*4882a593Smuzhiyun 		/* do not free the token, it belongs to an op */
1989*4882a593Smuzhiyun 		*tok = NULL;
1990*4882a593Smuzhiyun 		type = process_arg(event, right, tok);
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	} else if (strcmp(token, "?") == 0) {
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun 		left = alloc_arg();
1995*4882a593Smuzhiyun 		if (!left)
1996*4882a593Smuzhiyun 			goto out_warn_free;
1997*4882a593Smuzhiyun 
1998*4882a593Smuzhiyun 		/* copy the top arg to the left */
1999*4882a593Smuzhiyun 		*left = *arg;
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun 		arg->type = TEP_PRINT_OP;
2002*4882a593Smuzhiyun 		arg->op.op = token;
2003*4882a593Smuzhiyun 		arg->op.left = left;
2004*4882a593Smuzhiyun 		arg->op.prio = 0;
2005*4882a593Smuzhiyun 
2006*4882a593Smuzhiyun 		/* it will set arg->op.right */
2007*4882a593Smuzhiyun 		type = process_cond(event, arg, tok);
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun 	} else if (strcmp(token, ">>") == 0 ||
2010*4882a593Smuzhiyun 		   strcmp(token, "<<") == 0 ||
2011*4882a593Smuzhiyun 		   strcmp(token, "&") == 0 ||
2012*4882a593Smuzhiyun 		   strcmp(token, "|") == 0 ||
2013*4882a593Smuzhiyun 		   strcmp(token, "&&") == 0 ||
2014*4882a593Smuzhiyun 		   strcmp(token, "||") == 0 ||
2015*4882a593Smuzhiyun 		   strcmp(token, "-") == 0 ||
2016*4882a593Smuzhiyun 		   strcmp(token, "+") == 0 ||
2017*4882a593Smuzhiyun 		   strcmp(token, "*") == 0 ||
2018*4882a593Smuzhiyun 		   strcmp(token, "^") == 0 ||
2019*4882a593Smuzhiyun 		   strcmp(token, "/") == 0 ||
2020*4882a593Smuzhiyun 		   strcmp(token, "%") == 0 ||
2021*4882a593Smuzhiyun 		   strcmp(token, "<") == 0 ||
2022*4882a593Smuzhiyun 		   strcmp(token, ">") == 0 ||
2023*4882a593Smuzhiyun 		   strcmp(token, "<=") == 0 ||
2024*4882a593Smuzhiyun 		   strcmp(token, ">=") == 0 ||
2025*4882a593Smuzhiyun 		   strcmp(token, "==") == 0 ||
2026*4882a593Smuzhiyun 		   strcmp(token, "!=") == 0) {
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 		left = alloc_arg();
2029*4882a593Smuzhiyun 		if (!left)
2030*4882a593Smuzhiyun 			goto out_warn_free;
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun 		/* copy the top arg to the left */
2033*4882a593Smuzhiyun 		*left = *arg;
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 		arg->type = TEP_PRINT_OP;
2036*4882a593Smuzhiyun 		arg->op.op = token;
2037*4882a593Smuzhiyun 		arg->op.left = left;
2038*4882a593Smuzhiyun 		arg->op.right = NULL;
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun 		if (set_op_prio(arg) == -1) {
2041*4882a593Smuzhiyun 			event->flags |= TEP_EVENT_FL_FAILED;
2042*4882a593Smuzhiyun 			/* arg->op.op (= token) will be freed at out_free */
2043*4882a593Smuzhiyun 			arg->op.op = NULL;
2044*4882a593Smuzhiyun 			goto out_free;
2045*4882a593Smuzhiyun 		}
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 		type = read_token_item(&token);
2048*4882a593Smuzhiyun 		*tok = token;
2049*4882a593Smuzhiyun 
2050*4882a593Smuzhiyun 		/* could just be a type pointer */
2051*4882a593Smuzhiyun 		if ((strcmp(arg->op.op, "*") == 0) &&
2052*4882a593Smuzhiyun 		    type == TEP_EVENT_DELIM && (strcmp(token, ")") == 0)) {
2053*4882a593Smuzhiyun 			int ret;
2054*4882a593Smuzhiyun 
2055*4882a593Smuzhiyun 			if (left->type != TEP_PRINT_ATOM) {
2056*4882a593Smuzhiyun 				do_warning_event(event, "bad pointer type");
2057*4882a593Smuzhiyun 				goto out_free;
2058*4882a593Smuzhiyun 			}
2059*4882a593Smuzhiyun 			ret = append(&left->atom.atom, " ", "*");
2060*4882a593Smuzhiyun 			if (ret < 0)
2061*4882a593Smuzhiyun 				goto out_warn_free;
2062*4882a593Smuzhiyun 
2063*4882a593Smuzhiyun 			free(arg->op.op);
2064*4882a593Smuzhiyun 			*arg = *left;
2065*4882a593Smuzhiyun 			free(left);
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 			return type;
2068*4882a593Smuzhiyun 		}
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun 		right = alloc_arg();
2071*4882a593Smuzhiyun 		if (!right)
2072*4882a593Smuzhiyun 			goto out_warn_free;
2073*4882a593Smuzhiyun 
2074*4882a593Smuzhiyun 		type = process_arg_token(event, right, tok, type);
2075*4882a593Smuzhiyun 		if (type == TEP_EVENT_ERROR) {
2076*4882a593Smuzhiyun 			free_arg(right);
2077*4882a593Smuzhiyun 			/* token was freed in process_arg_token() via *tok */
2078*4882a593Smuzhiyun 			token = NULL;
2079*4882a593Smuzhiyun 			goto out_free;
2080*4882a593Smuzhiyun 		}
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 		if (right->type == TEP_PRINT_OP &&
2083*4882a593Smuzhiyun 		    get_op_prio(arg->op.op) < get_op_prio(right->op.op)) {
2084*4882a593Smuzhiyun 			struct tep_print_arg tmp;
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 			/* rotate ops according to the priority */
2087*4882a593Smuzhiyun 			arg->op.right = right->op.left;
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 			tmp = *arg;
2090*4882a593Smuzhiyun 			*arg = *right;
2091*4882a593Smuzhiyun 			*right = tmp;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 			arg->op.left = right;
2094*4882a593Smuzhiyun 		} else {
2095*4882a593Smuzhiyun 			arg->op.right = right;
2096*4882a593Smuzhiyun 		}
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun 	} else if (strcmp(token, "[") == 0) {
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 		left = alloc_arg();
2101*4882a593Smuzhiyun 		if (!left)
2102*4882a593Smuzhiyun 			goto out_warn_free;
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun 		*left = *arg;
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 		arg->type = TEP_PRINT_OP;
2107*4882a593Smuzhiyun 		arg->op.op = token;
2108*4882a593Smuzhiyun 		arg->op.left = left;
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 		arg->op.prio = 0;
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 		/* it will set arg->op.right */
2113*4882a593Smuzhiyun 		type = process_array(event, arg, tok);
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	} else {
2116*4882a593Smuzhiyun 		do_warning_event(event, "unknown op '%s'", token);
2117*4882a593Smuzhiyun 		event->flags |= TEP_EVENT_FL_FAILED;
2118*4882a593Smuzhiyun 		/* the arg is now the left side */
2119*4882a593Smuzhiyun 		goto out_free;
2120*4882a593Smuzhiyun 	}
2121*4882a593Smuzhiyun 
2122*4882a593Smuzhiyun 	if (type == TEP_EVENT_OP && strcmp(*tok, ":") != 0) {
2123*4882a593Smuzhiyun 		int prio;
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 		/* higher prios need to be closer to the root */
2126*4882a593Smuzhiyun 		prio = get_op_prio(*tok);
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun 		if (prio > arg->op.prio)
2129*4882a593Smuzhiyun 			return process_op(event, arg, tok);
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		return process_op(event, right, tok);
2132*4882a593Smuzhiyun 	}
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 	return type;
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun out_warn_free:
2137*4882a593Smuzhiyun 	do_warning_event(event, "%s: not enough memory!", __func__);
2138*4882a593Smuzhiyun out_free:
2139*4882a593Smuzhiyun 	free_token(token);
2140*4882a593Smuzhiyun 	*tok = NULL;
2141*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2142*4882a593Smuzhiyun }
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun static enum tep_event_type
process_entry(struct tep_event * event __maybe_unused,struct tep_print_arg * arg,char ** tok)2145*4882a593Smuzhiyun process_entry(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
2146*4882a593Smuzhiyun 	      char **tok)
2147*4882a593Smuzhiyun {
2148*4882a593Smuzhiyun 	enum tep_event_type type;
2149*4882a593Smuzhiyun 	char *field;
2150*4882a593Smuzhiyun 	char *token;
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, "->") < 0)
2153*4882a593Smuzhiyun 		goto out_err;
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
2156*4882a593Smuzhiyun 		goto out_free;
2157*4882a593Smuzhiyun 	field = token;
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	arg->type = TEP_PRINT_FIELD;
2160*4882a593Smuzhiyun 	arg->field.name = field;
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	if (is_flag_field) {
2163*4882a593Smuzhiyun 		arg->field.field = tep_find_any_field(event, arg->field.name);
2164*4882a593Smuzhiyun 		arg->field.field->flags |= TEP_FIELD_IS_FLAG;
2165*4882a593Smuzhiyun 		is_flag_field = 0;
2166*4882a593Smuzhiyun 	} else if (is_symbolic_field) {
2167*4882a593Smuzhiyun 		arg->field.field = tep_find_any_field(event, arg->field.name);
2168*4882a593Smuzhiyun 		arg->field.field->flags |= TEP_FIELD_IS_SYMBOLIC;
2169*4882a593Smuzhiyun 		is_symbolic_field = 0;
2170*4882a593Smuzhiyun 	}
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun 	type = read_token(&token);
2173*4882a593Smuzhiyun 	*tok = token;
2174*4882a593Smuzhiyun 
2175*4882a593Smuzhiyun 	return type;
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun  out_free:
2178*4882a593Smuzhiyun 	free_token(token);
2179*4882a593Smuzhiyun  out_err:
2180*4882a593Smuzhiyun 	*tok = NULL;
2181*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2182*4882a593Smuzhiyun }
2183*4882a593Smuzhiyun 
alloc_and_process_delim(struct tep_event * event,char * next_token,struct tep_print_arg ** print_arg)2184*4882a593Smuzhiyun static int alloc_and_process_delim(struct tep_event *event, char *next_token,
2185*4882a593Smuzhiyun 				   struct tep_print_arg **print_arg)
2186*4882a593Smuzhiyun {
2187*4882a593Smuzhiyun 	struct tep_print_arg *field;
2188*4882a593Smuzhiyun 	enum tep_event_type type;
2189*4882a593Smuzhiyun 	char *token;
2190*4882a593Smuzhiyun 	int ret = 0;
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun 	field = alloc_arg();
2193*4882a593Smuzhiyun 	if (!field) {
2194*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
2195*4882a593Smuzhiyun 		errno = ENOMEM;
2196*4882a593Smuzhiyun 		return -1;
2197*4882a593Smuzhiyun 	}
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun 	type = process_arg(event, field, &token);
2200*4882a593Smuzhiyun 
2201*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, next_token)) {
2202*4882a593Smuzhiyun 		errno = EINVAL;
2203*4882a593Smuzhiyun 		ret = -1;
2204*4882a593Smuzhiyun 		free_arg(field);
2205*4882a593Smuzhiyun 		goto out_free_token;
2206*4882a593Smuzhiyun 	}
2207*4882a593Smuzhiyun 
2208*4882a593Smuzhiyun 	*print_arg = field;
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun out_free_token:
2211*4882a593Smuzhiyun 	free_token(token);
2212*4882a593Smuzhiyun 
2213*4882a593Smuzhiyun 	return ret;
2214*4882a593Smuzhiyun }
2215*4882a593Smuzhiyun 
2216*4882a593Smuzhiyun static char *arg_eval (struct tep_print_arg *arg);
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun static unsigned long long
eval_type_str(unsigned long long val,const char * type,int pointer)2219*4882a593Smuzhiyun eval_type_str(unsigned long long val, const char *type, int pointer)
2220*4882a593Smuzhiyun {
2221*4882a593Smuzhiyun 	int sign = 0;
2222*4882a593Smuzhiyun 	char *ref;
2223*4882a593Smuzhiyun 	int len;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	len = strlen(type);
2226*4882a593Smuzhiyun 
2227*4882a593Smuzhiyun 	if (pointer) {
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun 		if (type[len-1] != '*') {
2230*4882a593Smuzhiyun 			do_warning("pointer expected with non pointer type");
2231*4882a593Smuzhiyun 			return val;
2232*4882a593Smuzhiyun 		}
2233*4882a593Smuzhiyun 
2234*4882a593Smuzhiyun 		ref = malloc(len);
2235*4882a593Smuzhiyun 		if (!ref) {
2236*4882a593Smuzhiyun 			do_warning("%s: not enough memory!", __func__);
2237*4882a593Smuzhiyun 			return val;
2238*4882a593Smuzhiyun 		}
2239*4882a593Smuzhiyun 		memcpy(ref, type, len);
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 		/* chop off the " *" */
2242*4882a593Smuzhiyun 		ref[len - 2] = 0;
2243*4882a593Smuzhiyun 
2244*4882a593Smuzhiyun 		val = eval_type_str(val, ref, 0);
2245*4882a593Smuzhiyun 		free(ref);
2246*4882a593Smuzhiyun 		return val;
2247*4882a593Smuzhiyun 	}
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 	/* check if this is a pointer */
2250*4882a593Smuzhiyun 	if (type[len - 1] == '*')
2251*4882a593Smuzhiyun 		return val;
2252*4882a593Smuzhiyun 
2253*4882a593Smuzhiyun 	/* Try to figure out the arg size*/
2254*4882a593Smuzhiyun 	if (strncmp(type, "struct", 6) == 0)
2255*4882a593Smuzhiyun 		/* all bets off */
2256*4882a593Smuzhiyun 		return val;
2257*4882a593Smuzhiyun 
2258*4882a593Smuzhiyun 	if (strcmp(type, "u8") == 0)
2259*4882a593Smuzhiyun 		return val & 0xff;
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun 	if (strcmp(type, "u16") == 0)
2262*4882a593Smuzhiyun 		return val & 0xffff;
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	if (strcmp(type, "u32") == 0)
2265*4882a593Smuzhiyun 		return val & 0xffffffff;
2266*4882a593Smuzhiyun 
2267*4882a593Smuzhiyun 	if (strcmp(type, "u64") == 0 ||
2268*4882a593Smuzhiyun 	    strcmp(type, "s64") == 0)
2269*4882a593Smuzhiyun 		return val;
2270*4882a593Smuzhiyun 
2271*4882a593Smuzhiyun 	if (strcmp(type, "s8") == 0)
2272*4882a593Smuzhiyun 		return (unsigned long long)(char)val & 0xff;
2273*4882a593Smuzhiyun 
2274*4882a593Smuzhiyun 	if (strcmp(type, "s16") == 0)
2275*4882a593Smuzhiyun 		return (unsigned long long)(short)val & 0xffff;
2276*4882a593Smuzhiyun 
2277*4882a593Smuzhiyun 	if (strcmp(type, "s32") == 0)
2278*4882a593Smuzhiyun 		return (unsigned long long)(int)val & 0xffffffff;
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun 	if (strncmp(type, "unsigned ", 9) == 0) {
2281*4882a593Smuzhiyun 		sign = 0;
2282*4882a593Smuzhiyun 		type += 9;
2283*4882a593Smuzhiyun 	}
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	if (strcmp(type, "char") == 0) {
2286*4882a593Smuzhiyun 		if (sign)
2287*4882a593Smuzhiyun 			return (unsigned long long)(char)val & 0xff;
2288*4882a593Smuzhiyun 		else
2289*4882a593Smuzhiyun 			return val & 0xff;
2290*4882a593Smuzhiyun 	}
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 	if (strcmp(type, "short") == 0) {
2293*4882a593Smuzhiyun 		if (sign)
2294*4882a593Smuzhiyun 			return (unsigned long long)(short)val & 0xffff;
2295*4882a593Smuzhiyun 		else
2296*4882a593Smuzhiyun 			return val & 0xffff;
2297*4882a593Smuzhiyun 	}
2298*4882a593Smuzhiyun 
2299*4882a593Smuzhiyun 	if (strcmp(type, "int") == 0) {
2300*4882a593Smuzhiyun 		if (sign)
2301*4882a593Smuzhiyun 			return (unsigned long long)(int)val & 0xffffffff;
2302*4882a593Smuzhiyun 		else
2303*4882a593Smuzhiyun 			return val & 0xffffffff;
2304*4882a593Smuzhiyun 	}
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun 	return val;
2307*4882a593Smuzhiyun }
2308*4882a593Smuzhiyun 
2309*4882a593Smuzhiyun /*
2310*4882a593Smuzhiyun  * Try to figure out the type.
2311*4882a593Smuzhiyun  */
2312*4882a593Smuzhiyun static unsigned long long
eval_type(unsigned long long val,struct tep_print_arg * arg,int pointer)2313*4882a593Smuzhiyun eval_type(unsigned long long val, struct tep_print_arg *arg, int pointer)
2314*4882a593Smuzhiyun {
2315*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_TYPE) {
2316*4882a593Smuzhiyun 		do_warning("expected type argument");
2317*4882a593Smuzhiyun 		return 0;
2318*4882a593Smuzhiyun 	}
2319*4882a593Smuzhiyun 
2320*4882a593Smuzhiyun 	return eval_type_str(val, arg->typecast.type, pointer);
2321*4882a593Smuzhiyun }
2322*4882a593Smuzhiyun 
arg_num_eval(struct tep_print_arg * arg,long long * val)2323*4882a593Smuzhiyun static int arg_num_eval(struct tep_print_arg *arg, long long *val)
2324*4882a593Smuzhiyun {
2325*4882a593Smuzhiyun 	long long left, right;
2326*4882a593Smuzhiyun 	int ret = 1;
2327*4882a593Smuzhiyun 
2328*4882a593Smuzhiyun 	switch (arg->type) {
2329*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
2330*4882a593Smuzhiyun 		*val = strtoll(arg->atom.atom, NULL, 0);
2331*4882a593Smuzhiyun 		break;
2332*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
2333*4882a593Smuzhiyun 		ret = arg_num_eval(arg->typecast.item, val);
2334*4882a593Smuzhiyun 		if (!ret)
2335*4882a593Smuzhiyun 			break;
2336*4882a593Smuzhiyun 		*val = eval_type(*val, arg, 0);
2337*4882a593Smuzhiyun 		break;
2338*4882a593Smuzhiyun 	case TEP_PRINT_OP:
2339*4882a593Smuzhiyun 		switch (arg->op.op[0]) {
2340*4882a593Smuzhiyun 		case '|':
2341*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2342*4882a593Smuzhiyun 			if (!ret)
2343*4882a593Smuzhiyun 				break;
2344*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2345*4882a593Smuzhiyun 			if (!ret)
2346*4882a593Smuzhiyun 				break;
2347*4882a593Smuzhiyun 			if (arg->op.op[1])
2348*4882a593Smuzhiyun 				*val = left || right;
2349*4882a593Smuzhiyun 			else
2350*4882a593Smuzhiyun 				*val = left | right;
2351*4882a593Smuzhiyun 			break;
2352*4882a593Smuzhiyun 		case '&':
2353*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2354*4882a593Smuzhiyun 			if (!ret)
2355*4882a593Smuzhiyun 				break;
2356*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2357*4882a593Smuzhiyun 			if (!ret)
2358*4882a593Smuzhiyun 				break;
2359*4882a593Smuzhiyun 			if (arg->op.op[1])
2360*4882a593Smuzhiyun 				*val = left && right;
2361*4882a593Smuzhiyun 			else
2362*4882a593Smuzhiyun 				*val = left & right;
2363*4882a593Smuzhiyun 			break;
2364*4882a593Smuzhiyun 		case '<':
2365*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2366*4882a593Smuzhiyun 			if (!ret)
2367*4882a593Smuzhiyun 				break;
2368*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2369*4882a593Smuzhiyun 			if (!ret)
2370*4882a593Smuzhiyun 				break;
2371*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
2372*4882a593Smuzhiyun 			case 0:
2373*4882a593Smuzhiyun 				*val = left < right;
2374*4882a593Smuzhiyun 				break;
2375*4882a593Smuzhiyun 			case '<':
2376*4882a593Smuzhiyun 				*val = left << right;
2377*4882a593Smuzhiyun 				break;
2378*4882a593Smuzhiyun 			case '=':
2379*4882a593Smuzhiyun 				*val = left <= right;
2380*4882a593Smuzhiyun 				break;
2381*4882a593Smuzhiyun 			default:
2382*4882a593Smuzhiyun 				do_warning("unknown op '%s'", arg->op.op);
2383*4882a593Smuzhiyun 				ret = 0;
2384*4882a593Smuzhiyun 			}
2385*4882a593Smuzhiyun 			break;
2386*4882a593Smuzhiyun 		case '>':
2387*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2388*4882a593Smuzhiyun 			if (!ret)
2389*4882a593Smuzhiyun 				break;
2390*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2391*4882a593Smuzhiyun 			if (!ret)
2392*4882a593Smuzhiyun 				break;
2393*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
2394*4882a593Smuzhiyun 			case 0:
2395*4882a593Smuzhiyun 				*val = left > right;
2396*4882a593Smuzhiyun 				break;
2397*4882a593Smuzhiyun 			case '>':
2398*4882a593Smuzhiyun 				*val = left >> right;
2399*4882a593Smuzhiyun 				break;
2400*4882a593Smuzhiyun 			case '=':
2401*4882a593Smuzhiyun 				*val = left >= right;
2402*4882a593Smuzhiyun 				break;
2403*4882a593Smuzhiyun 			default:
2404*4882a593Smuzhiyun 				do_warning("unknown op '%s'", arg->op.op);
2405*4882a593Smuzhiyun 				ret = 0;
2406*4882a593Smuzhiyun 			}
2407*4882a593Smuzhiyun 			break;
2408*4882a593Smuzhiyun 		case '=':
2409*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2410*4882a593Smuzhiyun 			if (!ret)
2411*4882a593Smuzhiyun 				break;
2412*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2413*4882a593Smuzhiyun 			if (!ret)
2414*4882a593Smuzhiyun 				break;
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 			if (arg->op.op[1] != '=') {
2417*4882a593Smuzhiyun 				do_warning("unknown op '%s'", arg->op.op);
2418*4882a593Smuzhiyun 				ret = 0;
2419*4882a593Smuzhiyun 			} else
2420*4882a593Smuzhiyun 				*val = left == right;
2421*4882a593Smuzhiyun 			break;
2422*4882a593Smuzhiyun 		case '!':
2423*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.left, &left);
2424*4882a593Smuzhiyun 			if (!ret)
2425*4882a593Smuzhiyun 				break;
2426*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2427*4882a593Smuzhiyun 			if (!ret)
2428*4882a593Smuzhiyun 				break;
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
2431*4882a593Smuzhiyun 			case '=':
2432*4882a593Smuzhiyun 				*val = left != right;
2433*4882a593Smuzhiyun 				break;
2434*4882a593Smuzhiyun 			default:
2435*4882a593Smuzhiyun 				do_warning("unknown op '%s'", arg->op.op);
2436*4882a593Smuzhiyun 				ret = 0;
2437*4882a593Smuzhiyun 			}
2438*4882a593Smuzhiyun 			break;
2439*4882a593Smuzhiyun 		case '-':
2440*4882a593Smuzhiyun 			/* check for negative */
2441*4882a593Smuzhiyun 			if (arg->op.left->type == TEP_PRINT_NULL)
2442*4882a593Smuzhiyun 				left = 0;
2443*4882a593Smuzhiyun 			else
2444*4882a593Smuzhiyun 				ret = arg_num_eval(arg->op.left, &left);
2445*4882a593Smuzhiyun 			if (!ret)
2446*4882a593Smuzhiyun 				break;
2447*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2448*4882a593Smuzhiyun 			if (!ret)
2449*4882a593Smuzhiyun 				break;
2450*4882a593Smuzhiyun 			*val = left - right;
2451*4882a593Smuzhiyun 			break;
2452*4882a593Smuzhiyun 		case '+':
2453*4882a593Smuzhiyun 			if (arg->op.left->type == TEP_PRINT_NULL)
2454*4882a593Smuzhiyun 				left = 0;
2455*4882a593Smuzhiyun 			else
2456*4882a593Smuzhiyun 				ret = arg_num_eval(arg->op.left, &left);
2457*4882a593Smuzhiyun 			if (!ret)
2458*4882a593Smuzhiyun 				break;
2459*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2460*4882a593Smuzhiyun 			if (!ret)
2461*4882a593Smuzhiyun 				break;
2462*4882a593Smuzhiyun 			*val = left + right;
2463*4882a593Smuzhiyun 			break;
2464*4882a593Smuzhiyun 		case '~':
2465*4882a593Smuzhiyun 			ret = arg_num_eval(arg->op.right, &right);
2466*4882a593Smuzhiyun 			if (!ret)
2467*4882a593Smuzhiyun 				break;
2468*4882a593Smuzhiyun 			*val = ~right;
2469*4882a593Smuzhiyun 			break;
2470*4882a593Smuzhiyun 		default:
2471*4882a593Smuzhiyun 			do_warning("unknown op '%s'", arg->op.op);
2472*4882a593Smuzhiyun 			ret = 0;
2473*4882a593Smuzhiyun 		}
2474*4882a593Smuzhiyun 		break;
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
2477*4882a593Smuzhiyun 	case TEP_PRINT_FIELD ... TEP_PRINT_SYMBOL:
2478*4882a593Smuzhiyun 	case TEP_PRINT_STRING:
2479*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
2480*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK:
2481*4882a593Smuzhiyun 	default:
2482*4882a593Smuzhiyun 		do_warning("invalid eval type %d", arg->type);
2483*4882a593Smuzhiyun 		ret = 0;
2484*4882a593Smuzhiyun 
2485*4882a593Smuzhiyun 	}
2486*4882a593Smuzhiyun 	return ret;
2487*4882a593Smuzhiyun }
2488*4882a593Smuzhiyun 
arg_eval(struct tep_print_arg * arg)2489*4882a593Smuzhiyun static char *arg_eval (struct tep_print_arg *arg)
2490*4882a593Smuzhiyun {
2491*4882a593Smuzhiyun 	long long val;
2492*4882a593Smuzhiyun 	static char buf[24];
2493*4882a593Smuzhiyun 
2494*4882a593Smuzhiyun 	switch (arg->type) {
2495*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
2496*4882a593Smuzhiyun 		return arg->atom.atom;
2497*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
2498*4882a593Smuzhiyun 		return arg_eval(arg->typecast.item);
2499*4882a593Smuzhiyun 	case TEP_PRINT_OP:
2500*4882a593Smuzhiyun 		if (!arg_num_eval(arg, &val))
2501*4882a593Smuzhiyun 			break;
2502*4882a593Smuzhiyun 		sprintf(buf, "%lld", val);
2503*4882a593Smuzhiyun 		return buf;
2504*4882a593Smuzhiyun 
2505*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
2506*4882a593Smuzhiyun 	case TEP_PRINT_FIELD ... TEP_PRINT_SYMBOL:
2507*4882a593Smuzhiyun 	case TEP_PRINT_STRING:
2508*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
2509*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK:
2510*4882a593Smuzhiyun 	default:
2511*4882a593Smuzhiyun 		do_warning("invalid eval type %d", arg->type);
2512*4882a593Smuzhiyun 		break;
2513*4882a593Smuzhiyun 	}
2514*4882a593Smuzhiyun 
2515*4882a593Smuzhiyun 	return NULL;
2516*4882a593Smuzhiyun }
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun static enum tep_event_type
process_fields(struct tep_event * event,struct tep_print_flag_sym ** list,char ** tok)2519*4882a593Smuzhiyun process_fields(struct tep_event *event, struct tep_print_flag_sym **list, char **tok)
2520*4882a593Smuzhiyun {
2521*4882a593Smuzhiyun 	enum tep_event_type type;
2522*4882a593Smuzhiyun 	struct tep_print_arg *arg = NULL;
2523*4882a593Smuzhiyun 	struct tep_print_flag_sym *field;
2524*4882a593Smuzhiyun 	char *token = *tok;
2525*4882a593Smuzhiyun 	char *value;
2526*4882a593Smuzhiyun 
2527*4882a593Smuzhiyun 	do {
2528*4882a593Smuzhiyun 		free_token(token);
2529*4882a593Smuzhiyun 		type = read_token_item(&token);
2530*4882a593Smuzhiyun 		if (test_type_token(type, token, TEP_EVENT_OP, "{"))
2531*4882a593Smuzhiyun 			break;
2532*4882a593Smuzhiyun 
2533*4882a593Smuzhiyun 		arg = alloc_arg();
2534*4882a593Smuzhiyun 		if (!arg)
2535*4882a593Smuzhiyun 			goto out_free;
2536*4882a593Smuzhiyun 
2537*4882a593Smuzhiyun 		free_token(token);
2538*4882a593Smuzhiyun 		type = process_arg(event, arg, &token);
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 		if (type == TEP_EVENT_OP)
2541*4882a593Smuzhiyun 			type = process_op(event, arg, &token);
2542*4882a593Smuzhiyun 
2543*4882a593Smuzhiyun 		if (type == TEP_EVENT_ERROR)
2544*4882a593Smuzhiyun 			goto out_free;
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun 		if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
2547*4882a593Smuzhiyun 			goto out_free;
2548*4882a593Smuzhiyun 
2549*4882a593Smuzhiyun 		field = calloc(1, sizeof(*field));
2550*4882a593Smuzhiyun 		if (!field)
2551*4882a593Smuzhiyun 			goto out_free;
2552*4882a593Smuzhiyun 
2553*4882a593Smuzhiyun 		value = arg_eval(arg);
2554*4882a593Smuzhiyun 		if (value == NULL)
2555*4882a593Smuzhiyun 			goto out_free_field;
2556*4882a593Smuzhiyun 		field->value = strdup(value);
2557*4882a593Smuzhiyun 		if (field->value == NULL)
2558*4882a593Smuzhiyun 			goto out_free_field;
2559*4882a593Smuzhiyun 
2560*4882a593Smuzhiyun 		free_arg(arg);
2561*4882a593Smuzhiyun 		arg = alloc_arg();
2562*4882a593Smuzhiyun 		if (!arg)
2563*4882a593Smuzhiyun 			goto out_free;
2564*4882a593Smuzhiyun 
2565*4882a593Smuzhiyun 		free_token(token);
2566*4882a593Smuzhiyun 		type = process_arg(event, arg, &token);
2567*4882a593Smuzhiyun 		if (test_type_token(type, token, TEP_EVENT_OP, "}"))
2568*4882a593Smuzhiyun 			goto out_free_field;
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun 		value = arg_eval(arg);
2571*4882a593Smuzhiyun 		if (value == NULL)
2572*4882a593Smuzhiyun 			goto out_free_field;
2573*4882a593Smuzhiyun 		field->str = strdup(value);
2574*4882a593Smuzhiyun 		if (field->str == NULL)
2575*4882a593Smuzhiyun 			goto out_free_field;
2576*4882a593Smuzhiyun 		free_arg(arg);
2577*4882a593Smuzhiyun 		arg = NULL;
2578*4882a593Smuzhiyun 
2579*4882a593Smuzhiyun 		*list = field;
2580*4882a593Smuzhiyun 		list = &field->next;
2581*4882a593Smuzhiyun 
2582*4882a593Smuzhiyun 		free_token(token);
2583*4882a593Smuzhiyun 		type = read_token_item(&token);
2584*4882a593Smuzhiyun 	} while (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0);
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 	*tok = token;
2587*4882a593Smuzhiyun 	return type;
2588*4882a593Smuzhiyun 
2589*4882a593Smuzhiyun out_free_field:
2590*4882a593Smuzhiyun 	free_flag_sym(field);
2591*4882a593Smuzhiyun out_free:
2592*4882a593Smuzhiyun 	free_arg(arg);
2593*4882a593Smuzhiyun 	free_token(token);
2594*4882a593Smuzhiyun 	*tok = NULL;
2595*4882a593Smuzhiyun 
2596*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun static enum tep_event_type
process_flags(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2600*4882a593Smuzhiyun process_flags(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2601*4882a593Smuzhiyun {
2602*4882a593Smuzhiyun 	struct tep_print_arg *field;
2603*4882a593Smuzhiyun 	enum tep_event_type type;
2604*4882a593Smuzhiyun 	char *token = NULL;
2605*4882a593Smuzhiyun 
2606*4882a593Smuzhiyun 	memset(arg, 0, sizeof(*arg));
2607*4882a593Smuzhiyun 	arg->type = TEP_PRINT_FLAGS;
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun 	field = alloc_arg();
2610*4882a593Smuzhiyun 	if (!field) {
2611*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
2612*4882a593Smuzhiyun 		goto out_free;
2613*4882a593Smuzhiyun 	}
2614*4882a593Smuzhiyun 
2615*4882a593Smuzhiyun 	type = process_field_arg(event, field, &token);
2616*4882a593Smuzhiyun 
2617*4882a593Smuzhiyun 	/* Handle operations in the first argument */
2618*4882a593Smuzhiyun 	while (type == TEP_EVENT_OP)
2619*4882a593Smuzhiyun 		type = process_op(event, field, &token);
2620*4882a593Smuzhiyun 
2621*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
2622*4882a593Smuzhiyun 		goto out_free_field;
2623*4882a593Smuzhiyun 	free_token(token);
2624*4882a593Smuzhiyun 
2625*4882a593Smuzhiyun 	arg->flags.field = field;
2626*4882a593Smuzhiyun 
2627*4882a593Smuzhiyun 	type = read_token_item(&token);
2628*4882a593Smuzhiyun 	if (event_item_type(type)) {
2629*4882a593Smuzhiyun 		arg->flags.delim = token;
2630*4882a593Smuzhiyun 		type = read_token_item(&token);
2631*4882a593Smuzhiyun 	}
2632*4882a593Smuzhiyun 
2633*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
2634*4882a593Smuzhiyun 		goto out_free;
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun 	type = process_fields(event, &arg->flags.flags, &token);
2637*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ")"))
2638*4882a593Smuzhiyun 		goto out_free;
2639*4882a593Smuzhiyun 
2640*4882a593Smuzhiyun 	free_token(token);
2641*4882a593Smuzhiyun 	type = read_token_item(tok);
2642*4882a593Smuzhiyun 	return type;
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun out_free_field:
2645*4882a593Smuzhiyun 	free_arg(field);
2646*4882a593Smuzhiyun out_free:
2647*4882a593Smuzhiyun 	free_token(token);
2648*4882a593Smuzhiyun 	*tok = NULL;
2649*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2650*4882a593Smuzhiyun }
2651*4882a593Smuzhiyun 
2652*4882a593Smuzhiyun static enum tep_event_type
process_symbols(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2653*4882a593Smuzhiyun process_symbols(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2654*4882a593Smuzhiyun {
2655*4882a593Smuzhiyun 	struct tep_print_arg *field;
2656*4882a593Smuzhiyun 	enum tep_event_type type;
2657*4882a593Smuzhiyun 	char *token = NULL;
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun 	memset(arg, 0, sizeof(*arg));
2660*4882a593Smuzhiyun 	arg->type = TEP_PRINT_SYMBOL;
2661*4882a593Smuzhiyun 
2662*4882a593Smuzhiyun 	field = alloc_arg();
2663*4882a593Smuzhiyun 	if (!field) {
2664*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
2665*4882a593Smuzhiyun 		goto out_free;
2666*4882a593Smuzhiyun 	}
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 	type = process_field_arg(event, field, &token);
2669*4882a593Smuzhiyun 
2670*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
2671*4882a593Smuzhiyun 		goto out_free_field;
2672*4882a593Smuzhiyun 
2673*4882a593Smuzhiyun 	arg->symbol.field = field;
2674*4882a593Smuzhiyun 
2675*4882a593Smuzhiyun 	type = process_fields(event, &arg->symbol.symbols, &token);
2676*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ")"))
2677*4882a593Smuzhiyun 		goto out_free;
2678*4882a593Smuzhiyun 
2679*4882a593Smuzhiyun 	free_token(token);
2680*4882a593Smuzhiyun 	type = read_token_item(tok);
2681*4882a593Smuzhiyun 	return type;
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun out_free_field:
2684*4882a593Smuzhiyun 	free_arg(field);
2685*4882a593Smuzhiyun out_free:
2686*4882a593Smuzhiyun 	free_token(token);
2687*4882a593Smuzhiyun 	*tok = NULL;
2688*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2689*4882a593Smuzhiyun }
2690*4882a593Smuzhiyun 
2691*4882a593Smuzhiyun static enum tep_event_type
process_hex_common(struct tep_event * event,struct tep_print_arg * arg,char ** tok,enum tep_print_arg_type type)2692*4882a593Smuzhiyun process_hex_common(struct tep_event *event, struct tep_print_arg *arg,
2693*4882a593Smuzhiyun 		   char **tok, enum tep_print_arg_type type)
2694*4882a593Smuzhiyun {
2695*4882a593Smuzhiyun 	memset(arg, 0, sizeof(*arg));
2696*4882a593Smuzhiyun 	arg->type = type;
2697*4882a593Smuzhiyun 
2698*4882a593Smuzhiyun 	if (alloc_and_process_delim(event, ",", &arg->hex.field))
2699*4882a593Smuzhiyun 		goto out;
2700*4882a593Smuzhiyun 
2701*4882a593Smuzhiyun 	if (alloc_and_process_delim(event, ")", &arg->hex.size))
2702*4882a593Smuzhiyun 		goto free_field;
2703*4882a593Smuzhiyun 
2704*4882a593Smuzhiyun 	return read_token_item(tok);
2705*4882a593Smuzhiyun 
2706*4882a593Smuzhiyun free_field:
2707*4882a593Smuzhiyun 	free_arg(arg->hex.field);
2708*4882a593Smuzhiyun 	arg->hex.field = NULL;
2709*4882a593Smuzhiyun out:
2710*4882a593Smuzhiyun 	*tok = NULL;
2711*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2712*4882a593Smuzhiyun }
2713*4882a593Smuzhiyun 
2714*4882a593Smuzhiyun static enum tep_event_type
process_hex(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2715*4882a593Smuzhiyun process_hex(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2716*4882a593Smuzhiyun {
2717*4882a593Smuzhiyun 	return process_hex_common(event, arg, tok, TEP_PRINT_HEX);
2718*4882a593Smuzhiyun }
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun static enum tep_event_type
process_hex_str(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2721*4882a593Smuzhiyun process_hex_str(struct tep_event *event, struct tep_print_arg *arg,
2722*4882a593Smuzhiyun 		char **tok)
2723*4882a593Smuzhiyun {
2724*4882a593Smuzhiyun 	return process_hex_common(event, arg, tok, TEP_PRINT_HEX_STR);
2725*4882a593Smuzhiyun }
2726*4882a593Smuzhiyun 
2727*4882a593Smuzhiyun static enum tep_event_type
process_int_array(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2728*4882a593Smuzhiyun process_int_array(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2729*4882a593Smuzhiyun {
2730*4882a593Smuzhiyun 	memset(arg, 0, sizeof(*arg));
2731*4882a593Smuzhiyun 	arg->type = TEP_PRINT_INT_ARRAY;
2732*4882a593Smuzhiyun 
2733*4882a593Smuzhiyun 	if (alloc_and_process_delim(event, ",", &arg->int_array.field))
2734*4882a593Smuzhiyun 		goto out;
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	if (alloc_and_process_delim(event, ",", &arg->int_array.count))
2737*4882a593Smuzhiyun 		goto free_field;
2738*4882a593Smuzhiyun 
2739*4882a593Smuzhiyun 	if (alloc_and_process_delim(event, ")", &arg->int_array.el_size))
2740*4882a593Smuzhiyun 		goto free_size;
2741*4882a593Smuzhiyun 
2742*4882a593Smuzhiyun 	return read_token_item(tok);
2743*4882a593Smuzhiyun 
2744*4882a593Smuzhiyun free_size:
2745*4882a593Smuzhiyun 	free_arg(arg->int_array.count);
2746*4882a593Smuzhiyun 	arg->int_array.count = NULL;
2747*4882a593Smuzhiyun free_field:
2748*4882a593Smuzhiyun 	free_arg(arg->int_array.field);
2749*4882a593Smuzhiyun 	arg->int_array.field = NULL;
2750*4882a593Smuzhiyun out:
2751*4882a593Smuzhiyun 	*tok = NULL;
2752*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2753*4882a593Smuzhiyun }
2754*4882a593Smuzhiyun 
2755*4882a593Smuzhiyun static enum tep_event_type
process_dynamic_array(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2756*4882a593Smuzhiyun process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2757*4882a593Smuzhiyun {
2758*4882a593Smuzhiyun 	struct tep_format_field *field;
2759*4882a593Smuzhiyun 	enum tep_event_type type;
2760*4882a593Smuzhiyun 	char *token;
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun 	memset(arg, 0, sizeof(*arg));
2763*4882a593Smuzhiyun 	arg->type = TEP_PRINT_DYNAMIC_ARRAY;
2764*4882a593Smuzhiyun 
2765*4882a593Smuzhiyun 	/*
2766*4882a593Smuzhiyun 	 * The item within the parenthesis is another field that holds
2767*4882a593Smuzhiyun 	 * the index into where the array starts.
2768*4882a593Smuzhiyun 	 */
2769*4882a593Smuzhiyun 	type = read_token(&token);
2770*4882a593Smuzhiyun 	*tok = token;
2771*4882a593Smuzhiyun 	if (type != TEP_EVENT_ITEM)
2772*4882a593Smuzhiyun 		goto out_free;
2773*4882a593Smuzhiyun 
2774*4882a593Smuzhiyun 	/* Find the field */
2775*4882a593Smuzhiyun 
2776*4882a593Smuzhiyun 	field = tep_find_field(event, token);
2777*4882a593Smuzhiyun 	if (!field)
2778*4882a593Smuzhiyun 		goto out_free;
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	arg->dynarray.field = field;
2781*4882a593Smuzhiyun 	arg->dynarray.index = 0;
2782*4882a593Smuzhiyun 
2783*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
2784*4882a593Smuzhiyun 		goto out_free;
2785*4882a593Smuzhiyun 
2786*4882a593Smuzhiyun 	free_token(token);
2787*4882a593Smuzhiyun 	type = read_token_item(&token);
2788*4882a593Smuzhiyun 	*tok = token;
2789*4882a593Smuzhiyun 	if (type != TEP_EVENT_OP || strcmp(token, "[") != 0)
2790*4882a593Smuzhiyun 		return type;
2791*4882a593Smuzhiyun 
2792*4882a593Smuzhiyun 	free_token(token);
2793*4882a593Smuzhiyun 	arg = alloc_arg();
2794*4882a593Smuzhiyun 	if (!arg) {
2795*4882a593Smuzhiyun 		do_warning_event(event, "%s: not enough memory!", __func__);
2796*4882a593Smuzhiyun 		*tok = NULL;
2797*4882a593Smuzhiyun 		return TEP_EVENT_ERROR;
2798*4882a593Smuzhiyun 	}
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun 	type = process_arg(event, arg, &token);
2801*4882a593Smuzhiyun 	if (type == TEP_EVENT_ERROR)
2802*4882a593Smuzhiyun 		goto out_free_arg;
2803*4882a593Smuzhiyun 
2804*4882a593Smuzhiyun 	if (!test_type_token(type, token, TEP_EVENT_OP, "]"))
2805*4882a593Smuzhiyun 		goto out_free_arg;
2806*4882a593Smuzhiyun 
2807*4882a593Smuzhiyun 	free_token(token);
2808*4882a593Smuzhiyun 	type = read_token_item(tok);
2809*4882a593Smuzhiyun 	return type;
2810*4882a593Smuzhiyun 
2811*4882a593Smuzhiyun  out_free_arg:
2812*4882a593Smuzhiyun 	free_arg(arg);
2813*4882a593Smuzhiyun  out_free:
2814*4882a593Smuzhiyun 	free_token(token);
2815*4882a593Smuzhiyun 	*tok = NULL;
2816*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2817*4882a593Smuzhiyun }
2818*4882a593Smuzhiyun 
2819*4882a593Smuzhiyun static enum tep_event_type
process_dynamic_array_len(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2820*4882a593Smuzhiyun process_dynamic_array_len(struct tep_event *event, struct tep_print_arg *arg,
2821*4882a593Smuzhiyun 			  char **tok)
2822*4882a593Smuzhiyun {
2823*4882a593Smuzhiyun 	struct tep_format_field *field;
2824*4882a593Smuzhiyun 	enum tep_event_type type;
2825*4882a593Smuzhiyun 	char *token;
2826*4882a593Smuzhiyun 
2827*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
2828*4882a593Smuzhiyun 		goto out_free;
2829*4882a593Smuzhiyun 
2830*4882a593Smuzhiyun 	arg->type = TEP_PRINT_DYNAMIC_ARRAY_LEN;
2831*4882a593Smuzhiyun 
2832*4882a593Smuzhiyun 	/* Find the field */
2833*4882a593Smuzhiyun 	field = tep_find_field(event, token);
2834*4882a593Smuzhiyun 	if (!field)
2835*4882a593Smuzhiyun 		goto out_free;
2836*4882a593Smuzhiyun 
2837*4882a593Smuzhiyun 	arg->dynarray.field = field;
2838*4882a593Smuzhiyun 	arg->dynarray.index = 0;
2839*4882a593Smuzhiyun 
2840*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
2841*4882a593Smuzhiyun 		goto out_err;
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 	free_token(token);
2844*4882a593Smuzhiyun 	type = read_token(&token);
2845*4882a593Smuzhiyun 	*tok = token;
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun 	return type;
2848*4882a593Smuzhiyun 
2849*4882a593Smuzhiyun  out_free:
2850*4882a593Smuzhiyun 	free_token(token);
2851*4882a593Smuzhiyun  out_err:
2852*4882a593Smuzhiyun 	*tok = NULL;
2853*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2854*4882a593Smuzhiyun }
2855*4882a593Smuzhiyun 
2856*4882a593Smuzhiyun static enum tep_event_type
process_paren(struct tep_event * event,struct tep_print_arg * arg,char ** tok)2857*4882a593Smuzhiyun process_paren(struct tep_event *event, struct tep_print_arg *arg, char **tok)
2858*4882a593Smuzhiyun {
2859*4882a593Smuzhiyun 	struct tep_print_arg *item_arg;
2860*4882a593Smuzhiyun 	enum tep_event_type type;
2861*4882a593Smuzhiyun 	char *token;
2862*4882a593Smuzhiyun 
2863*4882a593Smuzhiyun 	type = process_arg(event, arg, &token);
2864*4882a593Smuzhiyun 
2865*4882a593Smuzhiyun 	if (type == TEP_EVENT_ERROR)
2866*4882a593Smuzhiyun 		goto out_free;
2867*4882a593Smuzhiyun 
2868*4882a593Smuzhiyun 	if (type == TEP_EVENT_OP)
2869*4882a593Smuzhiyun 		type = process_op(event, arg, &token);
2870*4882a593Smuzhiyun 
2871*4882a593Smuzhiyun 	if (type == TEP_EVENT_ERROR)
2872*4882a593Smuzhiyun 		goto out_free;
2873*4882a593Smuzhiyun 
2874*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ")"))
2875*4882a593Smuzhiyun 		goto out_free;
2876*4882a593Smuzhiyun 
2877*4882a593Smuzhiyun 	free_token(token);
2878*4882a593Smuzhiyun 	type = read_token_item(&token);
2879*4882a593Smuzhiyun 
2880*4882a593Smuzhiyun 	/*
2881*4882a593Smuzhiyun 	 * If the next token is an item or another open paren, then
2882*4882a593Smuzhiyun 	 * this was a typecast.
2883*4882a593Smuzhiyun 	 */
2884*4882a593Smuzhiyun 	if (event_item_type(type) ||
2885*4882a593Smuzhiyun 	    (type == TEP_EVENT_DELIM && strcmp(token, "(") == 0)) {
2886*4882a593Smuzhiyun 
2887*4882a593Smuzhiyun 		/* make this a typecast and contine */
2888*4882a593Smuzhiyun 
2889*4882a593Smuzhiyun 		/* prevous must be an atom */
2890*4882a593Smuzhiyun 		if (arg->type != TEP_PRINT_ATOM) {
2891*4882a593Smuzhiyun 			do_warning_event(event, "previous needed to be TEP_PRINT_ATOM");
2892*4882a593Smuzhiyun 			goto out_free;
2893*4882a593Smuzhiyun 		}
2894*4882a593Smuzhiyun 
2895*4882a593Smuzhiyun 		item_arg = alloc_arg();
2896*4882a593Smuzhiyun 		if (!item_arg) {
2897*4882a593Smuzhiyun 			do_warning_event(event, "%s: not enough memory!",
2898*4882a593Smuzhiyun 					 __func__);
2899*4882a593Smuzhiyun 			goto out_free;
2900*4882a593Smuzhiyun 		}
2901*4882a593Smuzhiyun 
2902*4882a593Smuzhiyun 		arg->type = TEP_PRINT_TYPE;
2903*4882a593Smuzhiyun 		arg->typecast.type = arg->atom.atom;
2904*4882a593Smuzhiyun 		arg->typecast.item = item_arg;
2905*4882a593Smuzhiyun 		type = process_arg_token(event, item_arg, &token, type);
2906*4882a593Smuzhiyun 
2907*4882a593Smuzhiyun 	}
2908*4882a593Smuzhiyun 
2909*4882a593Smuzhiyun 	*tok = token;
2910*4882a593Smuzhiyun 	return type;
2911*4882a593Smuzhiyun 
2912*4882a593Smuzhiyun  out_free:
2913*4882a593Smuzhiyun 	free_token(token);
2914*4882a593Smuzhiyun 	*tok = NULL;
2915*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2916*4882a593Smuzhiyun }
2917*4882a593Smuzhiyun 
2918*4882a593Smuzhiyun 
2919*4882a593Smuzhiyun static enum tep_event_type
process_str(struct tep_event * event __maybe_unused,struct tep_print_arg * arg,char ** tok)2920*4882a593Smuzhiyun process_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
2921*4882a593Smuzhiyun 	    char **tok)
2922*4882a593Smuzhiyun {
2923*4882a593Smuzhiyun 	enum tep_event_type type;
2924*4882a593Smuzhiyun 	char *token;
2925*4882a593Smuzhiyun 
2926*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
2927*4882a593Smuzhiyun 		goto out_free;
2928*4882a593Smuzhiyun 
2929*4882a593Smuzhiyun 	arg->type = TEP_PRINT_STRING;
2930*4882a593Smuzhiyun 	arg->string.string = token;
2931*4882a593Smuzhiyun 	arg->string.offset = -1;
2932*4882a593Smuzhiyun 
2933*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
2934*4882a593Smuzhiyun 		goto out_err;
2935*4882a593Smuzhiyun 
2936*4882a593Smuzhiyun 	type = read_token(&token);
2937*4882a593Smuzhiyun 	*tok = token;
2938*4882a593Smuzhiyun 
2939*4882a593Smuzhiyun 	return type;
2940*4882a593Smuzhiyun 
2941*4882a593Smuzhiyun  out_free:
2942*4882a593Smuzhiyun 	free_token(token);
2943*4882a593Smuzhiyun  out_err:
2944*4882a593Smuzhiyun 	*tok = NULL;
2945*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2946*4882a593Smuzhiyun }
2947*4882a593Smuzhiyun 
2948*4882a593Smuzhiyun static enum tep_event_type
process_bitmask(struct tep_event * event __maybe_unused,struct tep_print_arg * arg,char ** tok)2949*4882a593Smuzhiyun process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
2950*4882a593Smuzhiyun 		char **tok)
2951*4882a593Smuzhiyun {
2952*4882a593Smuzhiyun 	enum tep_event_type type;
2953*4882a593Smuzhiyun 	char *token;
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
2956*4882a593Smuzhiyun 		goto out_free;
2957*4882a593Smuzhiyun 
2958*4882a593Smuzhiyun 	arg->type = TEP_PRINT_BITMASK;
2959*4882a593Smuzhiyun 	arg->bitmask.bitmask = token;
2960*4882a593Smuzhiyun 	arg->bitmask.offset = -1;
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
2963*4882a593Smuzhiyun 		goto out_err;
2964*4882a593Smuzhiyun 
2965*4882a593Smuzhiyun 	type = read_token(&token);
2966*4882a593Smuzhiyun 	*tok = token;
2967*4882a593Smuzhiyun 
2968*4882a593Smuzhiyun 	return type;
2969*4882a593Smuzhiyun 
2970*4882a593Smuzhiyun  out_free:
2971*4882a593Smuzhiyun 	free_token(token);
2972*4882a593Smuzhiyun  out_err:
2973*4882a593Smuzhiyun 	*tok = NULL;
2974*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
2975*4882a593Smuzhiyun }
2976*4882a593Smuzhiyun 
2977*4882a593Smuzhiyun static struct tep_function_handler *
find_func_handler(struct tep_handle * tep,char * func_name)2978*4882a593Smuzhiyun find_func_handler(struct tep_handle *tep, char *func_name)
2979*4882a593Smuzhiyun {
2980*4882a593Smuzhiyun 	struct tep_function_handler *func;
2981*4882a593Smuzhiyun 
2982*4882a593Smuzhiyun 	if (!tep)
2983*4882a593Smuzhiyun 		return NULL;
2984*4882a593Smuzhiyun 
2985*4882a593Smuzhiyun 	for (func = tep->func_handlers; func; func = func->next) {
2986*4882a593Smuzhiyun 		if (strcmp(func->name, func_name) == 0)
2987*4882a593Smuzhiyun 			break;
2988*4882a593Smuzhiyun 	}
2989*4882a593Smuzhiyun 
2990*4882a593Smuzhiyun 	return func;
2991*4882a593Smuzhiyun }
2992*4882a593Smuzhiyun 
remove_func_handler(struct tep_handle * tep,char * func_name)2993*4882a593Smuzhiyun static void remove_func_handler(struct tep_handle *tep, char *func_name)
2994*4882a593Smuzhiyun {
2995*4882a593Smuzhiyun 	struct tep_function_handler *func;
2996*4882a593Smuzhiyun 	struct tep_function_handler **next;
2997*4882a593Smuzhiyun 
2998*4882a593Smuzhiyun 	next = &tep->func_handlers;
2999*4882a593Smuzhiyun 	while ((func = *next)) {
3000*4882a593Smuzhiyun 		if (strcmp(func->name, func_name) == 0) {
3001*4882a593Smuzhiyun 			*next = func->next;
3002*4882a593Smuzhiyun 			free_func_handle(func);
3003*4882a593Smuzhiyun 			break;
3004*4882a593Smuzhiyun 		}
3005*4882a593Smuzhiyun 		next = &func->next;
3006*4882a593Smuzhiyun 	}
3007*4882a593Smuzhiyun }
3008*4882a593Smuzhiyun 
3009*4882a593Smuzhiyun static enum tep_event_type
process_func_handler(struct tep_event * event,struct tep_function_handler * func,struct tep_print_arg * arg,char ** tok)3010*4882a593Smuzhiyun process_func_handler(struct tep_event *event, struct tep_function_handler *func,
3011*4882a593Smuzhiyun 		     struct tep_print_arg *arg, char **tok)
3012*4882a593Smuzhiyun {
3013*4882a593Smuzhiyun 	struct tep_print_arg **next_arg;
3014*4882a593Smuzhiyun 	struct tep_print_arg *farg;
3015*4882a593Smuzhiyun 	enum tep_event_type type;
3016*4882a593Smuzhiyun 	char *token;
3017*4882a593Smuzhiyun 	int i;
3018*4882a593Smuzhiyun 
3019*4882a593Smuzhiyun 	arg->type = TEP_PRINT_FUNC;
3020*4882a593Smuzhiyun 	arg->func.func = func;
3021*4882a593Smuzhiyun 
3022*4882a593Smuzhiyun 	*tok = NULL;
3023*4882a593Smuzhiyun 
3024*4882a593Smuzhiyun 	next_arg = &(arg->func.args);
3025*4882a593Smuzhiyun 	for (i = 0; i < func->nr_args; i++) {
3026*4882a593Smuzhiyun 		farg = alloc_arg();
3027*4882a593Smuzhiyun 		if (!farg) {
3028*4882a593Smuzhiyun 			do_warning_event(event, "%s: not enough memory!",
3029*4882a593Smuzhiyun 					 __func__);
3030*4882a593Smuzhiyun 			return TEP_EVENT_ERROR;
3031*4882a593Smuzhiyun 		}
3032*4882a593Smuzhiyun 
3033*4882a593Smuzhiyun 		type = process_arg(event, farg, &token);
3034*4882a593Smuzhiyun 		if (i < (func->nr_args - 1)) {
3035*4882a593Smuzhiyun 			if (type != TEP_EVENT_DELIM || strcmp(token, ",") != 0) {
3036*4882a593Smuzhiyun 				do_warning_event(event,
3037*4882a593Smuzhiyun 					"Error: function '%s()' expects %d arguments but event %s only uses %d",
3038*4882a593Smuzhiyun 					func->name, func->nr_args,
3039*4882a593Smuzhiyun 					event->name, i + 1);
3040*4882a593Smuzhiyun 				goto err;
3041*4882a593Smuzhiyun 			}
3042*4882a593Smuzhiyun 		} else {
3043*4882a593Smuzhiyun 			if (type != TEP_EVENT_DELIM || strcmp(token, ")") != 0) {
3044*4882a593Smuzhiyun 				do_warning_event(event,
3045*4882a593Smuzhiyun 					"Error: function '%s()' only expects %d arguments but event %s has more",
3046*4882a593Smuzhiyun 					func->name, func->nr_args, event->name);
3047*4882a593Smuzhiyun 				goto err;
3048*4882a593Smuzhiyun 			}
3049*4882a593Smuzhiyun 		}
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 		*next_arg = farg;
3052*4882a593Smuzhiyun 		next_arg = &(farg->next);
3053*4882a593Smuzhiyun 		free_token(token);
3054*4882a593Smuzhiyun 	}
3055*4882a593Smuzhiyun 
3056*4882a593Smuzhiyun 	type = read_token(&token);
3057*4882a593Smuzhiyun 	*tok = token;
3058*4882a593Smuzhiyun 
3059*4882a593Smuzhiyun 	return type;
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun err:
3062*4882a593Smuzhiyun 	free_arg(farg);
3063*4882a593Smuzhiyun 	free_token(token);
3064*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
3065*4882a593Smuzhiyun }
3066*4882a593Smuzhiyun 
3067*4882a593Smuzhiyun static enum tep_event_type
process_builtin_expect(struct tep_event * event,struct tep_print_arg * arg,char ** tok)3068*4882a593Smuzhiyun process_builtin_expect(struct tep_event *event, struct tep_print_arg *arg, char **tok)
3069*4882a593Smuzhiyun {
3070*4882a593Smuzhiyun 	enum tep_event_type type;
3071*4882a593Smuzhiyun 	char *token = NULL;
3072*4882a593Smuzhiyun 
3073*4882a593Smuzhiyun 	/* Handle __builtin_expect( cond, #) */
3074*4882a593Smuzhiyun 	type = process_arg(event, arg, &token);
3075*4882a593Smuzhiyun 
3076*4882a593Smuzhiyun 	if (type != TEP_EVENT_DELIM || token[0] != ',')
3077*4882a593Smuzhiyun 		goto out_free;
3078*4882a593Smuzhiyun 
3079*4882a593Smuzhiyun 	free_token(token);
3080*4882a593Smuzhiyun 
3081*4882a593Smuzhiyun 	/* We don't care what the second parameter is of the __builtin_expect() */
3082*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
3083*4882a593Smuzhiyun 		goto out_free;
3084*4882a593Smuzhiyun 
3085*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
3086*4882a593Smuzhiyun 		goto out_free;
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 	free_token(token);
3089*4882a593Smuzhiyun 	type = read_token_item(tok);
3090*4882a593Smuzhiyun 	return type;
3091*4882a593Smuzhiyun 
3092*4882a593Smuzhiyun out_free:
3093*4882a593Smuzhiyun 	free_token(token);
3094*4882a593Smuzhiyun 	*tok = NULL;
3095*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
3096*4882a593Smuzhiyun }
3097*4882a593Smuzhiyun 
3098*4882a593Smuzhiyun static enum tep_event_type
process_function(struct tep_event * event,struct tep_print_arg * arg,char * token,char ** tok)3099*4882a593Smuzhiyun process_function(struct tep_event *event, struct tep_print_arg *arg,
3100*4882a593Smuzhiyun 		 char *token, char **tok)
3101*4882a593Smuzhiyun {
3102*4882a593Smuzhiyun 	struct tep_function_handler *func;
3103*4882a593Smuzhiyun 
3104*4882a593Smuzhiyun 	if (strcmp(token, "__print_flags") == 0) {
3105*4882a593Smuzhiyun 		free_token(token);
3106*4882a593Smuzhiyun 		is_flag_field = 1;
3107*4882a593Smuzhiyun 		return process_flags(event, arg, tok);
3108*4882a593Smuzhiyun 	}
3109*4882a593Smuzhiyun 	if (strcmp(token, "__print_symbolic") == 0) {
3110*4882a593Smuzhiyun 		free_token(token);
3111*4882a593Smuzhiyun 		is_symbolic_field = 1;
3112*4882a593Smuzhiyun 		return process_symbols(event, arg, tok);
3113*4882a593Smuzhiyun 	}
3114*4882a593Smuzhiyun 	if (strcmp(token, "__print_hex") == 0) {
3115*4882a593Smuzhiyun 		free_token(token);
3116*4882a593Smuzhiyun 		return process_hex(event, arg, tok);
3117*4882a593Smuzhiyun 	}
3118*4882a593Smuzhiyun 	if (strcmp(token, "__print_hex_str") == 0) {
3119*4882a593Smuzhiyun 		free_token(token);
3120*4882a593Smuzhiyun 		return process_hex_str(event, arg, tok);
3121*4882a593Smuzhiyun 	}
3122*4882a593Smuzhiyun 	if (strcmp(token, "__print_array") == 0) {
3123*4882a593Smuzhiyun 		free_token(token);
3124*4882a593Smuzhiyun 		return process_int_array(event, arg, tok);
3125*4882a593Smuzhiyun 	}
3126*4882a593Smuzhiyun 	if (strcmp(token, "__get_str") == 0) {
3127*4882a593Smuzhiyun 		free_token(token);
3128*4882a593Smuzhiyun 		return process_str(event, arg, tok);
3129*4882a593Smuzhiyun 	}
3130*4882a593Smuzhiyun 	if (strcmp(token, "__get_bitmask") == 0) {
3131*4882a593Smuzhiyun 		free_token(token);
3132*4882a593Smuzhiyun 		return process_bitmask(event, arg, tok);
3133*4882a593Smuzhiyun 	}
3134*4882a593Smuzhiyun 	if (strcmp(token, "__get_dynamic_array") == 0) {
3135*4882a593Smuzhiyun 		free_token(token);
3136*4882a593Smuzhiyun 		return process_dynamic_array(event, arg, tok);
3137*4882a593Smuzhiyun 	}
3138*4882a593Smuzhiyun 	if (strcmp(token, "__get_dynamic_array_len") == 0) {
3139*4882a593Smuzhiyun 		free_token(token);
3140*4882a593Smuzhiyun 		return process_dynamic_array_len(event, arg, tok);
3141*4882a593Smuzhiyun 	}
3142*4882a593Smuzhiyun 	if (strcmp(token, "__builtin_expect") == 0) {
3143*4882a593Smuzhiyun 		free_token(token);
3144*4882a593Smuzhiyun 		return process_builtin_expect(event, arg, tok);
3145*4882a593Smuzhiyun 	}
3146*4882a593Smuzhiyun 
3147*4882a593Smuzhiyun 	func = find_func_handler(event->tep, token);
3148*4882a593Smuzhiyun 	if (func) {
3149*4882a593Smuzhiyun 		free_token(token);
3150*4882a593Smuzhiyun 		return process_func_handler(event, func, arg, tok);
3151*4882a593Smuzhiyun 	}
3152*4882a593Smuzhiyun 
3153*4882a593Smuzhiyun 	do_warning_event(event, "function %s not defined", token);
3154*4882a593Smuzhiyun 	free_token(token);
3155*4882a593Smuzhiyun 	return TEP_EVENT_ERROR;
3156*4882a593Smuzhiyun }
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun static enum tep_event_type
process_arg_token(struct tep_event * event,struct tep_print_arg * arg,char ** tok,enum tep_event_type type)3159*4882a593Smuzhiyun process_arg_token(struct tep_event *event, struct tep_print_arg *arg,
3160*4882a593Smuzhiyun 		  char **tok, enum tep_event_type type)
3161*4882a593Smuzhiyun {
3162*4882a593Smuzhiyun 	char *token;
3163*4882a593Smuzhiyun 	char *atom;
3164*4882a593Smuzhiyun 
3165*4882a593Smuzhiyun 	token = *tok;
3166*4882a593Smuzhiyun 
3167*4882a593Smuzhiyun 	switch (type) {
3168*4882a593Smuzhiyun 	case TEP_EVENT_ITEM:
3169*4882a593Smuzhiyun 		if (strcmp(token, "REC") == 0) {
3170*4882a593Smuzhiyun 			free_token(token);
3171*4882a593Smuzhiyun 			type = process_entry(event, arg, &token);
3172*4882a593Smuzhiyun 			break;
3173*4882a593Smuzhiyun 		}
3174*4882a593Smuzhiyun 		atom = token;
3175*4882a593Smuzhiyun 		/* test the next token */
3176*4882a593Smuzhiyun 		type = read_token_item(&token);
3177*4882a593Smuzhiyun 
3178*4882a593Smuzhiyun 		/*
3179*4882a593Smuzhiyun 		 * If the next token is a parenthesis, then this
3180*4882a593Smuzhiyun 		 * is a function.
3181*4882a593Smuzhiyun 		 */
3182*4882a593Smuzhiyun 		if (type == TEP_EVENT_DELIM && strcmp(token, "(") == 0) {
3183*4882a593Smuzhiyun 			free_token(token);
3184*4882a593Smuzhiyun 			token = NULL;
3185*4882a593Smuzhiyun 			/* this will free atom. */
3186*4882a593Smuzhiyun 			type = process_function(event, arg, atom, &token);
3187*4882a593Smuzhiyun 			break;
3188*4882a593Smuzhiyun 		}
3189*4882a593Smuzhiyun 		/* atoms can be more than one token long */
3190*4882a593Smuzhiyun 		while (type == TEP_EVENT_ITEM) {
3191*4882a593Smuzhiyun 			int ret;
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun 			ret = append(&atom, " ", token);
3194*4882a593Smuzhiyun 			if (ret < 0) {
3195*4882a593Smuzhiyun 				free(atom);
3196*4882a593Smuzhiyun 				*tok = NULL;
3197*4882a593Smuzhiyun 				free_token(token);
3198*4882a593Smuzhiyun 				return TEP_EVENT_ERROR;
3199*4882a593Smuzhiyun 			}
3200*4882a593Smuzhiyun 			free_token(token);
3201*4882a593Smuzhiyun 			type = read_token_item(&token);
3202*4882a593Smuzhiyun 		}
3203*4882a593Smuzhiyun 
3204*4882a593Smuzhiyun 		arg->type = TEP_PRINT_ATOM;
3205*4882a593Smuzhiyun 		arg->atom.atom = atom;
3206*4882a593Smuzhiyun 		break;
3207*4882a593Smuzhiyun 
3208*4882a593Smuzhiyun 	case TEP_EVENT_DQUOTE:
3209*4882a593Smuzhiyun 	case TEP_EVENT_SQUOTE:
3210*4882a593Smuzhiyun 		arg->type = TEP_PRINT_ATOM;
3211*4882a593Smuzhiyun 		arg->atom.atom = token;
3212*4882a593Smuzhiyun 		type = read_token_item(&token);
3213*4882a593Smuzhiyun 		break;
3214*4882a593Smuzhiyun 	case TEP_EVENT_DELIM:
3215*4882a593Smuzhiyun 		if (strcmp(token, "(") == 0) {
3216*4882a593Smuzhiyun 			free_token(token);
3217*4882a593Smuzhiyun 			type = process_paren(event, arg, &token);
3218*4882a593Smuzhiyun 			break;
3219*4882a593Smuzhiyun 		}
3220*4882a593Smuzhiyun 	case TEP_EVENT_OP:
3221*4882a593Smuzhiyun 		/* handle single ops */
3222*4882a593Smuzhiyun 		arg->type = TEP_PRINT_OP;
3223*4882a593Smuzhiyun 		arg->op.op = token;
3224*4882a593Smuzhiyun 		arg->op.left = NULL;
3225*4882a593Smuzhiyun 		type = process_op(event, arg, &token);
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun 		/* On error, the op is freed */
3228*4882a593Smuzhiyun 		if (type == TEP_EVENT_ERROR)
3229*4882a593Smuzhiyun 			arg->op.op = NULL;
3230*4882a593Smuzhiyun 
3231*4882a593Smuzhiyun 		/* return error type if errored */
3232*4882a593Smuzhiyun 		break;
3233*4882a593Smuzhiyun 
3234*4882a593Smuzhiyun 	case TEP_EVENT_ERROR ... TEP_EVENT_NEWLINE:
3235*4882a593Smuzhiyun 	default:
3236*4882a593Smuzhiyun 		do_warning_event(event, "unexpected type %d", type);
3237*4882a593Smuzhiyun 		return TEP_EVENT_ERROR;
3238*4882a593Smuzhiyun 	}
3239*4882a593Smuzhiyun 	*tok = token;
3240*4882a593Smuzhiyun 
3241*4882a593Smuzhiyun 	return type;
3242*4882a593Smuzhiyun }
3243*4882a593Smuzhiyun 
event_read_print_args(struct tep_event * event,struct tep_print_arg ** list)3244*4882a593Smuzhiyun static int event_read_print_args(struct tep_event *event, struct tep_print_arg **list)
3245*4882a593Smuzhiyun {
3246*4882a593Smuzhiyun 	enum tep_event_type type = TEP_EVENT_ERROR;
3247*4882a593Smuzhiyun 	struct tep_print_arg *arg;
3248*4882a593Smuzhiyun 	char *token;
3249*4882a593Smuzhiyun 	int args = 0;
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun 	do {
3252*4882a593Smuzhiyun 		if (type == TEP_EVENT_NEWLINE) {
3253*4882a593Smuzhiyun 			type = read_token_item(&token);
3254*4882a593Smuzhiyun 			continue;
3255*4882a593Smuzhiyun 		}
3256*4882a593Smuzhiyun 
3257*4882a593Smuzhiyun 		arg = alloc_arg();
3258*4882a593Smuzhiyun 		if (!arg) {
3259*4882a593Smuzhiyun 			do_warning_event(event, "%s: not enough memory!",
3260*4882a593Smuzhiyun 					 __func__);
3261*4882a593Smuzhiyun 			return -1;
3262*4882a593Smuzhiyun 		}
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 		type = process_arg(event, arg, &token);
3265*4882a593Smuzhiyun 
3266*4882a593Smuzhiyun 		if (type == TEP_EVENT_ERROR) {
3267*4882a593Smuzhiyun 			free_token(token);
3268*4882a593Smuzhiyun 			free_arg(arg);
3269*4882a593Smuzhiyun 			return -1;
3270*4882a593Smuzhiyun 		}
3271*4882a593Smuzhiyun 
3272*4882a593Smuzhiyun 		*list = arg;
3273*4882a593Smuzhiyun 		args++;
3274*4882a593Smuzhiyun 
3275*4882a593Smuzhiyun 		if (type == TEP_EVENT_OP) {
3276*4882a593Smuzhiyun 			type = process_op(event, arg, &token);
3277*4882a593Smuzhiyun 			free_token(token);
3278*4882a593Smuzhiyun 			if (type == TEP_EVENT_ERROR) {
3279*4882a593Smuzhiyun 				*list = NULL;
3280*4882a593Smuzhiyun 				free_arg(arg);
3281*4882a593Smuzhiyun 				return -1;
3282*4882a593Smuzhiyun 			}
3283*4882a593Smuzhiyun 			list = &arg->next;
3284*4882a593Smuzhiyun 			continue;
3285*4882a593Smuzhiyun 		}
3286*4882a593Smuzhiyun 
3287*4882a593Smuzhiyun 		if (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0) {
3288*4882a593Smuzhiyun 			free_token(token);
3289*4882a593Smuzhiyun 			*list = arg;
3290*4882a593Smuzhiyun 			list = &arg->next;
3291*4882a593Smuzhiyun 			continue;
3292*4882a593Smuzhiyun 		}
3293*4882a593Smuzhiyun 		break;
3294*4882a593Smuzhiyun 	} while (type != TEP_EVENT_NONE);
3295*4882a593Smuzhiyun 
3296*4882a593Smuzhiyun 	if (type != TEP_EVENT_NONE && type != TEP_EVENT_ERROR)
3297*4882a593Smuzhiyun 		free_token(token);
3298*4882a593Smuzhiyun 
3299*4882a593Smuzhiyun 	return args;
3300*4882a593Smuzhiyun }
3301*4882a593Smuzhiyun 
event_read_print(struct tep_event * event)3302*4882a593Smuzhiyun static int event_read_print(struct tep_event *event)
3303*4882a593Smuzhiyun {
3304*4882a593Smuzhiyun 	enum tep_event_type type;
3305*4882a593Smuzhiyun 	char *token;
3306*4882a593Smuzhiyun 	int ret;
3307*4882a593Smuzhiyun 
3308*4882a593Smuzhiyun 	if (read_expected_item(TEP_EVENT_ITEM, "print") < 0)
3309*4882a593Smuzhiyun 		return -1;
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_ITEM, "fmt") < 0)
3312*4882a593Smuzhiyun 		return -1;
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
3315*4882a593Smuzhiyun 		return -1;
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_DQUOTE, &token) < 0)
3318*4882a593Smuzhiyun 		goto fail;
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun  concat:
3321*4882a593Smuzhiyun 	event->print_fmt.format = token;
3322*4882a593Smuzhiyun 	event->print_fmt.args = NULL;
3323*4882a593Smuzhiyun 
3324*4882a593Smuzhiyun 	/* ok to have no arg */
3325*4882a593Smuzhiyun 	type = read_token_item(&token);
3326*4882a593Smuzhiyun 
3327*4882a593Smuzhiyun 	if (type == TEP_EVENT_NONE)
3328*4882a593Smuzhiyun 		return 0;
3329*4882a593Smuzhiyun 
3330*4882a593Smuzhiyun 	/* Handle concatenation of print lines */
3331*4882a593Smuzhiyun 	if (type == TEP_EVENT_DQUOTE) {
3332*4882a593Smuzhiyun 		char *cat;
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun 		if (asprintf(&cat, "%s%s", event->print_fmt.format, token) < 0)
3335*4882a593Smuzhiyun 			goto fail;
3336*4882a593Smuzhiyun 		free_token(token);
3337*4882a593Smuzhiyun 		free_token(event->print_fmt.format);
3338*4882a593Smuzhiyun 		event->print_fmt.format = NULL;
3339*4882a593Smuzhiyun 		token = cat;
3340*4882a593Smuzhiyun 		goto concat;
3341*4882a593Smuzhiyun 	}
3342*4882a593Smuzhiyun 
3343*4882a593Smuzhiyun 	if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
3344*4882a593Smuzhiyun 		goto fail;
3345*4882a593Smuzhiyun 
3346*4882a593Smuzhiyun 	free_token(token);
3347*4882a593Smuzhiyun 
3348*4882a593Smuzhiyun 	ret = event_read_print_args(event, &event->print_fmt.args);
3349*4882a593Smuzhiyun 	if (ret < 0)
3350*4882a593Smuzhiyun 		return -1;
3351*4882a593Smuzhiyun 
3352*4882a593Smuzhiyun 	return ret;
3353*4882a593Smuzhiyun 
3354*4882a593Smuzhiyun  fail:
3355*4882a593Smuzhiyun 	free_token(token);
3356*4882a593Smuzhiyun 	return -1;
3357*4882a593Smuzhiyun }
3358*4882a593Smuzhiyun 
3359*4882a593Smuzhiyun /**
3360*4882a593Smuzhiyun  * tep_find_common_field - return a common field by event
3361*4882a593Smuzhiyun  * @event: handle for the event
3362*4882a593Smuzhiyun  * @name: the name of the common field to return
3363*4882a593Smuzhiyun  *
3364*4882a593Smuzhiyun  * Returns a common field from the event by the given @name.
3365*4882a593Smuzhiyun  * This only searches the common fields and not all field.
3366*4882a593Smuzhiyun  */
3367*4882a593Smuzhiyun struct tep_format_field *
tep_find_common_field(struct tep_event * event,const char * name)3368*4882a593Smuzhiyun tep_find_common_field(struct tep_event *event, const char *name)
3369*4882a593Smuzhiyun {
3370*4882a593Smuzhiyun 	struct tep_format_field *format;
3371*4882a593Smuzhiyun 
3372*4882a593Smuzhiyun 	for (format = event->format.common_fields;
3373*4882a593Smuzhiyun 	     format; format = format->next) {
3374*4882a593Smuzhiyun 		if (strcmp(format->name, name) == 0)
3375*4882a593Smuzhiyun 			break;
3376*4882a593Smuzhiyun 	}
3377*4882a593Smuzhiyun 
3378*4882a593Smuzhiyun 	return format;
3379*4882a593Smuzhiyun }
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun /**
3382*4882a593Smuzhiyun  * tep_find_field - find a non-common field
3383*4882a593Smuzhiyun  * @event: handle for the event
3384*4882a593Smuzhiyun  * @name: the name of the non-common field
3385*4882a593Smuzhiyun  *
3386*4882a593Smuzhiyun  * Returns a non-common field by the given @name.
3387*4882a593Smuzhiyun  * This does not search common fields.
3388*4882a593Smuzhiyun  */
3389*4882a593Smuzhiyun struct tep_format_field *
tep_find_field(struct tep_event * event,const char * name)3390*4882a593Smuzhiyun tep_find_field(struct tep_event *event, const char *name)
3391*4882a593Smuzhiyun {
3392*4882a593Smuzhiyun 	struct tep_format_field *format;
3393*4882a593Smuzhiyun 
3394*4882a593Smuzhiyun 	for (format = event->format.fields;
3395*4882a593Smuzhiyun 	     format; format = format->next) {
3396*4882a593Smuzhiyun 		if (strcmp(format->name, name) == 0)
3397*4882a593Smuzhiyun 			break;
3398*4882a593Smuzhiyun 	}
3399*4882a593Smuzhiyun 
3400*4882a593Smuzhiyun 	return format;
3401*4882a593Smuzhiyun }
3402*4882a593Smuzhiyun 
3403*4882a593Smuzhiyun /**
3404*4882a593Smuzhiyun  * tep_find_any_field - find any field by name
3405*4882a593Smuzhiyun  * @event: handle for the event
3406*4882a593Smuzhiyun  * @name: the name of the field
3407*4882a593Smuzhiyun  *
3408*4882a593Smuzhiyun  * Returns a field by the given @name.
3409*4882a593Smuzhiyun  * This searches the common field names first, then
3410*4882a593Smuzhiyun  * the non-common ones if a common one was not found.
3411*4882a593Smuzhiyun  */
3412*4882a593Smuzhiyun struct tep_format_field *
tep_find_any_field(struct tep_event * event,const char * name)3413*4882a593Smuzhiyun tep_find_any_field(struct tep_event *event, const char *name)
3414*4882a593Smuzhiyun {
3415*4882a593Smuzhiyun 	struct tep_format_field *format;
3416*4882a593Smuzhiyun 
3417*4882a593Smuzhiyun 	format = tep_find_common_field(event, name);
3418*4882a593Smuzhiyun 	if (format)
3419*4882a593Smuzhiyun 		return format;
3420*4882a593Smuzhiyun 	return tep_find_field(event, name);
3421*4882a593Smuzhiyun }
3422*4882a593Smuzhiyun 
3423*4882a593Smuzhiyun /**
3424*4882a593Smuzhiyun  * tep_read_number - read a number from data
3425*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
3426*4882a593Smuzhiyun  * @ptr: the raw data
3427*4882a593Smuzhiyun  * @size: the size of the data that holds the number
3428*4882a593Smuzhiyun  *
3429*4882a593Smuzhiyun  * Returns the number (converted to host) from the
3430*4882a593Smuzhiyun  * raw data.
3431*4882a593Smuzhiyun  */
tep_read_number(struct tep_handle * tep,const void * ptr,int size)3432*4882a593Smuzhiyun unsigned long long tep_read_number(struct tep_handle *tep,
3433*4882a593Smuzhiyun 				   const void *ptr, int size)
3434*4882a593Smuzhiyun {
3435*4882a593Smuzhiyun 	unsigned long long val;
3436*4882a593Smuzhiyun 
3437*4882a593Smuzhiyun 	switch (size) {
3438*4882a593Smuzhiyun 	case 1:
3439*4882a593Smuzhiyun 		return *(unsigned char *)ptr;
3440*4882a593Smuzhiyun 	case 2:
3441*4882a593Smuzhiyun 		return data2host2(tep, *(unsigned short *)ptr);
3442*4882a593Smuzhiyun 	case 4:
3443*4882a593Smuzhiyun 		return data2host4(tep, *(unsigned int *)ptr);
3444*4882a593Smuzhiyun 	case 8:
3445*4882a593Smuzhiyun 		memcpy(&val, (ptr), sizeof(unsigned long long));
3446*4882a593Smuzhiyun 		return data2host8(tep, val);
3447*4882a593Smuzhiyun 	default:
3448*4882a593Smuzhiyun 		/* BUG! */
3449*4882a593Smuzhiyun 		return 0;
3450*4882a593Smuzhiyun 	}
3451*4882a593Smuzhiyun }
3452*4882a593Smuzhiyun 
3453*4882a593Smuzhiyun /**
3454*4882a593Smuzhiyun  * tep_read_number_field - read a number from data
3455*4882a593Smuzhiyun  * @field: a handle to the field
3456*4882a593Smuzhiyun  * @data: the raw data to read
3457*4882a593Smuzhiyun  * @value: the value to place the number in
3458*4882a593Smuzhiyun  *
3459*4882a593Smuzhiyun  * Reads raw data according to a field offset and size,
3460*4882a593Smuzhiyun  * and translates it into @value.
3461*4882a593Smuzhiyun  *
3462*4882a593Smuzhiyun  * Returns 0 on success, -1 otherwise.
3463*4882a593Smuzhiyun  */
tep_read_number_field(struct tep_format_field * field,const void * data,unsigned long long * value)3464*4882a593Smuzhiyun int tep_read_number_field(struct tep_format_field *field, const void *data,
3465*4882a593Smuzhiyun 			  unsigned long long *value)
3466*4882a593Smuzhiyun {
3467*4882a593Smuzhiyun 	if (!field)
3468*4882a593Smuzhiyun 		return -1;
3469*4882a593Smuzhiyun 	switch (field->size) {
3470*4882a593Smuzhiyun 	case 1:
3471*4882a593Smuzhiyun 	case 2:
3472*4882a593Smuzhiyun 	case 4:
3473*4882a593Smuzhiyun 	case 8:
3474*4882a593Smuzhiyun 		*value = tep_read_number(field->event->tep,
3475*4882a593Smuzhiyun 					 data + field->offset, field->size);
3476*4882a593Smuzhiyun 		return 0;
3477*4882a593Smuzhiyun 	default:
3478*4882a593Smuzhiyun 		return -1;
3479*4882a593Smuzhiyun 	}
3480*4882a593Smuzhiyun }
3481*4882a593Smuzhiyun 
get_common_info(struct tep_handle * tep,const char * type,int * offset,int * size)3482*4882a593Smuzhiyun static int get_common_info(struct tep_handle *tep,
3483*4882a593Smuzhiyun 			   const char *type, int *offset, int *size)
3484*4882a593Smuzhiyun {
3485*4882a593Smuzhiyun 	struct tep_event *event;
3486*4882a593Smuzhiyun 	struct tep_format_field *field;
3487*4882a593Smuzhiyun 
3488*4882a593Smuzhiyun 	/*
3489*4882a593Smuzhiyun 	 * All events should have the same common elements.
3490*4882a593Smuzhiyun 	 * Pick any event to find where the type is;
3491*4882a593Smuzhiyun 	 */
3492*4882a593Smuzhiyun 	if (!tep->events) {
3493*4882a593Smuzhiyun 		do_warning("no event_list!");
3494*4882a593Smuzhiyun 		return -1;
3495*4882a593Smuzhiyun 	}
3496*4882a593Smuzhiyun 
3497*4882a593Smuzhiyun 	event = tep->events[0];
3498*4882a593Smuzhiyun 	field = tep_find_common_field(event, type);
3499*4882a593Smuzhiyun 	if (!field)
3500*4882a593Smuzhiyun 		return -1;
3501*4882a593Smuzhiyun 
3502*4882a593Smuzhiyun 	*offset = field->offset;
3503*4882a593Smuzhiyun 	*size = field->size;
3504*4882a593Smuzhiyun 
3505*4882a593Smuzhiyun 	return 0;
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun 
__parse_common(struct tep_handle * tep,void * data,int * size,int * offset,const char * name)3508*4882a593Smuzhiyun static int __parse_common(struct tep_handle *tep, void *data,
3509*4882a593Smuzhiyun 			  int *size, int *offset, const char *name)
3510*4882a593Smuzhiyun {
3511*4882a593Smuzhiyun 	int ret;
3512*4882a593Smuzhiyun 
3513*4882a593Smuzhiyun 	if (!*size) {
3514*4882a593Smuzhiyun 		ret = get_common_info(tep, name, offset, size);
3515*4882a593Smuzhiyun 		if (ret < 0)
3516*4882a593Smuzhiyun 			return ret;
3517*4882a593Smuzhiyun 	}
3518*4882a593Smuzhiyun 	return tep_read_number(tep, data + *offset, *size);
3519*4882a593Smuzhiyun }
3520*4882a593Smuzhiyun 
trace_parse_common_type(struct tep_handle * tep,void * data)3521*4882a593Smuzhiyun static int trace_parse_common_type(struct tep_handle *tep, void *data)
3522*4882a593Smuzhiyun {
3523*4882a593Smuzhiyun 	return __parse_common(tep, data,
3524*4882a593Smuzhiyun 			      &tep->type_size, &tep->type_offset,
3525*4882a593Smuzhiyun 			      "common_type");
3526*4882a593Smuzhiyun }
3527*4882a593Smuzhiyun 
parse_common_pid(struct tep_handle * tep,void * data)3528*4882a593Smuzhiyun static int parse_common_pid(struct tep_handle *tep, void *data)
3529*4882a593Smuzhiyun {
3530*4882a593Smuzhiyun 	return __parse_common(tep, data,
3531*4882a593Smuzhiyun 			      &tep->pid_size, &tep->pid_offset,
3532*4882a593Smuzhiyun 			      "common_pid");
3533*4882a593Smuzhiyun }
3534*4882a593Smuzhiyun 
parse_common_pc(struct tep_handle * tep,void * data)3535*4882a593Smuzhiyun static int parse_common_pc(struct tep_handle *tep, void *data)
3536*4882a593Smuzhiyun {
3537*4882a593Smuzhiyun 	return __parse_common(tep, data,
3538*4882a593Smuzhiyun 			      &tep->pc_size, &tep->pc_offset,
3539*4882a593Smuzhiyun 			      "common_preempt_count");
3540*4882a593Smuzhiyun }
3541*4882a593Smuzhiyun 
parse_common_flags(struct tep_handle * tep,void * data)3542*4882a593Smuzhiyun static int parse_common_flags(struct tep_handle *tep, void *data)
3543*4882a593Smuzhiyun {
3544*4882a593Smuzhiyun 	return __parse_common(tep, data,
3545*4882a593Smuzhiyun 			      &tep->flags_size, &tep->flags_offset,
3546*4882a593Smuzhiyun 			      "common_flags");
3547*4882a593Smuzhiyun }
3548*4882a593Smuzhiyun 
parse_common_lock_depth(struct tep_handle * tep,void * data)3549*4882a593Smuzhiyun static int parse_common_lock_depth(struct tep_handle *tep, void *data)
3550*4882a593Smuzhiyun {
3551*4882a593Smuzhiyun 	return __parse_common(tep, data,
3552*4882a593Smuzhiyun 			      &tep->ld_size, &tep->ld_offset,
3553*4882a593Smuzhiyun 			      "common_lock_depth");
3554*4882a593Smuzhiyun }
3555*4882a593Smuzhiyun 
parse_common_migrate_disable(struct tep_handle * tep,void * data)3556*4882a593Smuzhiyun static int parse_common_migrate_disable(struct tep_handle *tep, void *data)
3557*4882a593Smuzhiyun {
3558*4882a593Smuzhiyun 	return __parse_common(tep, data,
3559*4882a593Smuzhiyun 			      &tep->ld_size, &tep->ld_offset,
3560*4882a593Smuzhiyun 			      "common_migrate_disable");
3561*4882a593Smuzhiyun }
3562*4882a593Smuzhiyun 
3563*4882a593Smuzhiyun static int events_id_cmp(const void *a, const void *b);
3564*4882a593Smuzhiyun 
3565*4882a593Smuzhiyun /**
3566*4882a593Smuzhiyun  * tep_find_event - find an event by given id
3567*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
3568*4882a593Smuzhiyun  * @id: the id of the event
3569*4882a593Smuzhiyun  *
3570*4882a593Smuzhiyun  * Returns an event that has a given @id.
3571*4882a593Smuzhiyun  */
tep_find_event(struct tep_handle * tep,int id)3572*4882a593Smuzhiyun struct tep_event *tep_find_event(struct tep_handle *tep, int id)
3573*4882a593Smuzhiyun {
3574*4882a593Smuzhiyun 	struct tep_event **eventptr;
3575*4882a593Smuzhiyun 	struct tep_event key;
3576*4882a593Smuzhiyun 	struct tep_event *pkey = &key;
3577*4882a593Smuzhiyun 
3578*4882a593Smuzhiyun 	/* Check cache first */
3579*4882a593Smuzhiyun 	if (tep->last_event && tep->last_event->id == id)
3580*4882a593Smuzhiyun 		return tep->last_event;
3581*4882a593Smuzhiyun 
3582*4882a593Smuzhiyun 	key.id = id;
3583*4882a593Smuzhiyun 
3584*4882a593Smuzhiyun 	eventptr = bsearch(&pkey, tep->events, tep->nr_events,
3585*4882a593Smuzhiyun 			   sizeof(*tep->events), events_id_cmp);
3586*4882a593Smuzhiyun 
3587*4882a593Smuzhiyun 	if (eventptr) {
3588*4882a593Smuzhiyun 		tep->last_event = *eventptr;
3589*4882a593Smuzhiyun 		return *eventptr;
3590*4882a593Smuzhiyun 	}
3591*4882a593Smuzhiyun 
3592*4882a593Smuzhiyun 	return NULL;
3593*4882a593Smuzhiyun }
3594*4882a593Smuzhiyun 
3595*4882a593Smuzhiyun /**
3596*4882a593Smuzhiyun  * tep_find_event_by_name - find an event by given name
3597*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
3598*4882a593Smuzhiyun  * @sys: the system name to search for
3599*4882a593Smuzhiyun  * @name: the name of the event to search for
3600*4882a593Smuzhiyun  *
3601*4882a593Smuzhiyun  * This returns an event with a given @name and under the system
3602*4882a593Smuzhiyun  * @sys. If @sys is NULL the first event with @name is returned.
3603*4882a593Smuzhiyun  */
3604*4882a593Smuzhiyun struct tep_event *
tep_find_event_by_name(struct tep_handle * tep,const char * sys,const char * name)3605*4882a593Smuzhiyun tep_find_event_by_name(struct tep_handle *tep,
3606*4882a593Smuzhiyun 		       const char *sys, const char *name)
3607*4882a593Smuzhiyun {
3608*4882a593Smuzhiyun 	struct tep_event *event = NULL;
3609*4882a593Smuzhiyun 	int i;
3610*4882a593Smuzhiyun 
3611*4882a593Smuzhiyun 	if (tep->last_event &&
3612*4882a593Smuzhiyun 	    strcmp(tep->last_event->name, name) == 0 &&
3613*4882a593Smuzhiyun 	    (!sys || strcmp(tep->last_event->system, sys) == 0))
3614*4882a593Smuzhiyun 		return tep->last_event;
3615*4882a593Smuzhiyun 
3616*4882a593Smuzhiyun 	for (i = 0; i < tep->nr_events; i++) {
3617*4882a593Smuzhiyun 		event = tep->events[i];
3618*4882a593Smuzhiyun 		if (strcmp(event->name, name) == 0) {
3619*4882a593Smuzhiyun 			if (!sys)
3620*4882a593Smuzhiyun 				break;
3621*4882a593Smuzhiyun 			if (strcmp(event->system, sys) == 0)
3622*4882a593Smuzhiyun 				break;
3623*4882a593Smuzhiyun 		}
3624*4882a593Smuzhiyun 	}
3625*4882a593Smuzhiyun 	if (i == tep->nr_events)
3626*4882a593Smuzhiyun 		event = NULL;
3627*4882a593Smuzhiyun 
3628*4882a593Smuzhiyun 	tep->last_event = event;
3629*4882a593Smuzhiyun 	return event;
3630*4882a593Smuzhiyun }
3631*4882a593Smuzhiyun 
3632*4882a593Smuzhiyun static unsigned long long
eval_num_arg(void * data,int size,struct tep_event * event,struct tep_print_arg * arg)3633*4882a593Smuzhiyun eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg)
3634*4882a593Smuzhiyun {
3635*4882a593Smuzhiyun 	struct tep_handle *tep = event->tep;
3636*4882a593Smuzhiyun 	unsigned long long val = 0;
3637*4882a593Smuzhiyun 	unsigned long long left, right;
3638*4882a593Smuzhiyun 	struct tep_print_arg *typearg = NULL;
3639*4882a593Smuzhiyun 	struct tep_print_arg *larg;
3640*4882a593Smuzhiyun 	unsigned long offset;
3641*4882a593Smuzhiyun 	unsigned int field_size;
3642*4882a593Smuzhiyun 
3643*4882a593Smuzhiyun 	switch (arg->type) {
3644*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
3645*4882a593Smuzhiyun 		/* ?? */
3646*4882a593Smuzhiyun 		return 0;
3647*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
3648*4882a593Smuzhiyun 		return strtoull(arg->atom.atom, NULL, 0);
3649*4882a593Smuzhiyun 	case TEP_PRINT_FIELD:
3650*4882a593Smuzhiyun 		if (!arg->field.field) {
3651*4882a593Smuzhiyun 			arg->field.field = tep_find_any_field(event, arg->field.name);
3652*4882a593Smuzhiyun 			if (!arg->field.field)
3653*4882a593Smuzhiyun 				goto out_warning_field;
3654*4882a593Smuzhiyun 
3655*4882a593Smuzhiyun 		}
3656*4882a593Smuzhiyun 		/* must be a number */
3657*4882a593Smuzhiyun 		val = tep_read_number(tep, data + arg->field.field->offset,
3658*4882a593Smuzhiyun 				      arg->field.field->size);
3659*4882a593Smuzhiyun 		break;
3660*4882a593Smuzhiyun 	case TEP_PRINT_FLAGS:
3661*4882a593Smuzhiyun 	case TEP_PRINT_SYMBOL:
3662*4882a593Smuzhiyun 	case TEP_PRINT_INT_ARRAY:
3663*4882a593Smuzhiyun 	case TEP_PRINT_HEX:
3664*4882a593Smuzhiyun 	case TEP_PRINT_HEX_STR:
3665*4882a593Smuzhiyun 		break;
3666*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
3667*4882a593Smuzhiyun 		val = eval_num_arg(data, size, event, arg->typecast.item);
3668*4882a593Smuzhiyun 		return eval_type(val, arg, 0);
3669*4882a593Smuzhiyun 	case TEP_PRINT_STRING:
3670*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
3671*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK:
3672*4882a593Smuzhiyun 		return 0;
3673*4882a593Smuzhiyun 	case TEP_PRINT_FUNC: {
3674*4882a593Smuzhiyun 		struct trace_seq s;
3675*4882a593Smuzhiyun 		trace_seq_init(&s);
3676*4882a593Smuzhiyun 		val = process_defined_func(&s, data, size, event, arg);
3677*4882a593Smuzhiyun 		trace_seq_destroy(&s);
3678*4882a593Smuzhiyun 		return val;
3679*4882a593Smuzhiyun 	}
3680*4882a593Smuzhiyun 	case TEP_PRINT_OP:
3681*4882a593Smuzhiyun 		if (strcmp(arg->op.op, "[") == 0) {
3682*4882a593Smuzhiyun 			/*
3683*4882a593Smuzhiyun 			 * Arrays are special, since we don't want
3684*4882a593Smuzhiyun 			 * to read the arg as is.
3685*4882a593Smuzhiyun 			 */
3686*4882a593Smuzhiyun 			right = eval_num_arg(data, size, event, arg->op.right);
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun 			/* handle typecasts */
3689*4882a593Smuzhiyun 			larg = arg->op.left;
3690*4882a593Smuzhiyun 			while (larg->type == TEP_PRINT_TYPE) {
3691*4882a593Smuzhiyun 				if (!typearg)
3692*4882a593Smuzhiyun 					typearg = larg;
3693*4882a593Smuzhiyun 				larg = larg->typecast.item;
3694*4882a593Smuzhiyun 			}
3695*4882a593Smuzhiyun 
3696*4882a593Smuzhiyun 			/* Default to long size */
3697*4882a593Smuzhiyun 			field_size = tep->long_size;
3698*4882a593Smuzhiyun 
3699*4882a593Smuzhiyun 			switch (larg->type) {
3700*4882a593Smuzhiyun 			case TEP_PRINT_DYNAMIC_ARRAY:
3701*4882a593Smuzhiyun 				offset = tep_read_number(tep,
3702*4882a593Smuzhiyun 						   data + larg->dynarray.field->offset,
3703*4882a593Smuzhiyun 						   larg->dynarray.field->size);
3704*4882a593Smuzhiyun 				if (larg->dynarray.field->elementsize)
3705*4882a593Smuzhiyun 					field_size = larg->dynarray.field->elementsize;
3706*4882a593Smuzhiyun 				/*
3707*4882a593Smuzhiyun 				 * The actual length of the dynamic array is stored
3708*4882a593Smuzhiyun 				 * in the top half of the field, and the offset
3709*4882a593Smuzhiyun 				 * is in the bottom half of the 32 bit field.
3710*4882a593Smuzhiyun 				 */
3711*4882a593Smuzhiyun 				offset &= 0xffff;
3712*4882a593Smuzhiyun 				offset += right;
3713*4882a593Smuzhiyun 				break;
3714*4882a593Smuzhiyun 			case TEP_PRINT_FIELD:
3715*4882a593Smuzhiyun 				if (!larg->field.field) {
3716*4882a593Smuzhiyun 					larg->field.field =
3717*4882a593Smuzhiyun 						tep_find_any_field(event, larg->field.name);
3718*4882a593Smuzhiyun 					if (!larg->field.field) {
3719*4882a593Smuzhiyun 						arg = larg;
3720*4882a593Smuzhiyun 						goto out_warning_field;
3721*4882a593Smuzhiyun 					}
3722*4882a593Smuzhiyun 				}
3723*4882a593Smuzhiyun 				field_size = larg->field.field->elementsize;
3724*4882a593Smuzhiyun 				offset = larg->field.field->offset +
3725*4882a593Smuzhiyun 					right * larg->field.field->elementsize;
3726*4882a593Smuzhiyun 				break;
3727*4882a593Smuzhiyun 			default:
3728*4882a593Smuzhiyun 				goto default_op; /* oops, all bets off */
3729*4882a593Smuzhiyun 			}
3730*4882a593Smuzhiyun 			val = tep_read_number(tep,
3731*4882a593Smuzhiyun 					      data + offset, field_size);
3732*4882a593Smuzhiyun 			if (typearg)
3733*4882a593Smuzhiyun 				val = eval_type(val, typearg, 1);
3734*4882a593Smuzhiyun 			break;
3735*4882a593Smuzhiyun 		} else if (strcmp(arg->op.op, "?") == 0) {
3736*4882a593Smuzhiyun 			left = eval_num_arg(data, size, event, arg->op.left);
3737*4882a593Smuzhiyun 			arg = arg->op.right;
3738*4882a593Smuzhiyun 			if (left)
3739*4882a593Smuzhiyun 				val = eval_num_arg(data, size, event, arg->op.left);
3740*4882a593Smuzhiyun 			else
3741*4882a593Smuzhiyun 				val = eval_num_arg(data, size, event, arg->op.right);
3742*4882a593Smuzhiyun 			break;
3743*4882a593Smuzhiyun 		}
3744*4882a593Smuzhiyun  default_op:
3745*4882a593Smuzhiyun 		left = eval_num_arg(data, size, event, arg->op.left);
3746*4882a593Smuzhiyun 		right = eval_num_arg(data, size, event, arg->op.right);
3747*4882a593Smuzhiyun 		switch (arg->op.op[0]) {
3748*4882a593Smuzhiyun 		case '!':
3749*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
3750*4882a593Smuzhiyun 			case 0:
3751*4882a593Smuzhiyun 				val = !right;
3752*4882a593Smuzhiyun 				break;
3753*4882a593Smuzhiyun 			case '=':
3754*4882a593Smuzhiyun 				val = left != right;
3755*4882a593Smuzhiyun 				break;
3756*4882a593Smuzhiyun 			default:
3757*4882a593Smuzhiyun 				goto out_warning_op;
3758*4882a593Smuzhiyun 			}
3759*4882a593Smuzhiyun 			break;
3760*4882a593Smuzhiyun 		case '~':
3761*4882a593Smuzhiyun 			val = ~right;
3762*4882a593Smuzhiyun 			break;
3763*4882a593Smuzhiyun 		case '|':
3764*4882a593Smuzhiyun 			if (arg->op.op[1])
3765*4882a593Smuzhiyun 				val = left || right;
3766*4882a593Smuzhiyun 			else
3767*4882a593Smuzhiyun 				val = left | right;
3768*4882a593Smuzhiyun 			break;
3769*4882a593Smuzhiyun 		case '&':
3770*4882a593Smuzhiyun 			if (arg->op.op[1])
3771*4882a593Smuzhiyun 				val = left && right;
3772*4882a593Smuzhiyun 			else
3773*4882a593Smuzhiyun 				val = left & right;
3774*4882a593Smuzhiyun 			break;
3775*4882a593Smuzhiyun 		case '<':
3776*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
3777*4882a593Smuzhiyun 			case 0:
3778*4882a593Smuzhiyun 				val = left < right;
3779*4882a593Smuzhiyun 				break;
3780*4882a593Smuzhiyun 			case '<':
3781*4882a593Smuzhiyun 				val = left << right;
3782*4882a593Smuzhiyun 				break;
3783*4882a593Smuzhiyun 			case '=':
3784*4882a593Smuzhiyun 				val = left <= right;
3785*4882a593Smuzhiyun 				break;
3786*4882a593Smuzhiyun 			default:
3787*4882a593Smuzhiyun 				goto out_warning_op;
3788*4882a593Smuzhiyun 			}
3789*4882a593Smuzhiyun 			break;
3790*4882a593Smuzhiyun 		case '>':
3791*4882a593Smuzhiyun 			switch (arg->op.op[1]) {
3792*4882a593Smuzhiyun 			case 0:
3793*4882a593Smuzhiyun 				val = left > right;
3794*4882a593Smuzhiyun 				break;
3795*4882a593Smuzhiyun 			case '>':
3796*4882a593Smuzhiyun 				val = left >> right;
3797*4882a593Smuzhiyun 				break;
3798*4882a593Smuzhiyun 			case '=':
3799*4882a593Smuzhiyun 				val = left >= right;
3800*4882a593Smuzhiyun 				break;
3801*4882a593Smuzhiyun 			default:
3802*4882a593Smuzhiyun 				goto out_warning_op;
3803*4882a593Smuzhiyun 			}
3804*4882a593Smuzhiyun 			break;
3805*4882a593Smuzhiyun 		case '=':
3806*4882a593Smuzhiyun 			if (arg->op.op[1] != '=')
3807*4882a593Smuzhiyun 				goto out_warning_op;
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun 			val = left == right;
3810*4882a593Smuzhiyun 			break;
3811*4882a593Smuzhiyun 		case '-':
3812*4882a593Smuzhiyun 			val = left - right;
3813*4882a593Smuzhiyun 			break;
3814*4882a593Smuzhiyun 		case '+':
3815*4882a593Smuzhiyun 			val = left + right;
3816*4882a593Smuzhiyun 			break;
3817*4882a593Smuzhiyun 		case '/':
3818*4882a593Smuzhiyun 			val = left / right;
3819*4882a593Smuzhiyun 			break;
3820*4882a593Smuzhiyun 		case '%':
3821*4882a593Smuzhiyun 			val = left % right;
3822*4882a593Smuzhiyun 			break;
3823*4882a593Smuzhiyun 		case '*':
3824*4882a593Smuzhiyun 			val = left * right;
3825*4882a593Smuzhiyun 			break;
3826*4882a593Smuzhiyun 		default:
3827*4882a593Smuzhiyun 			goto out_warning_op;
3828*4882a593Smuzhiyun 		}
3829*4882a593Smuzhiyun 		break;
3830*4882a593Smuzhiyun 	case TEP_PRINT_DYNAMIC_ARRAY_LEN:
3831*4882a593Smuzhiyun 		offset = tep_read_number(tep,
3832*4882a593Smuzhiyun 					 data + arg->dynarray.field->offset,
3833*4882a593Smuzhiyun 					 arg->dynarray.field->size);
3834*4882a593Smuzhiyun 		/*
3835*4882a593Smuzhiyun 		 * The total allocated length of the dynamic array is
3836*4882a593Smuzhiyun 		 * stored in the top half of the field, and the offset
3837*4882a593Smuzhiyun 		 * is in the bottom half of the 32 bit field.
3838*4882a593Smuzhiyun 		 */
3839*4882a593Smuzhiyun 		val = (unsigned long long)(offset >> 16);
3840*4882a593Smuzhiyun 		break;
3841*4882a593Smuzhiyun 	case TEP_PRINT_DYNAMIC_ARRAY:
3842*4882a593Smuzhiyun 		/* Without [], we pass the address to the dynamic data */
3843*4882a593Smuzhiyun 		offset = tep_read_number(tep,
3844*4882a593Smuzhiyun 					 data + arg->dynarray.field->offset,
3845*4882a593Smuzhiyun 					 arg->dynarray.field->size);
3846*4882a593Smuzhiyun 		/*
3847*4882a593Smuzhiyun 		 * The total allocated length of the dynamic array is
3848*4882a593Smuzhiyun 		 * stored in the top half of the field, and the offset
3849*4882a593Smuzhiyun 		 * is in the bottom half of the 32 bit field.
3850*4882a593Smuzhiyun 		 */
3851*4882a593Smuzhiyun 		offset &= 0xffff;
3852*4882a593Smuzhiyun 		val = (unsigned long long)((unsigned long)data + offset);
3853*4882a593Smuzhiyun 		break;
3854*4882a593Smuzhiyun 	default: /* not sure what to do there */
3855*4882a593Smuzhiyun 		return 0;
3856*4882a593Smuzhiyun 	}
3857*4882a593Smuzhiyun 	return val;
3858*4882a593Smuzhiyun 
3859*4882a593Smuzhiyun out_warning_op:
3860*4882a593Smuzhiyun 	do_warning_event(event, "%s: unknown op '%s'", __func__, arg->op.op);
3861*4882a593Smuzhiyun 	return 0;
3862*4882a593Smuzhiyun 
3863*4882a593Smuzhiyun out_warning_field:
3864*4882a593Smuzhiyun 	do_warning_event(event, "%s: field %s not found",
3865*4882a593Smuzhiyun 			 __func__, arg->field.name);
3866*4882a593Smuzhiyun 	return 0;
3867*4882a593Smuzhiyun }
3868*4882a593Smuzhiyun 
3869*4882a593Smuzhiyun struct flag {
3870*4882a593Smuzhiyun 	const char *name;
3871*4882a593Smuzhiyun 	unsigned long long value;
3872*4882a593Smuzhiyun };
3873*4882a593Smuzhiyun 
3874*4882a593Smuzhiyun static const struct flag flags[] = {
3875*4882a593Smuzhiyun 	{ "HI_SOFTIRQ", 0 },
3876*4882a593Smuzhiyun 	{ "TIMER_SOFTIRQ", 1 },
3877*4882a593Smuzhiyun 	{ "NET_TX_SOFTIRQ", 2 },
3878*4882a593Smuzhiyun 	{ "NET_RX_SOFTIRQ", 3 },
3879*4882a593Smuzhiyun 	{ "BLOCK_SOFTIRQ", 4 },
3880*4882a593Smuzhiyun 	{ "IRQ_POLL_SOFTIRQ", 5 },
3881*4882a593Smuzhiyun 	{ "TASKLET_SOFTIRQ", 6 },
3882*4882a593Smuzhiyun 	{ "SCHED_SOFTIRQ", 7 },
3883*4882a593Smuzhiyun 	{ "HRTIMER_SOFTIRQ", 8 },
3884*4882a593Smuzhiyun 	{ "RCU_SOFTIRQ", 9 },
3885*4882a593Smuzhiyun 
3886*4882a593Smuzhiyun 	{ "HRTIMER_NORESTART", 0 },
3887*4882a593Smuzhiyun 	{ "HRTIMER_RESTART", 1 },
3888*4882a593Smuzhiyun };
3889*4882a593Smuzhiyun 
eval_flag(const char * flag)3890*4882a593Smuzhiyun static long long eval_flag(const char *flag)
3891*4882a593Smuzhiyun {
3892*4882a593Smuzhiyun 	int i;
3893*4882a593Smuzhiyun 
3894*4882a593Smuzhiyun 	/*
3895*4882a593Smuzhiyun 	 * Some flags in the format files do not get converted.
3896*4882a593Smuzhiyun 	 * If the flag is not numeric, see if it is something that
3897*4882a593Smuzhiyun 	 * we already know about.
3898*4882a593Smuzhiyun 	 */
3899*4882a593Smuzhiyun 	if (isdigit(flag[0]))
3900*4882a593Smuzhiyun 		return strtoull(flag, NULL, 0);
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun 	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
3903*4882a593Smuzhiyun 		if (strcmp(flags[i].name, flag) == 0)
3904*4882a593Smuzhiyun 			return flags[i].value;
3905*4882a593Smuzhiyun 
3906*4882a593Smuzhiyun 	return -1LL;
3907*4882a593Smuzhiyun }
3908*4882a593Smuzhiyun 
print_str_to_seq(struct trace_seq * s,const char * format,int len_arg,const char * str)3909*4882a593Smuzhiyun static void print_str_to_seq(struct trace_seq *s, const char *format,
3910*4882a593Smuzhiyun 			     int len_arg, const char *str)
3911*4882a593Smuzhiyun {
3912*4882a593Smuzhiyun 	if (len_arg >= 0)
3913*4882a593Smuzhiyun 		trace_seq_printf(s, format, len_arg, str);
3914*4882a593Smuzhiyun 	else
3915*4882a593Smuzhiyun 		trace_seq_printf(s, format, str);
3916*4882a593Smuzhiyun }
3917*4882a593Smuzhiyun 
print_bitmask_to_seq(struct tep_handle * tep,struct trace_seq * s,const char * format,int len_arg,const void * data,int size)3918*4882a593Smuzhiyun static void print_bitmask_to_seq(struct tep_handle *tep,
3919*4882a593Smuzhiyun 				 struct trace_seq *s, const char *format,
3920*4882a593Smuzhiyun 				 int len_arg, const void *data, int size)
3921*4882a593Smuzhiyun {
3922*4882a593Smuzhiyun 	int nr_bits = size * 8;
3923*4882a593Smuzhiyun 	int str_size = (nr_bits + 3) / 4;
3924*4882a593Smuzhiyun 	int len = 0;
3925*4882a593Smuzhiyun 	char buf[3];
3926*4882a593Smuzhiyun 	char *str;
3927*4882a593Smuzhiyun 	int index;
3928*4882a593Smuzhiyun 	int i;
3929*4882a593Smuzhiyun 
3930*4882a593Smuzhiyun 	/*
3931*4882a593Smuzhiyun 	 * The kernel likes to put in commas every 32 bits, we
3932*4882a593Smuzhiyun 	 * can do the same.
3933*4882a593Smuzhiyun 	 */
3934*4882a593Smuzhiyun 	str_size += (nr_bits - 1) / 32;
3935*4882a593Smuzhiyun 
3936*4882a593Smuzhiyun 	str = malloc(str_size + 1);
3937*4882a593Smuzhiyun 	if (!str) {
3938*4882a593Smuzhiyun 		do_warning("%s: not enough memory!", __func__);
3939*4882a593Smuzhiyun 		return;
3940*4882a593Smuzhiyun 	}
3941*4882a593Smuzhiyun 	str[str_size] = 0;
3942*4882a593Smuzhiyun 
3943*4882a593Smuzhiyun 	/* Start out with -2 for the two chars per byte */
3944*4882a593Smuzhiyun 	for (i = str_size - 2; i >= 0; i -= 2) {
3945*4882a593Smuzhiyun 		/*
3946*4882a593Smuzhiyun 		 * data points to a bit mask of size bytes.
3947*4882a593Smuzhiyun 		 * In the kernel, this is an array of long words, thus
3948*4882a593Smuzhiyun 		 * endianness is very important.
3949*4882a593Smuzhiyun 		 */
3950*4882a593Smuzhiyun 		if (tep->file_bigendian)
3951*4882a593Smuzhiyun 			index = size - (len + 1);
3952*4882a593Smuzhiyun 		else
3953*4882a593Smuzhiyun 			index = len;
3954*4882a593Smuzhiyun 
3955*4882a593Smuzhiyun 		snprintf(buf, 3, "%02x", *((unsigned char *)data + index));
3956*4882a593Smuzhiyun 		memcpy(str + i, buf, 2);
3957*4882a593Smuzhiyun 		len++;
3958*4882a593Smuzhiyun 		if (!(len & 3) && i > 0) {
3959*4882a593Smuzhiyun 			i--;
3960*4882a593Smuzhiyun 			str[i] = ',';
3961*4882a593Smuzhiyun 		}
3962*4882a593Smuzhiyun 	}
3963*4882a593Smuzhiyun 
3964*4882a593Smuzhiyun 	if (len_arg >= 0)
3965*4882a593Smuzhiyun 		trace_seq_printf(s, format, len_arg, str);
3966*4882a593Smuzhiyun 	else
3967*4882a593Smuzhiyun 		trace_seq_printf(s, format, str);
3968*4882a593Smuzhiyun 
3969*4882a593Smuzhiyun 	free(str);
3970*4882a593Smuzhiyun }
3971*4882a593Smuzhiyun 
print_str_arg(struct trace_seq * s,void * data,int size,struct tep_event * event,const char * format,int len_arg,struct tep_print_arg * arg)3972*4882a593Smuzhiyun static void print_str_arg(struct trace_seq *s, void *data, int size,
3973*4882a593Smuzhiyun 			  struct tep_event *event, const char *format,
3974*4882a593Smuzhiyun 			  int len_arg, struct tep_print_arg *arg)
3975*4882a593Smuzhiyun {
3976*4882a593Smuzhiyun 	struct tep_handle *tep = event->tep;
3977*4882a593Smuzhiyun 	struct tep_print_flag_sym *flag;
3978*4882a593Smuzhiyun 	struct tep_format_field *field;
3979*4882a593Smuzhiyun 	struct printk_map *printk;
3980*4882a593Smuzhiyun 	long long val, fval;
3981*4882a593Smuzhiyun 	unsigned long long addr;
3982*4882a593Smuzhiyun 	char *str;
3983*4882a593Smuzhiyun 	unsigned char *hex;
3984*4882a593Smuzhiyun 	int print;
3985*4882a593Smuzhiyun 	int i, len;
3986*4882a593Smuzhiyun 
3987*4882a593Smuzhiyun 	switch (arg->type) {
3988*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
3989*4882a593Smuzhiyun 		/* ?? */
3990*4882a593Smuzhiyun 		return;
3991*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
3992*4882a593Smuzhiyun 		print_str_to_seq(s, format, len_arg, arg->atom.atom);
3993*4882a593Smuzhiyun 		return;
3994*4882a593Smuzhiyun 	case TEP_PRINT_FIELD:
3995*4882a593Smuzhiyun 		field = arg->field.field;
3996*4882a593Smuzhiyun 		if (!field) {
3997*4882a593Smuzhiyun 			field = tep_find_any_field(event, arg->field.name);
3998*4882a593Smuzhiyun 			if (!field) {
3999*4882a593Smuzhiyun 				str = arg->field.name;
4000*4882a593Smuzhiyun 				goto out_warning_field;
4001*4882a593Smuzhiyun 			}
4002*4882a593Smuzhiyun 			arg->field.field = field;
4003*4882a593Smuzhiyun 		}
4004*4882a593Smuzhiyun 		/* Zero sized fields, mean the rest of the data */
4005*4882a593Smuzhiyun 		len = field->size ? : size - field->offset;
4006*4882a593Smuzhiyun 
4007*4882a593Smuzhiyun 		/*
4008*4882a593Smuzhiyun 		 * Some events pass in pointers. If this is not an array
4009*4882a593Smuzhiyun 		 * and the size is the same as long_size, assume that it
4010*4882a593Smuzhiyun 		 * is a pointer.
4011*4882a593Smuzhiyun 		 */
4012*4882a593Smuzhiyun 		if (!(field->flags & TEP_FIELD_IS_ARRAY) &&
4013*4882a593Smuzhiyun 		    field->size == tep->long_size) {
4014*4882a593Smuzhiyun 
4015*4882a593Smuzhiyun 			/* Handle heterogeneous recording and processing
4016*4882a593Smuzhiyun 			 * architectures
4017*4882a593Smuzhiyun 			 *
4018*4882a593Smuzhiyun 			 * CASE I:
4019*4882a593Smuzhiyun 			 * Traces recorded on 32-bit devices (32-bit
4020*4882a593Smuzhiyun 			 * addressing) and processed on 64-bit devices:
4021*4882a593Smuzhiyun 			 * In this case, only 32 bits should be read.
4022*4882a593Smuzhiyun 			 *
4023*4882a593Smuzhiyun 			 * CASE II:
4024*4882a593Smuzhiyun 			 * Traces recorded on 64 bit devices and processed
4025*4882a593Smuzhiyun 			 * on 32-bit devices:
4026*4882a593Smuzhiyun 			 * In this case, 64 bits must be read.
4027*4882a593Smuzhiyun 			 */
4028*4882a593Smuzhiyun 			addr = (tep->long_size == 8) ?
4029*4882a593Smuzhiyun 				*(unsigned long long *)(data + field->offset) :
4030*4882a593Smuzhiyun 				(unsigned long long)*(unsigned int *)(data + field->offset);
4031*4882a593Smuzhiyun 
4032*4882a593Smuzhiyun 			/* Check if it matches a print format */
4033*4882a593Smuzhiyun 			printk = find_printk(tep, addr);
4034*4882a593Smuzhiyun 			if (printk)
4035*4882a593Smuzhiyun 				trace_seq_puts(s, printk->printk);
4036*4882a593Smuzhiyun 			else
4037*4882a593Smuzhiyun 				trace_seq_printf(s, "%llx", addr);
4038*4882a593Smuzhiyun 			break;
4039*4882a593Smuzhiyun 		}
4040*4882a593Smuzhiyun 		str = malloc(len + 1);
4041*4882a593Smuzhiyun 		if (!str) {
4042*4882a593Smuzhiyun 			do_warning_event(event, "%s: not enough memory!",
4043*4882a593Smuzhiyun 					 __func__);
4044*4882a593Smuzhiyun 			return;
4045*4882a593Smuzhiyun 		}
4046*4882a593Smuzhiyun 		memcpy(str, data + field->offset, len);
4047*4882a593Smuzhiyun 		str[len] = 0;
4048*4882a593Smuzhiyun 		print_str_to_seq(s, format, len_arg, str);
4049*4882a593Smuzhiyun 		free(str);
4050*4882a593Smuzhiyun 		break;
4051*4882a593Smuzhiyun 	case TEP_PRINT_FLAGS:
4052*4882a593Smuzhiyun 		val = eval_num_arg(data, size, event, arg->flags.field);
4053*4882a593Smuzhiyun 		print = 0;
4054*4882a593Smuzhiyun 		for (flag = arg->flags.flags; flag; flag = flag->next) {
4055*4882a593Smuzhiyun 			fval = eval_flag(flag->value);
4056*4882a593Smuzhiyun 			if (!val && fval < 0) {
4057*4882a593Smuzhiyun 				print_str_to_seq(s, format, len_arg, flag->str);
4058*4882a593Smuzhiyun 				break;
4059*4882a593Smuzhiyun 			}
4060*4882a593Smuzhiyun 			if (fval > 0 && (val & fval) == fval) {
4061*4882a593Smuzhiyun 				if (print && arg->flags.delim)
4062*4882a593Smuzhiyun 					trace_seq_puts(s, arg->flags.delim);
4063*4882a593Smuzhiyun 				print_str_to_seq(s, format, len_arg, flag->str);
4064*4882a593Smuzhiyun 				print = 1;
4065*4882a593Smuzhiyun 				val &= ~fval;
4066*4882a593Smuzhiyun 			}
4067*4882a593Smuzhiyun 		}
4068*4882a593Smuzhiyun 		if (val) {
4069*4882a593Smuzhiyun 			if (print && arg->flags.delim)
4070*4882a593Smuzhiyun 				trace_seq_puts(s, arg->flags.delim);
4071*4882a593Smuzhiyun 			trace_seq_printf(s, "0x%llx", val);
4072*4882a593Smuzhiyun 		}
4073*4882a593Smuzhiyun 		break;
4074*4882a593Smuzhiyun 	case TEP_PRINT_SYMBOL:
4075*4882a593Smuzhiyun 		val = eval_num_arg(data, size, event, arg->symbol.field);
4076*4882a593Smuzhiyun 		for (flag = arg->symbol.symbols; flag; flag = flag->next) {
4077*4882a593Smuzhiyun 			fval = eval_flag(flag->value);
4078*4882a593Smuzhiyun 			if (val == fval) {
4079*4882a593Smuzhiyun 				print_str_to_seq(s, format, len_arg, flag->str);
4080*4882a593Smuzhiyun 				break;
4081*4882a593Smuzhiyun 			}
4082*4882a593Smuzhiyun 		}
4083*4882a593Smuzhiyun 		if (!flag)
4084*4882a593Smuzhiyun 			trace_seq_printf(s, "0x%llx", val);
4085*4882a593Smuzhiyun 		break;
4086*4882a593Smuzhiyun 	case TEP_PRINT_HEX:
4087*4882a593Smuzhiyun 	case TEP_PRINT_HEX_STR:
4088*4882a593Smuzhiyun 		if (arg->hex.field->type == TEP_PRINT_DYNAMIC_ARRAY) {
4089*4882a593Smuzhiyun 			unsigned long offset;
4090*4882a593Smuzhiyun 			offset = tep_read_number(tep,
4091*4882a593Smuzhiyun 				data + arg->hex.field->dynarray.field->offset,
4092*4882a593Smuzhiyun 				arg->hex.field->dynarray.field->size);
4093*4882a593Smuzhiyun 			hex = data + (offset & 0xffff);
4094*4882a593Smuzhiyun 		} else {
4095*4882a593Smuzhiyun 			field = arg->hex.field->field.field;
4096*4882a593Smuzhiyun 			if (!field) {
4097*4882a593Smuzhiyun 				str = arg->hex.field->field.name;
4098*4882a593Smuzhiyun 				field = tep_find_any_field(event, str);
4099*4882a593Smuzhiyun 				if (!field)
4100*4882a593Smuzhiyun 					goto out_warning_field;
4101*4882a593Smuzhiyun 				arg->hex.field->field.field = field;
4102*4882a593Smuzhiyun 			}
4103*4882a593Smuzhiyun 			hex = data + field->offset;
4104*4882a593Smuzhiyun 		}
4105*4882a593Smuzhiyun 		len = eval_num_arg(data, size, event, arg->hex.size);
4106*4882a593Smuzhiyun 		for (i = 0; i < len; i++) {
4107*4882a593Smuzhiyun 			if (i && arg->type == TEP_PRINT_HEX)
4108*4882a593Smuzhiyun 				trace_seq_putc(s, ' ');
4109*4882a593Smuzhiyun 			trace_seq_printf(s, "%02x", hex[i]);
4110*4882a593Smuzhiyun 		}
4111*4882a593Smuzhiyun 		break;
4112*4882a593Smuzhiyun 
4113*4882a593Smuzhiyun 	case TEP_PRINT_INT_ARRAY: {
4114*4882a593Smuzhiyun 		void *num;
4115*4882a593Smuzhiyun 		int el_size;
4116*4882a593Smuzhiyun 
4117*4882a593Smuzhiyun 		if (arg->int_array.field->type == TEP_PRINT_DYNAMIC_ARRAY) {
4118*4882a593Smuzhiyun 			unsigned long offset;
4119*4882a593Smuzhiyun 			struct tep_format_field *field =
4120*4882a593Smuzhiyun 				arg->int_array.field->dynarray.field;
4121*4882a593Smuzhiyun 			offset = tep_read_number(tep,
4122*4882a593Smuzhiyun 						 data + field->offset,
4123*4882a593Smuzhiyun 						 field->size);
4124*4882a593Smuzhiyun 			num = data + (offset & 0xffff);
4125*4882a593Smuzhiyun 		} else {
4126*4882a593Smuzhiyun 			field = arg->int_array.field->field.field;
4127*4882a593Smuzhiyun 			if (!field) {
4128*4882a593Smuzhiyun 				str = arg->int_array.field->field.name;
4129*4882a593Smuzhiyun 				field = tep_find_any_field(event, str);
4130*4882a593Smuzhiyun 				if (!field)
4131*4882a593Smuzhiyun 					goto out_warning_field;
4132*4882a593Smuzhiyun 				arg->int_array.field->field.field = field;
4133*4882a593Smuzhiyun 			}
4134*4882a593Smuzhiyun 			num = data + field->offset;
4135*4882a593Smuzhiyun 		}
4136*4882a593Smuzhiyun 		len = eval_num_arg(data, size, event, arg->int_array.count);
4137*4882a593Smuzhiyun 		el_size = eval_num_arg(data, size, event,
4138*4882a593Smuzhiyun 				       arg->int_array.el_size);
4139*4882a593Smuzhiyun 		for (i = 0; i < len; i++) {
4140*4882a593Smuzhiyun 			if (i)
4141*4882a593Smuzhiyun 				trace_seq_putc(s, ' ');
4142*4882a593Smuzhiyun 
4143*4882a593Smuzhiyun 			if (el_size == 1) {
4144*4882a593Smuzhiyun 				trace_seq_printf(s, "%u", *(uint8_t *)num);
4145*4882a593Smuzhiyun 			} else if (el_size == 2) {
4146*4882a593Smuzhiyun 				trace_seq_printf(s, "%u", *(uint16_t *)num);
4147*4882a593Smuzhiyun 			} else if (el_size == 4) {
4148*4882a593Smuzhiyun 				trace_seq_printf(s, "%u", *(uint32_t *)num);
4149*4882a593Smuzhiyun 			} else if (el_size == 8) {
4150*4882a593Smuzhiyun 				trace_seq_printf(s, "%"PRIu64, *(uint64_t *)num);
4151*4882a593Smuzhiyun 			} else {
4152*4882a593Smuzhiyun 				trace_seq_printf(s, "BAD SIZE:%d 0x%x",
4153*4882a593Smuzhiyun 						 el_size, *(uint8_t *)num);
4154*4882a593Smuzhiyun 				el_size = 1;
4155*4882a593Smuzhiyun 			}
4156*4882a593Smuzhiyun 
4157*4882a593Smuzhiyun 			num += el_size;
4158*4882a593Smuzhiyun 		}
4159*4882a593Smuzhiyun 		break;
4160*4882a593Smuzhiyun 	}
4161*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
4162*4882a593Smuzhiyun 		break;
4163*4882a593Smuzhiyun 	case TEP_PRINT_STRING: {
4164*4882a593Smuzhiyun 		int str_offset;
4165*4882a593Smuzhiyun 
4166*4882a593Smuzhiyun 		if (arg->string.offset == -1) {
4167*4882a593Smuzhiyun 			struct tep_format_field *f;
4168*4882a593Smuzhiyun 
4169*4882a593Smuzhiyun 			f = tep_find_any_field(event, arg->string.string);
4170*4882a593Smuzhiyun 			arg->string.offset = f->offset;
4171*4882a593Smuzhiyun 		}
4172*4882a593Smuzhiyun 		str_offset = data2host4(tep, *(unsigned int *)(data + arg->string.offset));
4173*4882a593Smuzhiyun 		str_offset &= 0xffff;
4174*4882a593Smuzhiyun 		print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
4175*4882a593Smuzhiyun 		break;
4176*4882a593Smuzhiyun 	}
4177*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
4178*4882a593Smuzhiyun 		print_str_to_seq(s, format, len_arg, arg->string.string);
4179*4882a593Smuzhiyun 		break;
4180*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK: {
4181*4882a593Smuzhiyun 		int bitmask_offset;
4182*4882a593Smuzhiyun 		int bitmask_size;
4183*4882a593Smuzhiyun 
4184*4882a593Smuzhiyun 		if (arg->bitmask.offset == -1) {
4185*4882a593Smuzhiyun 			struct tep_format_field *f;
4186*4882a593Smuzhiyun 
4187*4882a593Smuzhiyun 			f = tep_find_any_field(event, arg->bitmask.bitmask);
4188*4882a593Smuzhiyun 			arg->bitmask.offset = f->offset;
4189*4882a593Smuzhiyun 		}
4190*4882a593Smuzhiyun 		bitmask_offset = data2host4(tep, *(unsigned int *)(data + arg->bitmask.offset));
4191*4882a593Smuzhiyun 		bitmask_size = bitmask_offset >> 16;
4192*4882a593Smuzhiyun 		bitmask_offset &= 0xffff;
4193*4882a593Smuzhiyun 		print_bitmask_to_seq(tep, s, format, len_arg,
4194*4882a593Smuzhiyun 				     data + bitmask_offset, bitmask_size);
4195*4882a593Smuzhiyun 		break;
4196*4882a593Smuzhiyun 	}
4197*4882a593Smuzhiyun 	case TEP_PRINT_OP:
4198*4882a593Smuzhiyun 		/*
4199*4882a593Smuzhiyun 		 * The only op for string should be ? :
4200*4882a593Smuzhiyun 		 */
4201*4882a593Smuzhiyun 		if (arg->op.op[0] != '?')
4202*4882a593Smuzhiyun 			return;
4203*4882a593Smuzhiyun 		val = eval_num_arg(data, size, event, arg->op.left);
4204*4882a593Smuzhiyun 		if (val)
4205*4882a593Smuzhiyun 			print_str_arg(s, data, size, event,
4206*4882a593Smuzhiyun 				      format, len_arg, arg->op.right->op.left);
4207*4882a593Smuzhiyun 		else
4208*4882a593Smuzhiyun 			print_str_arg(s, data, size, event,
4209*4882a593Smuzhiyun 				      format, len_arg, arg->op.right->op.right);
4210*4882a593Smuzhiyun 		break;
4211*4882a593Smuzhiyun 	case TEP_PRINT_FUNC:
4212*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4213*4882a593Smuzhiyun 		break;
4214*4882a593Smuzhiyun 	default:
4215*4882a593Smuzhiyun 		/* well... */
4216*4882a593Smuzhiyun 		break;
4217*4882a593Smuzhiyun 	}
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun 	return;
4220*4882a593Smuzhiyun 
4221*4882a593Smuzhiyun out_warning_field:
4222*4882a593Smuzhiyun 	do_warning_event(event, "%s: field %s not found",
4223*4882a593Smuzhiyun 			 __func__, arg->field.name);
4224*4882a593Smuzhiyun }
4225*4882a593Smuzhiyun 
4226*4882a593Smuzhiyun static unsigned long long
process_defined_func(struct trace_seq * s,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4227*4882a593Smuzhiyun process_defined_func(struct trace_seq *s, void *data, int size,
4228*4882a593Smuzhiyun 		     struct tep_event *event, struct tep_print_arg *arg)
4229*4882a593Smuzhiyun {
4230*4882a593Smuzhiyun 	struct tep_function_handler *func_handle = arg->func.func;
4231*4882a593Smuzhiyun 	struct func_params *param;
4232*4882a593Smuzhiyun 	unsigned long long *args;
4233*4882a593Smuzhiyun 	unsigned long long ret;
4234*4882a593Smuzhiyun 	struct tep_print_arg *farg;
4235*4882a593Smuzhiyun 	struct trace_seq str;
4236*4882a593Smuzhiyun 	struct save_str {
4237*4882a593Smuzhiyun 		struct save_str *next;
4238*4882a593Smuzhiyun 		char *str;
4239*4882a593Smuzhiyun 	} *strings = NULL, *string;
4240*4882a593Smuzhiyun 	int i;
4241*4882a593Smuzhiyun 
4242*4882a593Smuzhiyun 	if (!func_handle->nr_args) {
4243*4882a593Smuzhiyun 		ret = (*func_handle->func)(s, NULL);
4244*4882a593Smuzhiyun 		goto out;
4245*4882a593Smuzhiyun 	}
4246*4882a593Smuzhiyun 
4247*4882a593Smuzhiyun 	farg = arg->func.args;
4248*4882a593Smuzhiyun 	param = func_handle->params;
4249*4882a593Smuzhiyun 
4250*4882a593Smuzhiyun 	ret = ULLONG_MAX;
4251*4882a593Smuzhiyun 	args = malloc(sizeof(*args) * func_handle->nr_args);
4252*4882a593Smuzhiyun 	if (!args)
4253*4882a593Smuzhiyun 		goto out;
4254*4882a593Smuzhiyun 
4255*4882a593Smuzhiyun 	for (i = 0; i < func_handle->nr_args; i++) {
4256*4882a593Smuzhiyun 		switch (param->type) {
4257*4882a593Smuzhiyun 		case TEP_FUNC_ARG_INT:
4258*4882a593Smuzhiyun 		case TEP_FUNC_ARG_LONG:
4259*4882a593Smuzhiyun 		case TEP_FUNC_ARG_PTR:
4260*4882a593Smuzhiyun 			args[i] = eval_num_arg(data, size, event, farg);
4261*4882a593Smuzhiyun 			break;
4262*4882a593Smuzhiyun 		case TEP_FUNC_ARG_STRING:
4263*4882a593Smuzhiyun 			trace_seq_init(&str);
4264*4882a593Smuzhiyun 			print_str_arg(&str, data, size, event, "%s", -1, farg);
4265*4882a593Smuzhiyun 			trace_seq_terminate(&str);
4266*4882a593Smuzhiyun 			string = malloc(sizeof(*string));
4267*4882a593Smuzhiyun 			if (!string) {
4268*4882a593Smuzhiyun 				do_warning_event(event, "%s(%d): malloc str",
4269*4882a593Smuzhiyun 						 __func__, __LINE__);
4270*4882a593Smuzhiyun 				goto out_free;
4271*4882a593Smuzhiyun 			}
4272*4882a593Smuzhiyun 			string->next = strings;
4273*4882a593Smuzhiyun 			string->str = strdup(str.buffer);
4274*4882a593Smuzhiyun 			if (!string->str) {
4275*4882a593Smuzhiyun 				free(string);
4276*4882a593Smuzhiyun 				do_warning_event(event, "%s(%d): malloc str",
4277*4882a593Smuzhiyun 						 __func__, __LINE__);
4278*4882a593Smuzhiyun 				goto out_free;
4279*4882a593Smuzhiyun 			}
4280*4882a593Smuzhiyun 			args[i] = (uintptr_t)string->str;
4281*4882a593Smuzhiyun 			strings = string;
4282*4882a593Smuzhiyun 			trace_seq_destroy(&str);
4283*4882a593Smuzhiyun 			break;
4284*4882a593Smuzhiyun 		default:
4285*4882a593Smuzhiyun 			/*
4286*4882a593Smuzhiyun 			 * Something went totally wrong, this is not
4287*4882a593Smuzhiyun 			 * an input error, something in this code broke.
4288*4882a593Smuzhiyun 			 */
4289*4882a593Smuzhiyun 			do_warning_event(event, "Unexpected end of arguments\n");
4290*4882a593Smuzhiyun 			goto out_free;
4291*4882a593Smuzhiyun 		}
4292*4882a593Smuzhiyun 		farg = farg->next;
4293*4882a593Smuzhiyun 		param = param->next;
4294*4882a593Smuzhiyun 	}
4295*4882a593Smuzhiyun 
4296*4882a593Smuzhiyun 	ret = (*func_handle->func)(s, args);
4297*4882a593Smuzhiyun out_free:
4298*4882a593Smuzhiyun 	free(args);
4299*4882a593Smuzhiyun 	while (strings) {
4300*4882a593Smuzhiyun 		string = strings;
4301*4882a593Smuzhiyun 		strings = string->next;
4302*4882a593Smuzhiyun 		free(string->str);
4303*4882a593Smuzhiyun 		free(string);
4304*4882a593Smuzhiyun 	}
4305*4882a593Smuzhiyun 
4306*4882a593Smuzhiyun  out:
4307*4882a593Smuzhiyun 	/* TBD : handle return type here */
4308*4882a593Smuzhiyun 	return ret;
4309*4882a593Smuzhiyun }
4310*4882a593Smuzhiyun 
free_args(struct tep_print_arg * args)4311*4882a593Smuzhiyun static void free_args(struct tep_print_arg *args)
4312*4882a593Smuzhiyun {
4313*4882a593Smuzhiyun 	struct tep_print_arg *next;
4314*4882a593Smuzhiyun 
4315*4882a593Smuzhiyun 	while (args) {
4316*4882a593Smuzhiyun 		next = args->next;
4317*4882a593Smuzhiyun 
4318*4882a593Smuzhiyun 		free_arg(args);
4319*4882a593Smuzhiyun 		args = next;
4320*4882a593Smuzhiyun 	}
4321*4882a593Smuzhiyun }
4322*4882a593Smuzhiyun 
make_bprint_args(char * fmt,void * data,int size,struct tep_event * event)4323*4882a593Smuzhiyun static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, struct tep_event *event)
4324*4882a593Smuzhiyun {
4325*4882a593Smuzhiyun 	struct tep_handle *tep = event->tep;
4326*4882a593Smuzhiyun 	struct tep_format_field *field, *ip_field;
4327*4882a593Smuzhiyun 	struct tep_print_arg *args, *arg, **next;
4328*4882a593Smuzhiyun 	unsigned long long ip, val;
4329*4882a593Smuzhiyun 	char *ptr;
4330*4882a593Smuzhiyun 	void *bptr;
4331*4882a593Smuzhiyun 	int vsize = 0;
4332*4882a593Smuzhiyun 
4333*4882a593Smuzhiyun 	field = tep->bprint_buf_field;
4334*4882a593Smuzhiyun 	ip_field = tep->bprint_ip_field;
4335*4882a593Smuzhiyun 
4336*4882a593Smuzhiyun 	if (!field) {
4337*4882a593Smuzhiyun 		field = tep_find_field(event, "buf");
4338*4882a593Smuzhiyun 		if (!field) {
4339*4882a593Smuzhiyun 			do_warning_event(event, "can't find buffer field for binary printk");
4340*4882a593Smuzhiyun 			return NULL;
4341*4882a593Smuzhiyun 		}
4342*4882a593Smuzhiyun 		ip_field = tep_find_field(event, "ip");
4343*4882a593Smuzhiyun 		if (!ip_field) {
4344*4882a593Smuzhiyun 			do_warning_event(event, "can't find ip field for binary printk");
4345*4882a593Smuzhiyun 			return NULL;
4346*4882a593Smuzhiyun 		}
4347*4882a593Smuzhiyun 		tep->bprint_buf_field = field;
4348*4882a593Smuzhiyun 		tep->bprint_ip_field = ip_field;
4349*4882a593Smuzhiyun 	}
4350*4882a593Smuzhiyun 
4351*4882a593Smuzhiyun 	ip = tep_read_number(tep, data + ip_field->offset, ip_field->size);
4352*4882a593Smuzhiyun 
4353*4882a593Smuzhiyun 	/*
4354*4882a593Smuzhiyun 	 * The first arg is the IP pointer.
4355*4882a593Smuzhiyun 	 */
4356*4882a593Smuzhiyun 	args = alloc_arg();
4357*4882a593Smuzhiyun 	if (!args) {
4358*4882a593Smuzhiyun 		do_warning_event(event, "%s(%d): not enough memory!",
4359*4882a593Smuzhiyun 				 __func__, __LINE__);
4360*4882a593Smuzhiyun 		return NULL;
4361*4882a593Smuzhiyun 	}
4362*4882a593Smuzhiyun 	arg = args;
4363*4882a593Smuzhiyun 	arg->next = NULL;
4364*4882a593Smuzhiyun 	next = &arg->next;
4365*4882a593Smuzhiyun 
4366*4882a593Smuzhiyun 	arg->type = TEP_PRINT_ATOM;
4367*4882a593Smuzhiyun 
4368*4882a593Smuzhiyun 	if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
4369*4882a593Smuzhiyun 		goto out_free;
4370*4882a593Smuzhiyun 
4371*4882a593Smuzhiyun 	/* skip the first "%ps: " */
4372*4882a593Smuzhiyun 	for (ptr = fmt + 5, bptr = data + field->offset;
4373*4882a593Smuzhiyun 	     bptr < data + size && *ptr; ptr++) {
4374*4882a593Smuzhiyun 		int ls = 0;
4375*4882a593Smuzhiyun 
4376*4882a593Smuzhiyun 		if (*ptr == '%') {
4377*4882a593Smuzhiyun  process_again:
4378*4882a593Smuzhiyun 			ptr++;
4379*4882a593Smuzhiyun 			switch (*ptr) {
4380*4882a593Smuzhiyun 			case '%':
4381*4882a593Smuzhiyun 				break;
4382*4882a593Smuzhiyun 			case 'l':
4383*4882a593Smuzhiyun 				ls++;
4384*4882a593Smuzhiyun 				goto process_again;
4385*4882a593Smuzhiyun 			case 'L':
4386*4882a593Smuzhiyun 				ls = 2;
4387*4882a593Smuzhiyun 				goto process_again;
4388*4882a593Smuzhiyun 			case '0' ... '9':
4389*4882a593Smuzhiyun 				goto process_again;
4390*4882a593Smuzhiyun 			case '.':
4391*4882a593Smuzhiyun 				goto process_again;
4392*4882a593Smuzhiyun 			case 'z':
4393*4882a593Smuzhiyun 			case 'Z':
4394*4882a593Smuzhiyun 				ls = 1;
4395*4882a593Smuzhiyun 				goto process_again;
4396*4882a593Smuzhiyun 			case 'p':
4397*4882a593Smuzhiyun 				ls = 1;
4398*4882a593Smuzhiyun 				if (isalnum(ptr[1])) {
4399*4882a593Smuzhiyun 					ptr++;
4400*4882a593Smuzhiyun 					/* Check for special pointers */
4401*4882a593Smuzhiyun 					switch (*ptr) {
4402*4882a593Smuzhiyun 					case 's':
4403*4882a593Smuzhiyun 					case 'S':
4404*4882a593Smuzhiyun 					case 'x':
4405*4882a593Smuzhiyun 						break;
4406*4882a593Smuzhiyun 					case 'f':
4407*4882a593Smuzhiyun 					case 'F':
4408*4882a593Smuzhiyun 						/*
4409*4882a593Smuzhiyun 						 * Pre-5.5 kernels use %pf and
4410*4882a593Smuzhiyun 						 * %pF for printing symbols
4411*4882a593Smuzhiyun 						 * while kernels since 5.5 use
4412*4882a593Smuzhiyun 						 * %pfw for fwnodes. So check
4413*4882a593Smuzhiyun 						 * %p[fF] isn't followed by 'w'.
4414*4882a593Smuzhiyun 						 */
4415*4882a593Smuzhiyun 						if (ptr[1] != 'w')
4416*4882a593Smuzhiyun 							break;
4417*4882a593Smuzhiyun 						/* fall through */
4418*4882a593Smuzhiyun 					default:
4419*4882a593Smuzhiyun 						/*
4420*4882a593Smuzhiyun 						 * Older kernels do not process
4421*4882a593Smuzhiyun 						 * dereferenced pointers.
4422*4882a593Smuzhiyun 						 * Only process if the pointer
4423*4882a593Smuzhiyun 						 * value is a printable.
4424*4882a593Smuzhiyun 						 */
4425*4882a593Smuzhiyun 						if (isprint(*(char *)bptr))
4426*4882a593Smuzhiyun 							goto process_string;
4427*4882a593Smuzhiyun 					}
4428*4882a593Smuzhiyun 				}
4429*4882a593Smuzhiyun 				/* fall through */
4430*4882a593Smuzhiyun 			case 'd':
4431*4882a593Smuzhiyun 			case 'u':
4432*4882a593Smuzhiyun 			case 'i':
4433*4882a593Smuzhiyun 			case 'x':
4434*4882a593Smuzhiyun 			case 'X':
4435*4882a593Smuzhiyun 			case 'o':
4436*4882a593Smuzhiyun 				switch (ls) {
4437*4882a593Smuzhiyun 				case 0:
4438*4882a593Smuzhiyun 					vsize = 4;
4439*4882a593Smuzhiyun 					break;
4440*4882a593Smuzhiyun 				case 1:
4441*4882a593Smuzhiyun 					vsize = tep->long_size;
4442*4882a593Smuzhiyun 					break;
4443*4882a593Smuzhiyun 				case 2:
4444*4882a593Smuzhiyun 					vsize = 8;
4445*4882a593Smuzhiyun 					break;
4446*4882a593Smuzhiyun 				default:
4447*4882a593Smuzhiyun 					vsize = ls; /* ? */
4448*4882a593Smuzhiyun 					break;
4449*4882a593Smuzhiyun 				}
4450*4882a593Smuzhiyun 			/* fall through */
4451*4882a593Smuzhiyun 			case '*':
4452*4882a593Smuzhiyun 				if (*ptr == '*')
4453*4882a593Smuzhiyun 					vsize = 4;
4454*4882a593Smuzhiyun 
4455*4882a593Smuzhiyun 				/* the pointers are always 4 bytes aligned */
4456*4882a593Smuzhiyun 				bptr = (void *)(((unsigned long)bptr + 3) &
4457*4882a593Smuzhiyun 						~3);
4458*4882a593Smuzhiyun 				val = tep_read_number(tep, bptr, vsize);
4459*4882a593Smuzhiyun 				bptr += vsize;
4460*4882a593Smuzhiyun 				arg = alloc_arg();
4461*4882a593Smuzhiyun 				if (!arg) {
4462*4882a593Smuzhiyun 					do_warning_event(event, "%s(%d): not enough memory!",
4463*4882a593Smuzhiyun 						   __func__, __LINE__);
4464*4882a593Smuzhiyun 					goto out_free;
4465*4882a593Smuzhiyun 				}
4466*4882a593Smuzhiyun 				arg->next = NULL;
4467*4882a593Smuzhiyun 				arg->type = TEP_PRINT_ATOM;
4468*4882a593Smuzhiyun 				if (asprintf(&arg->atom.atom, "%lld", val) < 0) {
4469*4882a593Smuzhiyun 					free(arg);
4470*4882a593Smuzhiyun 					goto out_free;
4471*4882a593Smuzhiyun 				}
4472*4882a593Smuzhiyun 				*next = arg;
4473*4882a593Smuzhiyun 				next = &arg->next;
4474*4882a593Smuzhiyun 				/*
4475*4882a593Smuzhiyun 				 * The '*' case means that an arg is used as the length.
4476*4882a593Smuzhiyun 				 * We need to continue to figure out for what.
4477*4882a593Smuzhiyun 				 */
4478*4882a593Smuzhiyun 				if (*ptr == '*')
4479*4882a593Smuzhiyun 					goto process_again;
4480*4882a593Smuzhiyun 
4481*4882a593Smuzhiyun 				break;
4482*4882a593Smuzhiyun 			case 's':
4483*4882a593Smuzhiyun  process_string:
4484*4882a593Smuzhiyun 				arg = alloc_arg();
4485*4882a593Smuzhiyun 				if (!arg) {
4486*4882a593Smuzhiyun 					do_warning_event(event, "%s(%d): not enough memory!",
4487*4882a593Smuzhiyun 						   __func__, __LINE__);
4488*4882a593Smuzhiyun 					goto out_free;
4489*4882a593Smuzhiyun 				}
4490*4882a593Smuzhiyun 				arg->next = NULL;
4491*4882a593Smuzhiyun 				arg->type = TEP_PRINT_BSTRING;
4492*4882a593Smuzhiyun 				arg->string.string = strdup(bptr);
4493*4882a593Smuzhiyun 				if (!arg->string.string)
4494*4882a593Smuzhiyun 					goto out_free;
4495*4882a593Smuzhiyun 				bptr += strlen(bptr) + 1;
4496*4882a593Smuzhiyun 				*next = arg;
4497*4882a593Smuzhiyun 				next = &arg->next;
4498*4882a593Smuzhiyun 			default:
4499*4882a593Smuzhiyun 				break;
4500*4882a593Smuzhiyun 			}
4501*4882a593Smuzhiyun 		}
4502*4882a593Smuzhiyun 	}
4503*4882a593Smuzhiyun 
4504*4882a593Smuzhiyun 	return args;
4505*4882a593Smuzhiyun 
4506*4882a593Smuzhiyun out_free:
4507*4882a593Smuzhiyun 	free_args(args);
4508*4882a593Smuzhiyun 	return NULL;
4509*4882a593Smuzhiyun }
4510*4882a593Smuzhiyun 
4511*4882a593Smuzhiyun static char *
get_bprint_format(void * data,int size __maybe_unused,struct tep_event * event)4512*4882a593Smuzhiyun get_bprint_format(void *data, int size __maybe_unused,
4513*4882a593Smuzhiyun 		  struct tep_event *event)
4514*4882a593Smuzhiyun {
4515*4882a593Smuzhiyun 	struct tep_handle *tep = event->tep;
4516*4882a593Smuzhiyun 	unsigned long long addr;
4517*4882a593Smuzhiyun 	struct tep_format_field *field;
4518*4882a593Smuzhiyun 	struct printk_map *printk;
4519*4882a593Smuzhiyun 	char *format;
4520*4882a593Smuzhiyun 
4521*4882a593Smuzhiyun 	field = tep->bprint_fmt_field;
4522*4882a593Smuzhiyun 
4523*4882a593Smuzhiyun 	if (!field) {
4524*4882a593Smuzhiyun 		field = tep_find_field(event, "fmt");
4525*4882a593Smuzhiyun 		if (!field) {
4526*4882a593Smuzhiyun 			do_warning_event(event, "can't find format field for binary printk");
4527*4882a593Smuzhiyun 			return NULL;
4528*4882a593Smuzhiyun 		}
4529*4882a593Smuzhiyun 		tep->bprint_fmt_field = field;
4530*4882a593Smuzhiyun 	}
4531*4882a593Smuzhiyun 
4532*4882a593Smuzhiyun 	addr = tep_read_number(tep, data + field->offset, field->size);
4533*4882a593Smuzhiyun 
4534*4882a593Smuzhiyun 	printk = find_printk(tep, addr);
4535*4882a593Smuzhiyun 	if (!printk) {
4536*4882a593Smuzhiyun 		if (asprintf(&format, "%%ps: (NO FORMAT FOUND at %llx)\n", addr) < 0)
4537*4882a593Smuzhiyun 			return NULL;
4538*4882a593Smuzhiyun 		return format;
4539*4882a593Smuzhiyun 	}
4540*4882a593Smuzhiyun 
4541*4882a593Smuzhiyun 	if (asprintf(&format, "%s: %s", "%ps", printk->printk) < 0)
4542*4882a593Smuzhiyun 		return NULL;
4543*4882a593Smuzhiyun 
4544*4882a593Smuzhiyun 	return format;
4545*4882a593Smuzhiyun }
4546*4882a593Smuzhiyun 
print_mac_arg(struct trace_seq * s,const char * format,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4547*4882a593Smuzhiyun static int print_mac_arg(struct trace_seq *s, const char *format,
4548*4882a593Smuzhiyun 			 void *data, int size, struct tep_event *event,
4549*4882a593Smuzhiyun 			 struct tep_print_arg *arg)
4550*4882a593Smuzhiyun {
4551*4882a593Smuzhiyun 	const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
4552*4882a593Smuzhiyun 	bool reverse = false;
4553*4882a593Smuzhiyun 	unsigned char *buf;
4554*4882a593Smuzhiyun 	int ret = 0;
4555*4882a593Smuzhiyun 
4556*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
4557*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4558*4882a593Smuzhiyun 		return 0;
4559*4882a593Smuzhiyun 	}
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_FIELD) {
4562*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
4563*4882a593Smuzhiyun 				 arg->type);
4564*4882a593Smuzhiyun 		return 0;
4565*4882a593Smuzhiyun 	}
4566*4882a593Smuzhiyun 
4567*4882a593Smuzhiyun 	if (format[0] == 'm') {
4568*4882a593Smuzhiyun 		fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
4569*4882a593Smuzhiyun 	} else if (format[0] == 'M' && format[1] == 'F') {
4570*4882a593Smuzhiyun 		fmt = "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x";
4571*4882a593Smuzhiyun 		ret++;
4572*4882a593Smuzhiyun 	}
4573*4882a593Smuzhiyun 	if (format[1] == 'R') {
4574*4882a593Smuzhiyun 		reverse = true;
4575*4882a593Smuzhiyun 		ret++;
4576*4882a593Smuzhiyun 	}
4577*4882a593Smuzhiyun 
4578*4882a593Smuzhiyun 	if (!arg->field.field) {
4579*4882a593Smuzhiyun 		arg->field.field =
4580*4882a593Smuzhiyun 			tep_find_any_field(event, arg->field.name);
4581*4882a593Smuzhiyun 		if (!arg->field.field) {
4582*4882a593Smuzhiyun 			do_warning_event(event, "%s: field %s not found",
4583*4882a593Smuzhiyun 					 __func__, arg->field.name);
4584*4882a593Smuzhiyun 			return ret;
4585*4882a593Smuzhiyun 		}
4586*4882a593Smuzhiyun 	}
4587*4882a593Smuzhiyun 	if (arg->field.field->size != 6) {
4588*4882a593Smuzhiyun 		trace_seq_printf(s, "INVALIDMAC");
4589*4882a593Smuzhiyun 		return ret;
4590*4882a593Smuzhiyun 	}
4591*4882a593Smuzhiyun 
4592*4882a593Smuzhiyun 	buf = data + arg->field.field->offset;
4593*4882a593Smuzhiyun 	if (reverse)
4594*4882a593Smuzhiyun 		trace_seq_printf(s, fmt, buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
4595*4882a593Smuzhiyun 	else
4596*4882a593Smuzhiyun 		trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
4597*4882a593Smuzhiyun 
4598*4882a593Smuzhiyun 	return ret;
4599*4882a593Smuzhiyun }
4600*4882a593Smuzhiyun 
parse_ip4_print_args(struct tep_handle * tep,const char * ptr,bool * reverse)4601*4882a593Smuzhiyun static int parse_ip4_print_args(struct tep_handle *tep,
4602*4882a593Smuzhiyun 				const char *ptr, bool *reverse)
4603*4882a593Smuzhiyun {
4604*4882a593Smuzhiyun 	int ret = 0;
4605*4882a593Smuzhiyun 
4606*4882a593Smuzhiyun 	*reverse = false;
4607*4882a593Smuzhiyun 
4608*4882a593Smuzhiyun 	/* hnbl */
4609*4882a593Smuzhiyun 	switch (*ptr) {
4610*4882a593Smuzhiyun 	case 'h':
4611*4882a593Smuzhiyun 		if (tep->file_bigendian)
4612*4882a593Smuzhiyun 			*reverse = false;
4613*4882a593Smuzhiyun 		else
4614*4882a593Smuzhiyun 			*reverse = true;
4615*4882a593Smuzhiyun 		ret++;
4616*4882a593Smuzhiyun 		break;
4617*4882a593Smuzhiyun 	case 'l':
4618*4882a593Smuzhiyun 		*reverse = true;
4619*4882a593Smuzhiyun 		ret++;
4620*4882a593Smuzhiyun 		break;
4621*4882a593Smuzhiyun 	case 'n':
4622*4882a593Smuzhiyun 	case 'b':
4623*4882a593Smuzhiyun 		ret++;
4624*4882a593Smuzhiyun 		/* fall through */
4625*4882a593Smuzhiyun 	default:
4626*4882a593Smuzhiyun 		*reverse = false;
4627*4882a593Smuzhiyun 		break;
4628*4882a593Smuzhiyun 	}
4629*4882a593Smuzhiyun 
4630*4882a593Smuzhiyun 	return ret;
4631*4882a593Smuzhiyun }
4632*4882a593Smuzhiyun 
print_ip4_addr(struct trace_seq * s,char i,bool reverse,unsigned char * buf)4633*4882a593Smuzhiyun static void print_ip4_addr(struct trace_seq *s, char i, bool reverse, unsigned char *buf)
4634*4882a593Smuzhiyun {
4635*4882a593Smuzhiyun 	const char *fmt;
4636*4882a593Smuzhiyun 
4637*4882a593Smuzhiyun 	if (i == 'i')
4638*4882a593Smuzhiyun 		fmt = "%03d.%03d.%03d.%03d";
4639*4882a593Smuzhiyun 	else
4640*4882a593Smuzhiyun 		fmt = "%d.%d.%d.%d";
4641*4882a593Smuzhiyun 
4642*4882a593Smuzhiyun 	if (reverse)
4643*4882a593Smuzhiyun 		trace_seq_printf(s, fmt, buf[3], buf[2], buf[1], buf[0]);
4644*4882a593Smuzhiyun 	else
4645*4882a593Smuzhiyun 		trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3]);
4646*4882a593Smuzhiyun 
4647*4882a593Smuzhiyun }
4648*4882a593Smuzhiyun 
ipv6_addr_v4mapped(const struct in6_addr * a)4649*4882a593Smuzhiyun static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
4650*4882a593Smuzhiyun {
4651*4882a593Smuzhiyun 	return ((unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) |
4652*4882a593Smuzhiyun 		(unsigned long)(a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL;
4653*4882a593Smuzhiyun }
4654*4882a593Smuzhiyun 
ipv6_addr_is_isatap(const struct in6_addr * addr)4655*4882a593Smuzhiyun static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr)
4656*4882a593Smuzhiyun {
4657*4882a593Smuzhiyun 	return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
4658*4882a593Smuzhiyun }
4659*4882a593Smuzhiyun 
print_ip6c_addr(struct trace_seq * s,unsigned char * addr)4660*4882a593Smuzhiyun static void print_ip6c_addr(struct trace_seq *s, unsigned char *addr)
4661*4882a593Smuzhiyun {
4662*4882a593Smuzhiyun 	int i, j, range;
4663*4882a593Smuzhiyun 	unsigned char zerolength[8];
4664*4882a593Smuzhiyun 	int longest = 1;
4665*4882a593Smuzhiyun 	int colonpos = -1;
4666*4882a593Smuzhiyun 	uint16_t word;
4667*4882a593Smuzhiyun 	uint8_t hi, lo;
4668*4882a593Smuzhiyun 	bool needcolon = false;
4669*4882a593Smuzhiyun 	bool useIPv4;
4670*4882a593Smuzhiyun 	struct in6_addr in6;
4671*4882a593Smuzhiyun 
4672*4882a593Smuzhiyun 	memcpy(&in6, addr, sizeof(struct in6_addr));
4673*4882a593Smuzhiyun 
4674*4882a593Smuzhiyun 	useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
4675*4882a593Smuzhiyun 
4676*4882a593Smuzhiyun 	memset(zerolength, 0, sizeof(zerolength));
4677*4882a593Smuzhiyun 
4678*4882a593Smuzhiyun 	if (useIPv4)
4679*4882a593Smuzhiyun 		range = 6;
4680*4882a593Smuzhiyun 	else
4681*4882a593Smuzhiyun 		range = 8;
4682*4882a593Smuzhiyun 
4683*4882a593Smuzhiyun 	/* find position of longest 0 run */
4684*4882a593Smuzhiyun 	for (i = 0; i < range; i++) {
4685*4882a593Smuzhiyun 		for (j = i; j < range; j++) {
4686*4882a593Smuzhiyun 			if (in6.s6_addr16[j] != 0)
4687*4882a593Smuzhiyun 				break;
4688*4882a593Smuzhiyun 			zerolength[i]++;
4689*4882a593Smuzhiyun 		}
4690*4882a593Smuzhiyun 	}
4691*4882a593Smuzhiyun 	for (i = 0; i < range; i++) {
4692*4882a593Smuzhiyun 		if (zerolength[i] > longest) {
4693*4882a593Smuzhiyun 			longest = zerolength[i];
4694*4882a593Smuzhiyun 			colonpos = i;
4695*4882a593Smuzhiyun 		}
4696*4882a593Smuzhiyun 	}
4697*4882a593Smuzhiyun 	if (longest == 1)		/* don't compress a single 0 */
4698*4882a593Smuzhiyun 		colonpos = -1;
4699*4882a593Smuzhiyun 
4700*4882a593Smuzhiyun 	/* emit address */
4701*4882a593Smuzhiyun 	for (i = 0; i < range; i++) {
4702*4882a593Smuzhiyun 		if (i == colonpos) {
4703*4882a593Smuzhiyun 			if (needcolon || i == 0)
4704*4882a593Smuzhiyun 				trace_seq_printf(s, ":");
4705*4882a593Smuzhiyun 			trace_seq_printf(s, ":");
4706*4882a593Smuzhiyun 			needcolon = false;
4707*4882a593Smuzhiyun 			i += longest - 1;
4708*4882a593Smuzhiyun 			continue;
4709*4882a593Smuzhiyun 		}
4710*4882a593Smuzhiyun 		if (needcolon) {
4711*4882a593Smuzhiyun 			trace_seq_printf(s, ":");
4712*4882a593Smuzhiyun 			needcolon = false;
4713*4882a593Smuzhiyun 		}
4714*4882a593Smuzhiyun 		/* hex u16 without leading 0s */
4715*4882a593Smuzhiyun 		word = ntohs(in6.s6_addr16[i]);
4716*4882a593Smuzhiyun 		hi = word >> 8;
4717*4882a593Smuzhiyun 		lo = word & 0xff;
4718*4882a593Smuzhiyun 		if (hi)
4719*4882a593Smuzhiyun 			trace_seq_printf(s, "%x%02x", hi, lo);
4720*4882a593Smuzhiyun 		else
4721*4882a593Smuzhiyun 			trace_seq_printf(s, "%x", lo);
4722*4882a593Smuzhiyun 
4723*4882a593Smuzhiyun 		needcolon = true;
4724*4882a593Smuzhiyun 	}
4725*4882a593Smuzhiyun 
4726*4882a593Smuzhiyun 	if (useIPv4) {
4727*4882a593Smuzhiyun 		if (needcolon)
4728*4882a593Smuzhiyun 			trace_seq_printf(s, ":");
4729*4882a593Smuzhiyun 		print_ip4_addr(s, 'I', false, &in6.s6_addr[12]);
4730*4882a593Smuzhiyun 	}
4731*4882a593Smuzhiyun 
4732*4882a593Smuzhiyun 	return;
4733*4882a593Smuzhiyun }
4734*4882a593Smuzhiyun 
print_ip6_addr(struct trace_seq * s,char i,unsigned char * buf)4735*4882a593Smuzhiyun static void print_ip6_addr(struct trace_seq *s, char i, unsigned char *buf)
4736*4882a593Smuzhiyun {
4737*4882a593Smuzhiyun 	int j;
4738*4882a593Smuzhiyun 
4739*4882a593Smuzhiyun 	for (j = 0; j < 16; j += 2) {
4740*4882a593Smuzhiyun 		trace_seq_printf(s, "%02x%02x", buf[j], buf[j+1]);
4741*4882a593Smuzhiyun 		if (i == 'I' && j < 14)
4742*4882a593Smuzhiyun 			trace_seq_printf(s, ":");
4743*4882a593Smuzhiyun 	}
4744*4882a593Smuzhiyun }
4745*4882a593Smuzhiyun 
4746*4882a593Smuzhiyun /*
4747*4882a593Smuzhiyun  * %pi4   print an IPv4 address with leading zeros
4748*4882a593Smuzhiyun  * %pI4   print an IPv4 address without leading zeros
4749*4882a593Smuzhiyun  * %pi6   print an IPv6 address without colons
4750*4882a593Smuzhiyun  * %pI6   print an IPv6 address with colons
4751*4882a593Smuzhiyun  * %pI6c  print an IPv6 address in compressed form with colons
4752*4882a593Smuzhiyun  * %pISpc print an IP address based on sockaddr; p adds port.
4753*4882a593Smuzhiyun  */
print_ipv4_arg(struct trace_seq * s,const char * ptr,char i,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4754*4882a593Smuzhiyun static int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i,
4755*4882a593Smuzhiyun 			  void *data, int size, struct tep_event *event,
4756*4882a593Smuzhiyun 			  struct tep_print_arg *arg)
4757*4882a593Smuzhiyun {
4758*4882a593Smuzhiyun 	bool reverse = false;
4759*4882a593Smuzhiyun 	unsigned char *buf;
4760*4882a593Smuzhiyun 	int ret;
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun 	ret = parse_ip4_print_args(event->tep, ptr, &reverse);
4763*4882a593Smuzhiyun 
4764*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
4765*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4766*4882a593Smuzhiyun 		return ret;
4767*4882a593Smuzhiyun 	}
4768*4882a593Smuzhiyun 
4769*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_FIELD) {
4770*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4771*4882a593Smuzhiyun 		return ret;
4772*4882a593Smuzhiyun 	}
4773*4882a593Smuzhiyun 
4774*4882a593Smuzhiyun 	if (!arg->field.field) {
4775*4882a593Smuzhiyun 		arg->field.field =
4776*4882a593Smuzhiyun 			tep_find_any_field(event, arg->field.name);
4777*4882a593Smuzhiyun 		if (!arg->field.field) {
4778*4882a593Smuzhiyun 			do_warning("%s: field %s not found",
4779*4882a593Smuzhiyun 				   __func__, arg->field.name);
4780*4882a593Smuzhiyun 			return ret;
4781*4882a593Smuzhiyun 		}
4782*4882a593Smuzhiyun 	}
4783*4882a593Smuzhiyun 
4784*4882a593Smuzhiyun 	buf = data + arg->field.field->offset;
4785*4882a593Smuzhiyun 
4786*4882a593Smuzhiyun 	if (arg->field.field->size != 4) {
4787*4882a593Smuzhiyun 		trace_seq_printf(s, "INVALIDIPv4");
4788*4882a593Smuzhiyun 		return ret;
4789*4882a593Smuzhiyun 	}
4790*4882a593Smuzhiyun 
4791*4882a593Smuzhiyun 	print_ip4_addr(s, i, reverse, buf);
4792*4882a593Smuzhiyun 	return ret;
4793*4882a593Smuzhiyun 
4794*4882a593Smuzhiyun }
4795*4882a593Smuzhiyun 
print_ipv6_arg(struct trace_seq * s,const char * ptr,char i,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4796*4882a593Smuzhiyun static int print_ipv6_arg(struct trace_seq *s, const char *ptr, char i,
4797*4882a593Smuzhiyun 			  void *data, int size, struct tep_event *event,
4798*4882a593Smuzhiyun 			  struct tep_print_arg *arg)
4799*4882a593Smuzhiyun {
4800*4882a593Smuzhiyun 	char have_c = 0;
4801*4882a593Smuzhiyun 	unsigned char *buf;
4802*4882a593Smuzhiyun 	int rc = 0;
4803*4882a593Smuzhiyun 
4804*4882a593Smuzhiyun 	/* pI6c */
4805*4882a593Smuzhiyun 	if (i == 'I' && *ptr == 'c') {
4806*4882a593Smuzhiyun 		have_c = 1;
4807*4882a593Smuzhiyun 		ptr++;
4808*4882a593Smuzhiyun 		rc++;
4809*4882a593Smuzhiyun 	}
4810*4882a593Smuzhiyun 
4811*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
4812*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4813*4882a593Smuzhiyun 		return rc;
4814*4882a593Smuzhiyun 	}
4815*4882a593Smuzhiyun 
4816*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_FIELD) {
4817*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4818*4882a593Smuzhiyun 		return rc;
4819*4882a593Smuzhiyun 	}
4820*4882a593Smuzhiyun 
4821*4882a593Smuzhiyun 	if (!arg->field.field) {
4822*4882a593Smuzhiyun 		arg->field.field =
4823*4882a593Smuzhiyun 			tep_find_any_field(event, arg->field.name);
4824*4882a593Smuzhiyun 		if (!arg->field.field) {
4825*4882a593Smuzhiyun 			do_warning("%s: field %s not found",
4826*4882a593Smuzhiyun 				   __func__, arg->field.name);
4827*4882a593Smuzhiyun 			return rc;
4828*4882a593Smuzhiyun 		}
4829*4882a593Smuzhiyun 	}
4830*4882a593Smuzhiyun 
4831*4882a593Smuzhiyun 	buf = data + arg->field.field->offset;
4832*4882a593Smuzhiyun 
4833*4882a593Smuzhiyun 	if (arg->field.field->size != 16) {
4834*4882a593Smuzhiyun 		trace_seq_printf(s, "INVALIDIPv6");
4835*4882a593Smuzhiyun 		return rc;
4836*4882a593Smuzhiyun 	}
4837*4882a593Smuzhiyun 
4838*4882a593Smuzhiyun 	if (have_c)
4839*4882a593Smuzhiyun 		print_ip6c_addr(s, buf);
4840*4882a593Smuzhiyun 	else
4841*4882a593Smuzhiyun 		print_ip6_addr(s, i, buf);
4842*4882a593Smuzhiyun 
4843*4882a593Smuzhiyun 	return rc;
4844*4882a593Smuzhiyun }
4845*4882a593Smuzhiyun 
print_ipsa_arg(struct trace_seq * s,const char * ptr,char i,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4846*4882a593Smuzhiyun static int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i,
4847*4882a593Smuzhiyun 			  void *data, int size, struct tep_event *event,
4848*4882a593Smuzhiyun 			  struct tep_print_arg *arg)
4849*4882a593Smuzhiyun {
4850*4882a593Smuzhiyun 	char have_c = 0, have_p = 0;
4851*4882a593Smuzhiyun 	unsigned char *buf;
4852*4882a593Smuzhiyun 	struct sockaddr_storage *sa;
4853*4882a593Smuzhiyun 	bool reverse = false;
4854*4882a593Smuzhiyun 	int rc = 0;
4855*4882a593Smuzhiyun 	int ret;
4856*4882a593Smuzhiyun 
4857*4882a593Smuzhiyun 	/* pISpc */
4858*4882a593Smuzhiyun 	if (i == 'I') {
4859*4882a593Smuzhiyun 		if (*ptr == 'p') {
4860*4882a593Smuzhiyun 			have_p = 1;
4861*4882a593Smuzhiyun 			ptr++;
4862*4882a593Smuzhiyun 			rc++;
4863*4882a593Smuzhiyun 		}
4864*4882a593Smuzhiyun 		if (*ptr == 'c') {
4865*4882a593Smuzhiyun 			have_c = 1;
4866*4882a593Smuzhiyun 			ptr++;
4867*4882a593Smuzhiyun 			rc++;
4868*4882a593Smuzhiyun 		}
4869*4882a593Smuzhiyun 	}
4870*4882a593Smuzhiyun 	ret = parse_ip4_print_args(event->tep, ptr, &reverse);
4871*4882a593Smuzhiyun 	ptr += ret;
4872*4882a593Smuzhiyun 	rc += ret;
4873*4882a593Smuzhiyun 
4874*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
4875*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4876*4882a593Smuzhiyun 		return rc;
4877*4882a593Smuzhiyun 	}
4878*4882a593Smuzhiyun 
4879*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_FIELD) {
4880*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4881*4882a593Smuzhiyun 		return rc;
4882*4882a593Smuzhiyun 	}
4883*4882a593Smuzhiyun 
4884*4882a593Smuzhiyun 	if (!arg->field.field) {
4885*4882a593Smuzhiyun 		arg->field.field =
4886*4882a593Smuzhiyun 			tep_find_any_field(event, arg->field.name);
4887*4882a593Smuzhiyun 		if (!arg->field.field) {
4888*4882a593Smuzhiyun 			do_warning("%s: field %s not found",
4889*4882a593Smuzhiyun 				   __func__, arg->field.name);
4890*4882a593Smuzhiyun 			return rc;
4891*4882a593Smuzhiyun 		}
4892*4882a593Smuzhiyun 	}
4893*4882a593Smuzhiyun 
4894*4882a593Smuzhiyun 	sa = (struct sockaddr_storage *) (data + arg->field.field->offset);
4895*4882a593Smuzhiyun 
4896*4882a593Smuzhiyun 	if (sa->ss_family == AF_INET) {
4897*4882a593Smuzhiyun 		struct sockaddr_in *sa4 = (struct sockaddr_in *) sa;
4898*4882a593Smuzhiyun 
4899*4882a593Smuzhiyun 		if (arg->field.field->size < sizeof(struct sockaddr_in)) {
4900*4882a593Smuzhiyun 			trace_seq_printf(s, "INVALIDIPv4");
4901*4882a593Smuzhiyun 			return rc;
4902*4882a593Smuzhiyun 		}
4903*4882a593Smuzhiyun 
4904*4882a593Smuzhiyun 		print_ip4_addr(s, i, reverse, (unsigned char *) &sa4->sin_addr);
4905*4882a593Smuzhiyun 		if (have_p)
4906*4882a593Smuzhiyun 			trace_seq_printf(s, ":%d", ntohs(sa4->sin_port));
4907*4882a593Smuzhiyun 
4908*4882a593Smuzhiyun 
4909*4882a593Smuzhiyun 	} else if (sa->ss_family == AF_INET6) {
4910*4882a593Smuzhiyun 		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
4911*4882a593Smuzhiyun 
4912*4882a593Smuzhiyun 		if (arg->field.field->size < sizeof(struct sockaddr_in6)) {
4913*4882a593Smuzhiyun 			trace_seq_printf(s, "INVALIDIPv6");
4914*4882a593Smuzhiyun 			return rc;
4915*4882a593Smuzhiyun 		}
4916*4882a593Smuzhiyun 
4917*4882a593Smuzhiyun 		if (have_p)
4918*4882a593Smuzhiyun 			trace_seq_printf(s, "[");
4919*4882a593Smuzhiyun 
4920*4882a593Smuzhiyun 		buf = (unsigned char *) &sa6->sin6_addr;
4921*4882a593Smuzhiyun 		if (have_c)
4922*4882a593Smuzhiyun 			print_ip6c_addr(s, buf);
4923*4882a593Smuzhiyun 		else
4924*4882a593Smuzhiyun 			print_ip6_addr(s, i, buf);
4925*4882a593Smuzhiyun 
4926*4882a593Smuzhiyun 		if (have_p)
4927*4882a593Smuzhiyun 			trace_seq_printf(s, "]:%d", ntohs(sa6->sin6_port));
4928*4882a593Smuzhiyun 	}
4929*4882a593Smuzhiyun 
4930*4882a593Smuzhiyun 	return rc;
4931*4882a593Smuzhiyun }
4932*4882a593Smuzhiyun 
print_ip_arg(struct trace_seq * s,const char * ptr,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4933*4882a593Smuzhiyun static int print_ip_arg(struct trace_seq *s, const char *ptr,
4934*4882a593Smuzhiyun 			void *data, int size, struct tep_event *event,
4935*4882a593Smuzhiyun 			struct tep_print_arg *arg)
4936*4882a593Smuzhiyun {
4937*4882a593Smuzhiyun 	char i = *ptr;  /* 'i' or 'I' */
4938*4882a593Smuzhiyun 	int rc = 1;
4939*4882a593Smuzhiyun 
4940*4882a593Smuzhiyun 	/* IP version */
4941*4882a593Smuzhiyun 	ptr++;
4942*4882a593Smuzhiyun 
4943*4882a593Smuzhiyun 	switch (*ptr) {
4944*4882a593Smuzhiyun 	case '4':
4945*4882a593Smuzhiyun 		rc += print_ipv4_arg(s, ptr + 1, i, data, size, event, arg);
4946*4882a593Smuzhiyun 		break;
4947*4882a593Smuzhiyun 	case '6':
4948*4882a593Smuzhiyun 		rc += print_ipv6_arg(s, ptr + 1, i, data, size, event, arg);
4949*4882a593Smuzhiyun 		break;
4950*4882a593Smuzhiyun 	case 'S':
4951*4882a593Smuzhiyun 		rc += print_ipsa_arg(s, ptr + 1, i, data, size, event, arg);
4952*4882a593Smuzhiyun 		break;
4953*4882a593Smuzhiyun 	default:
4954*4882a593Smuzhiyun 		return 0;
4955*4882a593Smuzhiyun 	}
4956*4882a593Smuzhiyun 
4957*4882a593Smuzhiyun 	return rc;
4958*4882a593Smuzhiyun }
4959*4882a593Smuzhiyun 
4960*4882a593Smuzhiyun static const int guid_index[16] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15};
4961*4882a593Smuzhiyun static const int uuid_index[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
4962*4882a593Smuzhiyun 
print_uuid_arg(struct trace_seq * s,const char * ptr,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)4963*4882a593Smuzhiyun static int print_uuid_arg(struct trace_seq *s, const char *ptr,
4964*4882a593Smuzhiyun 			void *data, int size, struct tep_event *event,
4965*4882a593Smuzhiyun 			struct tep_print_arg *arg)
4966*4882a593Smuzhiyun {
4967*4882a593Smuzhiyun 	const int *index = uuid_index;
4968*4882a593Smuzhiyun 	char *format = "%02x";
4969*4882a593Smuzhiyun 	int ret = 0;
4970*4882a593Smuzhiyun 	char *buf;
4971*4882a593Smuzhiyun 	int i;
4972*4882a593Smuzhiyun 
4973*4882a593Smuzhiyun 	switch (*(ptr + 1)) {
4974*4882a593Smuzhiyun 	case 'L':
4975*4882a593Smuzhiyun 		format = "%02X";
4976*4882a593Smuzhiyun 		/* fall through */
4977*4882a593Smuzhiyun 	case 'l':
4978*4882a593Smuzhiyun 		index = guid_index;
4979*4882a593Smuzhiyun 		ret++;
4980*4882a593Smuzhiyun 		break;
4981*4882a593Smuzhiyun 	case 'B':
4982*4882a593Smuzhiyun 		format = "%02X";
4983*4882a593Smuzhiyun 		/* fall through */
4984*4882a593Smuzhiyun 	case 'b':
4985*4882a593Smuzhiyun 		ret++;
4986*4882a593Smuzhiyun 		break;
4987*4882a593Smuzhiyun 	}
4988*4882a593Smuzhiyun 
4989*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
4990*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
4991*4882a593Smuzhiyun 		return ret;
4992*4882a593Smuzhiyun 	}
4993*4882a593Smuzhiyun 
4994*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_FIELD) {
4995*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
4996*4882a593Smuzhiyun 		return ret;
4997*4882a593Smuzhiyun 	}
4998*4882a593Smuzhiyun 
4999*4882a593Smuzhiyun 	if (!arg->field.field) {
5000*4882a593Smuzhiyun 		arg->field.field =
5001*4882a593Smuzhiyun 			tep_find_any_field(event, arg->field.name);
5002*4882a593Smuzhiyun 		if (!arg->field.field) {
5003*4882a593Smuzhiyun 			do_warning("%s: field %s not found",
5004*4882a593Smuzhiyun 				   __func__, arg->field.name);
5005*4882a593Smuzhiyun 			return ret;
5006*4882a593Smuzhiyun 		}
5007*4882a593Smuzhiyun 	}
5008*4882a593Smuzhiyun 
5009*4882a593Smuzhiyun 	if (arg->field.field->size != 16) {
5010*4882a593Smuzhiyun 		trace_seq_printf(s, "INVALIDUUID");
5011*4882a593Smuzhiyun 		return ret;
5012*4882a593Smuzhiyun 	}
5013*4882a593Smuzhiyun 
5014*4882a593Smuzhiyun 	buf = data + arg->field.field->offset;
5015*4882a593Smuzhiyun 
5016*4882a593Smuzhiyun 	for (i = 0; i < 16; i++) {
5017*4882a593Smuzhiyun 		trace_seq_printf(s, format, buf[index[i]] & 0xff);
5018*4882a593Smuzhiyun 		switch (i) {
5019*4882a593Smuzhiyun 		case 3:
5020*4882a593Smuzhiyun 		case 5:
5021*4882a593Smuzhiyun 		case 7:
5022*4882a593Smuzhiyun 		case 9:
5023*4882a593Smuzhiyun 			trace_seq_printf(s, "-");
5024*4882a593Smuzhiyun 			break;
5025*4882a593Smuzhiyun 		}
5026*4882a593Smuzhiyun 	}
5027*4882a593Smuzhiyun 
5028*4882a593Smuzhiyun 	return ret;
5029*4882a593Smuzhiyun }
5030*4882a593Smuzhiyun 
print_raw_buff_arg(struct trace_seq * s,const char * ptr,void * data,int size,struct tep_event * event,struct tep_print_arg * arg,int print_len)5031*4882a593Smuzhiyun static int print_raw_buff_arg(struct trace_seq *s, const char *ptr,
5032*4882a593Smuzhiyun 			      void *data, int size, struct tep_event *event,
5033*4882a593Smuzhiyun 			      struct tep_print_arg *arg, int print_len)
5034*4882a593Smuzhiyun {
5035*4882a593Smuzhiyun 	int plen = print_len;
5036*4882a593Smuzhiyun 	char *delim = " ";
5037*4882a593Smuzhiyun 	int ret = 0;
5038*4882a593Smuzhiyun 	char *buf;
5039*4882a593Smuzhiyun 	int i;
5040*4882a593Smuzhiyun 	unsigned long offset;
5041*4882a593Smuzhiyun 	int arr_len;
5042*4882a593Smuzhiyun 
5043*4882a593Smuzhiyun 	switch (*(ptr + 1)) {
5044*4882a593Smuzhiyun 	case 'C':
5045*4882a593Smuzhiyun 		delim = ":";
5046*4882a593Smuzhiyun 		ret++;
5047*4882a593Smuzhiyun 		break;
5048*4882a593Smuzhiyun 	case 'D':
5049*4882a593Smuzhiyun 		delim = "-";
5050*4882a593Smuzhiyun 		ret++;
5051*4882a593Smuzhiyun 		break;
5052*4882a593Smuzhiyun 	case 'N':
5053*4882a593Smuzhiyun 		delim = "";
5054*4882a593Smuzhiyun 		ret++;
5055*4882a593Smuzhiyun 		break;
5056*4882a593Smuzhiyun 	}
5057*4882a593Smuzhiyun 
5058*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_FUNC) {
5059*4882a593Smuzhiyun 		process_defined_func(s, data, size, event, arg);
5060*4882a593Smuzhiyun 		return ret;
5061*4882a593Smuzhiyun 	}
5062*4882a593Smuzhiyun 
5063*4882a593Smuzhiyun 	if (arg->type != TEP_PRINT_DYNAMIC_ARRAY) {
5064*4882a593Smuzhiyun 		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
5065*4882a593Smuzhiyun 		return ret;
5066*4882a593Smuzhiyun 	}
5067*4882a593Smuzhiyun 
5068*4882a593Smuzhiyun 	offset = tep_read_number(event->tep,
5069*4882a593Smuzhiyun 				 data + arg->dynarray.field->offset,
5070*4882a593Smuzhiyun 				 arg->dynarray.field->size);
5071*4882a593Smuzhiyun 	arr_len = (unsigned long long)(offset >> 16);
5072*4882a593Smuzhiyun 	buf = data + (offset & 0xffff);
5073*4882a593Smuzhiyun 
5074*4882a593Smuzhiyun 	if (arr_len < plen)
5075*4882a593Smuzhiyun 		plen = arr_len;
5076*4882a593Smuzhiyun 
5077*4882a593Smuzhiyun 	if (plen < 1)
5078*4882a593Smuzhiyun 		return ret;
5079*4882a593Smuzhiyun 
5080*4882a593Smuzhiyun 	trace_seq_printf(s, "%02x", buf[0] & 0xff);
5081*4882a593Smuzhiyun 	for (i = 1; i < plen; i++)
5082*4882a593Smuzhiyun 		trace_seq_printf(s, "%s%02x", delim, buf[i] & 0xff);
5083*4882a593Smuzhiyun 
5084*4882a593Smuzhiyun 	return ret;
5085*4882a593Smuzhiyun }
5086*4882a593Smuzhiyun 
is_printable_array(char * p,unsigned int len)5087*4882a593Smuzhiyun static int is_printable_array(char *p, unsigned int len)
5088*4882a593Smuzhiyun {
5089*4882a593Smuzhiyun 	unsigned int i;
5090*4882a593Smuzhiyun 
5091*4882a593Smuzhiyun 	for (i = 0; i < len && p[i]; i++)
5092*4882a593Smuzhiyun 		if (!isprint(p[i]) && !isspace(p[i]))
5093*4882a593Smuzhiyun 		    return 0;
5094*4882a593Smuzhiyun 	return 1;
5095*4882a593Smuzhiyun }
5096*4882a593Smuzhiyun 
tep_print_field(struct trace_seq * s,void * data,struct tep_format_field * field)5097*4882a593Smuzhiyun void tep_print_field(struct trace_seq *s, void *data,
5098*4882a593Smuzhiyun 		     struct tep_format_field *field)
5099*4882a593Smuzhiyun {
5100*4882a593Smuzhiyun 	unsigned long long val;
5101*4882a593Smuzhiyun 	unsigned int offset, len, i;
5102*4882a593Smuzhiyun 	struct tep_handle *tep = field->event->tep;
5103*4882a593Smuzhiyun 
5104*4882a593Smuzhiyun 	if (field->flags & TEP_FIELD_IS_ARRAY) {
5105*4882a593Smuzhiyun 		offset = field->offset;
5106*4882a593Smuzhiyun 		len = field->size;
5107*4882a593Smuzhiyun 		if (field->flags & TEP_FIELD_IS_DYNAMIC) {
5108*4882a593Smuzhiyun 			val = tep_read_number(tep, data + offset, len);
5109*4882a593Smuzhiyun 			offset = val;
5110*4882a593Smuzhiyun 			len = offset >> 16;
5111*4882a593Smuzhiyun 			offset &= 0xffff;
5112*4882a593Smuzhiyun 		}
5113*4882a593Smuzhiyun 		if (field->flags & TEP_FIELD_IS_STRING &&
5114*4882a593Smuzhiyun 		    is_printable_array(data + offset, len)) {
5115*4882a593Smuzhiyun 			trace_seq_printf(s, "%s", (char *)data + offset);
5116*4882a593Smuzhiyun 		} else {
5117*4882a593Smuzhiyun 			trace_seq_puts(s, "ARRAY[");
5118*4882a593Smuzhiyun 			for (i = 0; i < len; i++) {
5119*4882a593Smuzhiyun 				if (i)
5120*4882a593Smuzhiyun 					trace_seq_puts(s, ", ");
5121*4882a593Smuzhiyun 				trace_seq_printf(s, "%02x",
5122*4882a593Smuzhiyun 						 *((unsigned char *)data + offset + i));
5123*4882a593Smuzhiyun 			}
5124*4882a593Smuzhiyun 			trace_seq_putc(s, ']');
5125*4882a593Smuzhiyun 			field->flags &= ~TEP_FIELD_IS_STRING;
5126*4882a593Smuzhiyun 		}
5127*4882a593Smuzhiyun 	} else {
5128*4882a593Smuzhiyun 		val = tep_read_number(tep, data + field->offset,
5129*4882a593Smuzhiyun 				      field->size);
5130*4882a593Smuzhiyun 		if (field->flags & TEP_FIELD_IS_POINTER) {
5131*4882a593Smuzhiyun 			trace_seq_printf(s, "0x%llx", val);
5132*4882a593Smuzhiyun 		} else if (field->flags & TEP_FIELD_IS_SIGNED) {
5133*4882a593Smuzhiyun 			switch (field->size) {
5134*4882a593Smuzhiyun 			case 4:
5135*4882a593Smuzhiyun 				/*
5136*4882a593Smuzhiyun 				 * If field is long then print it in hex.
5137*4882a593Smuzhiyun 				 * A long usually stores pointers.
5138*4882a593Smuzhiyun 				 */
5139*4882a593Smuzhiyun 				if (field->flags & TEP_FIELD_IS_LONG)
5140*4882a593Smuzhiyun 					trace_seq_printf(s, "0x%x", (int)val);
5141*4882a593Smuzhiyun 				else
5142*4882a593Smuzhiyun 					trace_seq_printf(s, "%d", (int)val);
5143*4882a593Smuzhiyun 				break;
5144*4882a593Smuzhiyun 			case 2:
5145*4882a593Smuzhiyun 				trace_seq_printf(s, "%2d", (short)val);
5146*4882a593Smuzhiyun 				break;
5147*4882a593Smuzhiyun 			case 1:
5148*4882a593Smuzhiyun 				trace_seq_printf(s, "%1d", (char)val);
5149*4882a593Smuzhiyun 				break;
5150*4882a593Smuzhiyun 			default:
5151*4882a593Smuzhiyun 				trace_seq_printf(s, "%lld", val);
5152*4882a593Smuzhiyun 			}
5153*4882a593Smuzhiyun 		} else {
5154*4882a593Smuzhiyun 			if (field->flags & TEP_FIELD_IS_LONG)
5155*4882a593Smuzhiyun 				trace_seq_printf(s, "0x%llx", val);
5156*4882a593Smuzhiyun 			else
5157*4882a593Smuzhiyun 				trace_seq_printf(s, "%llu", val);
5158*4882a593Smuzhiyun 		}
5159*4882a593Smuzhiyun 	}
5160*4882a593Smuzhiyun }
5161*4882a593Smuzhiyun 
tep_print_fields(struct trace_seq * s,void * data,int size __maybe_unused,struct tep_event * event)5162*4882a593Smuzhiyun void tep_print_fields(struct trace_seq *s, void *data,
5163*4882a593Smuzhiyun 		      int size __maybe_unused, struct tep_event *event)
5164*4882a593Smuzhiyun {
5165*4882a593Smuzhiyun 	struct tep_format_field *field;
5166*4882a593Smuzhiyun 
5167*4882a593Smuzhiyun 	field = event->format.fields;
5168*4882a593Smuzhiyun 	while (field) {
5169*4882a593Smuzhiyun 		trace_seq_printf(s, " %s=", field->name);
5170*4882a593Smuzhiyun 		tep_print_field(s, data, field);
5171*4882a593Smuzhiyun 		field = field->next;
5172*4882a593Smuzhiyun 	}
5173*4882a593Smuzhiyun }
5174*4882a593Smuzhiyun 
print_function(struct trace_seq * s,const char * format,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)5175*4882a593Smuzhiyun static int print_function(struct trace_seq *s, const char *format,
5176*4882a593Smuzhiyun 			  void *data, int size, struct tep_event *event,
5177*4882a593Smuzhiyun 			  struct tep_print_arg *arg)
5178*4882a593Smuzhiyun {
5179*4882a593Smuzhiyun 	struct func_map *func;
5180*4882a593Smuzhiyun 	unsigned long long val;
5181*4882a593Smuzhiyun 
5182*4882a593Smuzhiyun 	val = eval_num_arg(data, size, event, arg);
5183*4882a593Smuzhiyun 	func = find_func(event->tep, val);
5184*4882a593Smuzhiyun 	if (func) {
5185*4882a593Smuzhiyun 		trace_seq_puts(s, func->func);
5186*4882a593Smuzhiyun 		if (*format == 'F' || *format == 'S')
5187*4882a593Smuzhiyun 			trace_seq_printf(s, "+0x%llx", val - func->addr);
5188*4882a593Smuzhiyun 	} else {
5189*4882a593Smuzhiyun 		if (event->tep->long_size == 4)
5190*4882a593Smuzhiyun 			trace_seq_printf(s, "0x%lx", (long)val);
5191*4882a593Smuzhiyun 		else
5192*4882a593Smuzhiyun 			trace_seq_printf(s, "0x%llx", (long long)val);
5193*4882a593Smuzhiyun 	}
5194*4882a593Smuzhiyun 
5195*4882a593Smuzhiyun 	return 0;
5196*4882a593Smuzhiyun }
5197*4882a593Smuzhiyun 
print_arg_pointer(struct trace_seq * s,const char * format,int plen,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)5198*4882a593Smuzhiyun static int print_arg_pointer(struct trace_seq *s, const char *format, int plen,
5199*4882a593Smuzhiyun 			     void *data, int size,
5200*4882a593Smuzhiyun 			     struct tep_event *event, struct tep_print_arg *arg)
5201*4882a593Smuzhiyun {
5202*4882a593Smuzhiyun 	unsigned long long val;
5203*4882a593Smuzhiyun 	int ret = 1;
5204*4882a593Smuzhiyun 
5205*4882a593Smuzhiyun 	if (arg->type == TEP_PRINT_BSTRING) {
5206*4882a593Smuzhiyun 		trace_seq_puts(s, arg->string.string);
5207*4882a593Smuzhiyun 		return 0;
5208*4882a593Smuzhiyun 	}
5209*4882a593Smuzhiyun 	while (*format) {
5210*4882a593Smuzhiyun 		if (*format == 'p') {
5211*4882a593Smuzhiyun 			format++;
5212*4882a593Smuzhiyun 			break;
5213*4882a593Smuzhiyun 		}
5214*4882a593Smuzhiyun 		format++;
5215*4882a593Smuzhiyun 	}
5216*4882a593Smuzhiyun 
5217*4882a593Smuzhiyun 	switch (*format) {
5218*4882a593Smuzhiyun 	case 'F':
5219*4882a593Smuzhiyun 	case 'f':
5220*4882a593Smuzhiyun 	case 'S':
5221*4882a593Smuzhiyun 	case 's':
5222*4882a593Smuzhiyun 		ret += print_function(s, format, data, size, event, arg);
5223*4882a593Smuzhiyun 		break;
5224*4882a593Smuzhiyun 	case 'M':
5225*4882a593Smuzhiyun 	case 'm':
5226*4882a593Smuzhiyun 		ret += print_mac_arg(s, format, data, size, event, arg);
5227*4882a593Smuzhiyun 		break;
5228*4882a593Smuzhiyun 	case 'I':
5229*4882a593Smuzhiyun 	case 'i':
5230*4882a593Smuzhiyun 		ret += print_ip_arg(s, format, data, size, event, arg);
5231*4882a593Smuzhiyun 		break;
5232*4882a593Smuzhiyun 	case 'U':
5233*4882a593Smuzhiyun 		ret += print_uuid_arg(s, format, data, size, event, arg);
5234*4882a593Smuzhiyun 		break;
5235*4882a593Smuzhiyun 	case 'h':
5236*4882a593Smuzhiyun 		ret += print_raw_buff_arg(s, format, data, size, event, arg, plen);
5237*4882a593Smuzhiyun 		break;
5238*4882a593Smuzhiyun 	default:
5239*4882a593Smuzhiyun 		ret = 0;
5240*4882a593Smuzhiyun 		val = eval_num_arg(data, size, event, arg);
5241*4882a593Smuzhiyun 		trace_seq_printf(s, "%p", (void *)(intptr_t)val);
5242*4882a593Smuzhiyun 		break;
5243*4882a593Smuzhiyun 	}
5244*4882a593Smuzhiyun 
5245*4882a593Smuzhiyun 	return ret;
5246*4882a593Smuzhiyun 
5247*4882a593Smuzhiyun }
5248*4882a593Smuzhiyun 
print_arg_number(struct trace_seq * s,const char * format,int plen,void * data,int size,int ls,struct tep_event * event,struct tep_print_arg * arg)5249*4882a593Smuzhiyun static int print_arg_number(struct trace_seq *s, const char *format, int plen,
5250*4882a593Smuzhiyun 			    void *data, int size, int ls,
5251*4882a593Smuzhiyun 			    struct tep_event *event, struct tep_print_arg *arg)
5252*4882a593Smuzhiyun {
5253*4882a593Smuzhiyun 	unsigned long long val;
5254*4882a593Smuzhiyun 
5255*4882a593Smuzhiyun 	val = eval_num_arg(data, size, event, arg);
5256*4882a593Smuzhiyun 
5257*4882a593Smuzhiyun 	switch (ls) {
5258*4882a593Smuzhiyun 	case -2:
5259*4882a593Smuzhiyun 		if (plen >= 0)
5260*4882a593Smuzhiyun 			trace_seq_printf(s, format, plen, (char)val);
5261*4882a593Smuzhiyun 		else
5262*4882a593Smuzhiyun 			trace_seq_printf(s, format, (char)val);
5263*4882a593Smuzhiyun 		break;
5264*4882a593Smuzhiyun 	case -1:
5265*4882a593Smuzhiyun 		if (plen >= 0)
5266*4882a593Smuzhiyun 			trace_seq_printf(s, format, plen, (short)val);
5267*4882a593Smuzhiyun 		else
5268*4882a593Smuzhiyun 			trace_seq_printf(s, format, (short)val);
5269*4882a593Smuzhiyun 		break;
5270*4882a593Smuzhiyun 	case 0:
5271*4882a593Smuzhiyun 		if (plen >= 0)
5272*4882a593Smuzhiyun 			trace_seq_printf(s, format, plen, (int)val);
5273*4882a593Smuzhiyun 		else
5274*4882a593Smuzhiyun 			trace_seq_printf(s, format, (int)val);
5275*4882a593Smuzhiyun 		break;
5276*4882a593Smuzhiyun 	case 1:
5277*4882a593Smuzhiyun 		if (plen >= 0)
5278*4882a593Smuzhiyun 			trace_seq_printf(s, format, plen, (long)val);
5279*4882a593Smuzhiyun 		else
5280*4882a593Smuzhiyun 			trace_seq_printf(s, format, (long)val);
5281*4882a593Smuzhiyun 		break;
5282*4882a593Smuzhiyun 	case 2:
5283*4882a593Smuzhiyun 		if (plen >= 0)
5284*4882a593Smuzhiyun 			trace_seq_printf(s, format, plen, (long long)val);
5285*4882a593Smuzhiyun 		else
5286*4882a593Smuzhiyun 			trace_seq_printf(s, format, (long long)val);
5287*4882a593Smuzhiyun 		break;
5288*4882a593Smuzhiyun 	default:
5289*4882a593Smuzhiyun 		do_warning_event(event, "bad count (%d)", ls);
5290*4882a593Smuzhiyun 		event->flags |= TEP_EVENT_FL_FAILED;
5291*4882a593Smuzhiyun 	}
5292*4882a593Smuzhiyun 	return 0;
5293*4882a593Smuzhiyun }
5294*4882a593Smuzhiyun 
5295*4882a593Smuzhiyun 
print_arg_string(struct trace_seq * s,const char * format,int plen,void * data,int size,struct tep_event * event,struct tep_print_arg * arg)5296*4882a593Smuzhiyun static void print_arg_string(struct trace_seq *s, const char *format, int plen,
5297*4882a593Smuzhiyun 			     void *data, int size,
5298*4882a593Smuzhiyun 			     struct tep_event *event, struct tep_print_arg *arg)
5299*4882a593Smuzhiyun {
5300*4882a593Smuzhiyun 	struct trace_seq p;
5301*4882a593Smuzhiyun 
5302*4882a593Smuzhiyun 	/* Use helper trace_seq */
5303*4882a593Smuzhiyun 	trace_seq_init(&p);
5304*4882a593Smuzhiyun 	print_str_arg(&p, data, size, event,
5305*4882a593Smuzhiyun 		      format, plen, arg);
5306*4882a593Smuzhiyun 	trace_seq_terminate(&p);
5307*4882a593Smuzhiyun 	trace_seq_puts(s, p.buffer);
5308*4882a593Smuzhiyun 	trace_seq_destroy(&p);
5309*4882a593Smuzhiyun }
5310*4882a593Smuzhiyun 
parse_arg_format_pointer(const char * format)5311*4882a593Smuzhiyun static int parse_arg_format_pointer(const char *format)
5312*4882a593Smuzhiyun {
5313*4882a593Smuzhiyun 	int ret = 0;
5314*4882a593Smuzhiyun 	int index;
5315*4882a593Smuzhiyun 	int loop;
5316*4882a593Smuzhiyun 
5317*4882a593Smuzhiyun 	switch (*format) {
5318*4882a593Smuzhiyun 	case 'F':
5319*4882a593Smuzhiyun 	case 'S':
5320*4882a593Smuzhiyun 	case 'f':
5321*4882a593Smuzhiyun 	case 's':
5322*4882a593Smuzhiyun 		ret++;
5323*4882a593Smuzhiyun 		break;
5324*4882a593Smuzhiyun 	case 'M':
5325*4882a593Smuzhiyun 	case 'm':
5326*4882a593Smuzhiyun 		/* [mM]R , [mM]F */
5327*4882a593Smuzhiyun 		switch (format[1]) {
5328*4882a593Smuzhiyun 		case 'R':
5329*4882a593Smuzhiyun 		case 'F':
5330*4882a593Smuzhiyun 			ret++;
5331*4882a593Smuzhiyun 			break;
5332*4882a593Smuzhiyun 		}
5333*4882a593Smuzhiyun 		ret++;
5334*4882a593Smuzhiyun 		break;
5335*4882a593Smuzhiyun 	case 'I':
5336*4882a593Smuzhiyun 	case 'i':
5337*4882a593Smuzhiyun 		index = 2;
5338*4882a593Smuzhiyun 		loop = 1;
5339*4882a593Smuzhiyun 		switch (format[1]) {
5340*4882a593Smuzhiyun 		case 'S':
5341*4882a593Smuzhiyun 			/*[S][pfs]*/
5342*4882a593Smuzhiyun 			while (loop) {
5343*4882a593Smuzhiyun 				switch (format[index]) {
5344*4882a593Smuzhiyun 				case 'p':
5345*4882a593Smuzhiyun 				case 'f':
5346*4882a593Smuzhiyun 				case 's':
5347*4882a593Smuzhiyun 					ret++;
5348*4882a593Smuzhiyun 					index++;
5349*4882a593Smuzhiyun 					break;
5350*4882a593Smuzhiyun 				default:
5351*4882a593Smuzhiyun 					loop = 0;
5352*4882a593Smuzhiyun 					break;
5353*4882a593Smuzhiyun 				}
5354*4882a593Smuzhiyun 			}
5355*4882a593Smuzhiyun 			/* fall through */
5356*4882a593Smuzhiyun 		case '4':
5357*4882a593Smuzhiyun 			/* [4S][hnbl] */
5358*4882a593Smuzhiyun 			switch (format[index]) {
5359*4882a593Smuzhiyun 			case 'h':
5360*4882a593Smuzhiyun 			case 'n':
5361*4882a593Smuzhiyun 			case 'l':
5362*4882a593Smuzhiyun 			case 'b':
5363*4882a593Smuzhiyun 				ret++;
5364*4882a593Smuzhiyun 				index++;
5365*4882a593Smuzhiyun 				break;
5366*4882a593Smuzhiyun 			}
5367*4882a593Smuzhiyun 			if (format[1] == '4') {
5368*4882a593Smuzhiyun 				ret++;
5369*4882a593Smuzhiyun 				break;
5370*4882a593Smuzhiyun 			}
5371*4882a593Smuzhiyun 			/* fall through */
5372*4882a593Smuzhiyun 		case '6':
5373*4882a593Smuzhiyun 			/* [6S]c */
5374*4882a593Smuzhiyun 			if (format[index] == 'c')
5375*4882a593Smuzhiyun 				ret++;
5376*4882a593Smuzhiyun 			ret++;
5377*4882a593Smuzhiyun 			break;
5378*4882a593Smuzhiyun 		}
5379*4882a593Smuzhiyun 		ret++;
5380*4882a593Smuzhiyun 		break;
5381*4882a593Smuzhiyun 	case 'U':
5382*4882a593Smuzhiyun 		switch (format[1]) {
5383*4882a593Smuzhiyun 		case 'L':
5384*4882a593Smuzhiyun 		case 'l':
5385*4882a593Smuzhiyun 		case 'B':
5386*4882a593Smuzhiyun 		case 'b':
5387*4882a593Smuzhiyun 			ret++;
5388*4882a593Smuzhiyun 			break;
5389*4882a593Smuzhiyun 		}
5390*4882a593Smuzhiyun 		ret++;
5391*4882a593Smuzhiyun 		break;
5392*4882a593Smuzhiyun 	case 'h':
5393*4882a593Smuzhiyun 		switch (format[1]) {
5394*4882a593Smuzhiyun 		case 'C':
5395*4882a593Smuzhiyun 		case 'D':
5396*4882a593Smuzhiyun 		case 'N':
5397*4882a593Smuzhiyun 			ret++;
5398*4882a593Smuzhiyun 			break;
5399*4882a593Smuzhiyun 		}
5400*4882a593Smuzhiyun 		ret++;
5401*4882a593Smuzhiyun 		break;
5402*4882a593Smuzhiyun 	default:
5403*4882a593Smuzhiyun 		break;
5404*4882a593Smuzhiyun 	}
5405*4882a593Smuzhiyun 
5406*4882a593Smuzhiyun 	return ret;
5407*4882a593Smuzhiyun }
5408*4882a593Smuzhiyun 
free_parse_args(struct tep_print_parse * arg)5409*4882a593Smuzhiyun static void free_parse_args(struct tep_print_parse *arg)
5410*4882a593Smuzhiyun {
5411*4882a593Smuzhiyun 	struct tep_print_parse *del;
5412*4882a593Smuzhiyun 
5413*4882a593Smuzhiyun 	while (arg) {
5414*4882a593Smuzhiyun 		del = arg;
5415*4882a593Smuzhiyun 		arg = del->next;
5416*4882a593Smuzhiyun 		free(del->format);
5417*4882a593Smuzhiyun 		free(del);
5418*4882a593Smuzhiyun 	}
5419*4882a593Smuzhiyun }
5420*4882a593Smuzhiyun 
parse_arg_add(struct tep_print_parse ** parse,char * format,enum tep_print_parse_type type,struct tep_print_arg * arg,struct tep_print_arg * len_as_arg,int ls)5421*4882a593Smuzhiyun static int parse_arg_add(struct tep_print_parse **parse, char *format,
5422*4882a593Smuzhiyun 			 enum tep_print_parse_type type,
5423*4882a593Smuzhiyun 			 struct tep_print_arg *arg,
5424*4882a593Smuzhiyun 			 struct tep_print_arg *len_as_arg,
5425*4882a593Smuzhiyun 			 int ls)
5426*4882a593Smuzhiyun {
5427*4882a593Smuzhiyun 	struct tep_print_parse *parg = NULL;
5428*4882a593Smuzhiyun 
5429*4882a593Smuzhiyun 	parg = calloc(1, sizeof(*parg));
5430*4882a593Smuzhiyun 	if (!parg)
5431*4882a593Smuzhiyun 		goto error;
5432*4882a593Smuzhiyun 	parg->format = strdup(format);
5433*4882a593Smuzhiyun 	if (!parg->format)
5434*4882a593Smuzhiyun 		goto error;
5435*4882a593Smuzhiyun 	parg->type = type;
5436*4882a593Smuzhiyun 	parg->arg = arg;
5437*4882a593Smuzhiyun 	parg->len_as_arg = len_as_arg;
5438*4882a593Smuzhiyun 	parg->ls = ls;
5439*4882a593Smuzhiyun 	*parse = parg;
5440*4882a593Smuzhiyun 	return 0;
5441*4882a593Smuzhiyun error:
5442*4882a593Smuzhiyun 	if (parg) {
5443*4882a593Smuzhiyun 		free(parg->format);
5444*4882a593Smuzhiyun 		free(parg);
5445*4882a593Smuzhiyun 	}
5446*4882a593Smuzhiyun 	return -1;
5447*4882a593Smuzhiyun }
5448*4882a593Smuzhiyun 
parse_arg_format(struct tep_print_parse ** parse,struct tep_event * event,const char * format,struct tep_print_arg ** arg)5449*4882a593Smuzhiyun static int parse_arg_format(struct tep_print_parse **parse,
5450*4882a593Smuzhiyun 			    struct tep_event *event,
5451*4882a593Smuzhiyun 			    const char *format, struct tep_print_arg **arg)
5452*4882a593Smuzhiyun {
5453*4882a593Smuzhiyun 	struct tep_print_arg *len_arg = NULL;
5454*4882a593Smuzhiyun 	char print_format[32];
5455*4882a593Smuzhiyun 	const char *start = format;
5456*4882a593Smuzhiyun 	int ret = 0;
5457*4882a593Smuzhiyun 	int ls = 0;
5458*4882a593Smuzhiyun 	int res;
5459*4882a593Smuzhiyun 	int len;
5460*4882a593Smuzhiyun 
5461*4882a593Smuzhiyun 	format++;
5462*4882a593Smuzhiyun 	ret++;
5463*4882a593Smuzhiyun 	for (; *format; format++) {
5464*4882a593Smuzhiyun 		switch (*format) {
5465*4882a593Smuzhiyun 		case '#':
5466*4882a593Smuzhiyun 			/* FIXME: need to handle properly */
5467*4882a593Smuzhiyun 			break;
5468*4882a593Smuzhiyun 		case 'h':
5469*4882a593Smuzhiyun 			ls--;
5470*4882a593Smuzhiyun 			break;
5471*4882a593Smuzhiyun 		case 'l':
5472*4882a593Smuzhiyun 			ls++;
5473*4882a593Smuzhiyun 			break;
5474*4882a593Smuzhiyun 		case 'L':
5475*4882a593Smuzhiyun 			ls = 2;
5476*4882a593Smuzhiyun 			break;
5477*4882a593Smuzhiyun 		case '.':
5478*4882a593Smuzhiyun 		case 'z':
5479*4882a593Smuzhiyun 		case 'Z':
5480*4882a593Smuzhiyun 		case '0' ... '9':
5481*4882a593Smuzhiyun 		case '-':
5482*4882a593Smuzhiyun 			break;
5483*4882a593Smuzhiyun 		case '*':
5484*4882a593Smuzhiyun 			/* The argument is the length. */
5485*4882a593Smuzhiyun 			if (!*arg) {
5486*4882a593Smuzhiyun 				do_warning_event(event, "no argument match");
5487*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5488*4882a593Smuzhiyun 				goto out_failed;
5489*4882a593Smuzhiyun 			}
5490*4882a593Smuzhiyun 			if (len_arg) {
5491*4882a593Smuzhiyun 				do_warning_event(event, "argument already matched");
5492*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5493*4882a593Smuzhiyun 				goto out_failed;
5494*4882a593Smuzhiyun 			}
5495*4882a593Smuzhiyun 			len_arg = *arg;
5496*4882a593Smuzhiyun 			*arg = (*arg)->next;
5497*4882a593Smuzhiyun 			break;
5498*4882a593Smuzhiyun 		case 'p':
5499*4882a593Smuzhiyun 			if (!*arg) {
5500*4882a593Smuzhiyun 				do_warning_event(event, "no argument match");
5501*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5502*4882a593Smuzhiyun 				goto out_failed;
5503*4882a593Smuzhiyun 			}
5504*4882a593Smuzhiyun 			res = parse_arg_format_pointer(format + 1);
5505*4882a593Smuzhiyun 			if (res > 0) {
5506*4882a593Smuzhiyun 				format += res;
5507*4882a593Smuzhiyun 				ret += res;
5508*4882a593Smuzhiyun 			}
5509*4882a593Smuzhiyun 			len = ((unsigned long)format + 1) -
5510*4882a593Smuzhiyun 				(unsigned long)start;
5511*4882a593Smuzhiyun 			/* should never happen */
5512*4882a593Smuzhiyun 			if (len > 31) {
5513*4882a593Smuzhiyun 				do_warning_event(event, "bad format!");
5514*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5515*4882a593Smuzhiyun 				len = 31;
5516*4882a593Smuzhiyun 			}
5517*4882a593Smuzhiyun 			memcpy(print_format, start, len);
5518*4882a593Smuzhiyun 			print_format[len] = 0;
5519*4882a593Smuzhiyun 
5520*4882a593Smuzhiyun 			parse_arg_add(parse, print_format,
5521*4882a593Smuzhiyun 				      PRINT_FMT_ARG_POINTER, *arg, len_arg, ls);
5522*4882a593Smuzhiyun 			*arg = (*arg)->next;
5523*4882a593Smuzhiyun 			ret++;
5524*4882a593Smuzhiyun 			return ret;
5525*4882a593Smuzhiyun 		case 'd':
5526*4882a593Smuzhiyun 		case 'u':
5527*4882a593Smuzhiyun 		case 'i':
5528*4882a593Smuzhiyun 		case 'x':
5529*4882a593Smuzhiyun 		case 'X':
5530*4882a593Smuzhiyun 		case 'o':
5531*4882a593Smuzhiyun 			if (!*arg) {
5532*4882a593Smuzhiyun 				do_warning_event(event, "no argument match");
5533*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5534*4882a593Smuzhiyun 				goto out_failed;
5535*4882a593Smuzhiyun 			}
5536*4882a593Smuzhiyun 
5537*4882a593Smuzhiyun 			len = ((unsigned long)format + 1) -
5538*4882a593Smuzhiyun 				(unsigned long)start;
5539*4882a593Smuzhiyun 
5540*4882a593Smuzhiyun 			/* should never happen */
5541*4882a593Smuzhiyun 			if (len > 30) {
5542*4882a593Smuzhiyun 				do_warning_event(event, "bad format!");
5543*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5544*4882a593Smuzhiyun 				len = 31;
5545*4882a593Smuzhiyun 			}
5546*4882a593Smuzhiyun 			memcpy(print_format, start, len);
5547*4882a593Smuzhiyun 			print_format[len] = 0;
5548*4882a593Smuzhiyun 
5549*4882a593Smuzhiyun 			if (event->tep->long_size == 8 && ls == 1 &&
5550*4882a593Smuzhiyun 			    sizeof(long) != 8) {
5551*4882a593Smuzhiyun 				char *p;
5552*4882a593Smuzhiyun 
5553*4882a593Smuzhiyun 				/* make %l into %ll */
5554*4882a593Smuzhiyun 				if (ls == 1 && (p = strchr(print_format, 'l')))
5555*4882a593Smuzhiyun 					memmove(p+1, p, strlen(p)+1);
5556*4882a593Smuzhiyun 				ls = 2;
5557*4882a593Smuzhiyun 			}
5558*4882a593Smuzhiyun 			if (ls < -2 || ls > 2) {
5559*4882a593Smuzhiyun 				do_warning_event(event, "bad count (%d)", ls);
5560*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5561*4882a593Smuzhiyun 			}
5562*4882a593Smuzhiyun 			parse_arg_add(parse, print_format,
5563*4882a593Smuzhiyun 				      PRINT_FMT_ARG_DIGIT, *arg, len_arg, ls);
5564*4882a593Smuzhiyun 			*arg = (*arg)->next;
5565*4882a593Smuzhiyun 			ret++;
5566*4882a593Smuzhiyun 			return ret;
5567*4882a593Smuzhiyun 		case 's':
5568*4882a593Smuzhiyun 			if (!*arg) {
5569*4882a593Smuzhiyun 				do_warning_event(event, "no matching argument");
5570*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5571*4882a593Smuzhiyun 				goto out_failed;
5572*4882a593Smuzhiyun 			}
5573*4882a593Smuzhiyun 
5574*4882a593Smuzhiyun 			len = ((unsigned long)format + 1) -
5575*4882a593Smuzhiyun 				(unsigned long)start;
5576*4882a593Smuzhiyun 
5577*4882a593Smuzhiyun 			/* should never happen */
5578*4882a593Smuzhiyun 			if (len > 31) {
5579*4882a593Smuzhiyun 				do_warning_event(event, "bad format!");
5580*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
5581*4882a593Smuzhiyun 				len = 31;
5582*4882a593Smuzhiyun 			}
5583*4882a593Smuzhiyun 
5584*4882a593Smuzhiyun 			memcpy(print_format, start, len);
5585*4882a593Smuzhiyun 			print_format[len] = 0;
5586*4882a593Smuzhiyun 
5587*4882a593Smuzhiyun 			parse_arg_add(parse, print_format,
5588*4882a593Smuzhiyun 					PRINT_FMT_ARG_STRING, *arg, len_arg, 0);
5589*4882a593Smuzhiyun 			*arg = (*arg)->next;
5590*4882a593Smuzhiyun 			ret++;
5591*4882a593Smuzhiyun 			return ret;
5592*4882a593Smuzhiyun 		default:
5593*4882a593Smuzhiyun 			snprintf(print_format, 32, ">%c<", *format);
5594*4882a593Smuzhiyun 			parse_arg_add(parse, print_format,
5595*4882a593Smuzhiyun 					PRINT_FMT_STRING, NULL, NULL, 0);
5596*4882a593Smuzhiyun 			ret++;
5597*4882a593Smuzhiyun 			return ret;
5598*4882a593Smuzhiyun 		}
5599*4882a593Smuzhiyun 		ret++;
5600*4882a593Smuzhiyun 	}
5601*4882a593Smuzhiyun 
5602*4882a593Smuzhiyun out_failed:
5603*4882a593Smuzhiyun 	return ret;
5604*4882a593Smuzhiyun 
5605*4882a593Smuzhiyun }
5606*4882a593Smuzhiyun 
parse_arg_string(struct tep_print_parse ** parse,const char * format)5607*4882a593Smuzhiyun static int parse_arg_string(struct tep_print_parse **parse, const char *format)
5608*4882a593Smuzhiyun {
5609*4882a593Smuzhiyun 	struct trace_seq s;
5610*4882a593Smuzhiyun 	int ret = 0;
5611*4882a593Smuzhiyun 
5612*4882a593Smuzhiyun 	trace_seq_init(&s);
5613*4882a593Smuzhiyun 	for (; *format; format++) {
5614*4882a593Smuzhiyun 		if (*format == '\\') {
5615*4882a593Smuzhiyun 			format++;
5616*4882a593Smuzhiyun 			ret++;
5617*4882a593Smuzhiyun 			switch (*format) {
5618*4882a593Smuzhiyun 			case 'n':
5619*4882a593Smuzhiyun 				trace_seq_putc(&s, '\n');
5620*4882a593Smuzhiyun 				break;
5621*4882a593Smuzhiyun 			case 't':
5622*4882a593Smuzhiyun 				trace_seq_putc(&s, '\t');
5623*4882a593Smuzhiyun 				break;
5624*4882a593Smuzhiyun 			case 'r':
5625*4882a593Smuzhiyun 				trace_seq_putc(&s, '\r');
5626*4882a593Smuzhiyun 				break;
5627*4882a593Smuzhiyun 			case '\\':
5628*4882a593Smuzhiyun 				trace_seq_putc(&s, '\\');
5629*4882a593Smuzhiyun 				break;
5630*4882a593Smuzhiyun 			default:
5631*4882a593Smuzhiyun 				trace_seq_putc(&s, *format);
5632*4882a593Smuzhiyun 				break;
5633*4882a593Smuzhiyun 			}
5634*4882a593Smuzhiyun 		} else if (*format == '%') {
5635*4882a593Smuzhiyun 			if (*(format + 1) == '%') {
5636*4882a593Smuzhiyun 				trace_seq_putc(&s, '%');
5637*4882a593Smuzhiyun 				format++;
5638*4882a593Smuzhiyun 				ret++;
5639*4882a593Smuzhiyun 			} else
5640*4882a593Smuzhiyun 				break;
5641*4882a593Smuzhiyun 		} else
5642*4882a593Smuzhiyun 			trace_seq_putc(&s, *format);
5643*4882a593Smuzhiyun 
5644*4882a593Smuzhiyun 		ret++;
5645*4882a593Smuzhiyun 	}
5646*4882a593Smuzhiyun 	trace_seq_terminate(&s);
5647*4882a593Smuzhiyun 	parse_arg_add(parse, s.buffer, PRINT_FMT_STRING, NULL, NULL, 0);
5648*4882a593Smuzhiyun 	trace_seq_destroy(&s);
5649*4882a593Smuzhiyun 
5650*4882a593Smuzhiyun 	return ret;
5651*4882a593Smuzhiyun }
5652*4882a593Smuzhiyun 
5653*4882a593Smuzhiyun static struct tep_print_parse *
parse_args(struct tep_event * event,const char * format,struct tep_print_arg * arg)5654*4882a593Smuzhiyun parse_args(struct tep_event *event, const char *format, struct tep_print_arg *arg)
5655*4882a593Smuzhiyun {
5656*4882a593Smuzhiyun 	struct tep_print_parse *parse_ret = NULL;
5657*4882a593Smuzhiyun 	struct tep_print_parse **parse = NULL;
5658*4882a593Smuzhiyun 	int ret;
5659*4882a593Smuzhiyun 	int len;
5660*4882a593Smuzhiyun 
5661*4882a593Smuzhiyun 	len = strlen(format);
5662*4882a593Smuzhiyun 	while (*format) {
5663*4882a593Smuzhiyun 		if (!parse_ret)
5664*4882a593Smuzhiyun 			parse = &parse_ret;
5665*4882a593Smuzhiyun 		if (*format == '%' && *(format + 1) != '%')
5666*4882a593Smuzhiyun 			ret = parse_arg_format(parse, event, format, &arg);
5667*4882a593Smuzhiyun 		else
5668*4882a593Smuzhiyun 			ret = parse_arg_string(parse, format);
5669*4882a593Smuzhiyun 		if (*parse)
5670*4882a593Smuzhiyun 			parse = &((*parse)->next);
5671*4882a593Smuzhiyun 
5672*4882a593Smuzhiyun 		len -= ret;
5673*4882a593Smuzhiyun 		if (len > 0)
5674*4882a593Smuzhiyun 			format += ret;
5675*4882a593Smuzhiyun 		else
5676*4882a593Smuzhiyun 			break;
5677*4882a593Smuzhiyun 	}
5678*4882a593Smuzhiyun 	return parse_ret;
5679*4882a593Smuzhiyun }
5680*4882a593Smuzhiyun 
print_event_cache(struct tep_print_parse * parse,struct trace_seq * s,void * data,int size,struct tep_event * event)5681*4882a593Smuzhiyun static void print_event_cache(struct tep_print_parse *parse, struct trace_seq *s,
5682*4882a593Smuzhiyun 			      void *data, int size, struct tep_event *event)
5683*4882a593Smuzhiyun {
5684*4882a593Smuzhiyun 	int len_arg;
5685*4882a593Smuzhiyun 
5686*4882a593Smuzhiyun 	while (parse) {
5687*4882a593Smuzhiyun 		if (parse->len_as_arg)
5688*4882a593Smuzhiyun 			len_arg = eval_num_arg(data, size, event, parse->len_as_arg);
5689*4882a593Smuzhiyun 		switch (parse->type) {
5690*4882a593Smuzhiyun 		case PRINT_FMT_ARG_DIGIT:
5691*4882a593Smuzhiyun 			print_arg_number(s, parse->format,
5692*4882a593Smuzhiyun 					parse->len_as_arg ? len_arg : -1, data,
5693*4882a593Smuzhiyun 					 size, parse->ls, event, parse->arg);
5694*4882a593Smuzhiyun 			break;
5695*4882a593Smuzhiyun 		case PRINT_FMT_ARG_POINTER:
5696*4882a593Smuzhiyun 			print_arg_pointer(s, parse->format,
5697*4882a593Smuzhiyun 					  parse->len_as_arg ? len_arg : 1,
5698*4882a593Smuzhiyun 					  data, size, event, parse->arg);
5699*4882a593Smuzhiyun 			break;
5700*4882a593Smuzhiyun 		case PRINT_FMT_ARG_STRING:
5701*4882a593Smuzhiyun 			print_arg_string(s, parse->format,
5702*4882a593Smuzhiyun 					 parse->len_as_arg ? len_arg : -1,
5703*4882a593Smuzhiyun 					 data, size, event, parse->arg);
5704*4882a593Smuzhiyun 			break;
5705*4882a593Smuzhiyun 		case PRINT_FMT_STRING:
5706*4882a593Smuzhiyun 		default:
5707*4882a593Smuzhiyun 			trace_seq_printf(s, "%s", parse->format);
5708*4882a593Smuzhiyun 			break;
5709*4882a593Smuzhiyun 		}
5710*4882a593Smuzhiyun 		parse = parse->next;
5711*4882a593Smuzhiyun 	}
5712*4882a593Smuzhiyun }
5713*4882a593Smuzhiyun 
pretty_print(struct trace_seq * s,void * data,int size,struct tep_event * event)5714*4882a593Smuzhiyun static void pretty_print(struct trace_seq *s, void *data, int size, struct tep_event *event)
5715*4882a593Smuzhiyun {
5716*4882a593Smuzhiyun 	struct tep_print_parse *parse = event->print_fmt.print_cache;
5717*4882a593Smuzhiyun 	struct tep_print_arg *args = NULL;
5718*4882a593Smuzhiyun 	char *bprint_fmt = NULL;
5719*4882a593Smuzhiyun 
5720*4882a593Smuzhiyun 	if (event->flags & TEP_EVENT_FL_FAILED) {
5721*4882a593Smuzhiyun 		trace_seq_printf(s, "[FAILED TO PARSE]");
5722*4882a593Smuzhiyun 		tep_print_fields(s, data, size, event);
5723*4882a593Smuzhiyun 		return;
5724*4882a593Smuzhiyun 	}
5725*4882a593Smuzhiyun 
5726*4882a593Smuzhiyun 	if (event->flags & TEP_EVENT_FL_ISBPRINT) {
5727*4882a593Smuzhiyun 		bprint_fmt = get_bprint_format(data, size, event);
5728*4882a593Smuzhiyun 		args = make_bprint_args(bprint_fmt, data, size, event);
5729*4882a593Smuzhiyun 		parse = parse_args(event, bprint_fmt, args);
5730*4882a593Smuzhiyun 	}
5731*4882a593Smuzhiyun 
5732*4882a593Smuzhiyun 	print_event_cache(parse, s, data, size, event);
5733*4882a593Smuzhiyun 
5734*4882a593Smuzhiyun 	if (event->flags & TEP_EVENT_FL_ISBPRINT) {
5735*4882a593Smuzhiyun 		free_parse_args(parse);
5736*4882a593Smuzhiyun 		free_args(args);
5737*4882a593Smuzhiyun 		free(bprint_fmt);
5738*4882a593Smuzhiyun 	}
5739*4882a593Smuzhiyun }
5740*4882a593Smuzhiyun 
5741*4882a593Smuzhiyun /*
5742*4882a593Smuzhiyun  * This parses out the Latency format (interrupts disabled,
5743*4882a593Smuzhiyun  * need rescheduling, in hard/soft interrupt, preempt count
5744*4882a593Smuzhiyun  * and lock depth) and places it into the trace_seq.
5745*4882a593Smuzhiyun  */
data_latency_format(struct tep_handle * tep,struct trace_seq * s,char * format,struct tep_record * record)5746*4882a593Smuzhiyun static void data_latency_format(struct tep_handle *tep, struct trace_seq *s,
5747*4882a593Smuzhiyun 				char *format, struct tep_record *record)
5748*4882a593Smuzhiyun {
5749*4882a593Smuzhiyun 	static int check_lock_depth = 1;
5750*4882a593Smuzhiyun 	static int check_migrate_disable = 1;
5751*4882a593Smuzhiyun 	static int lock_depth_exists;
5752*4882a593Smuzhiyun 	static int migrate_disable_exists;
5753*4882a593Smuzhiyun 	unsigned int lat_flags;
5754*4882a593Smuzhiyun 	struct trace_seq sq;
5755*4882a593Smuzhiyun 	unsigned int pc;
5756*4882a593Smuzhiyun 	int lock_depth = 0;
5757*4882a593Smuzhiyun 	int migrate_disable = 0;
5758*4882a593Smuzhiyun 	int hardirq;
5759*4882a593Smuzhiyun 	int softirq;
5760*4882a593Smuzhiyun 	void *data = record->data;
5761*4882a593Smuzhiyun 
5762*4882a593Smuzhiyun 	trace_seq_init(&sq);
5763*4882a593Smuzhiyun 	lat_flags = parse_common_flags(tep, data);
5764*4882a593Smuzhiyun 	pc = parse_common_pc(tep, data);
5765*4882a593Smuzhiyun 	/* lock_depth may not always exist */
5766*4882a593Smuzhiyun 	if (lock_depth_exists)
5767*4882a593Smuzhiyun 		lock_depth = parse_common_lock_depth(tep, data);
5768*4882a593Smuzhiyun 	else if (check_lock_depth) {
5769*4882a593Smuzhiyun 		lock_depth = parse_common_lock_depth(tep, data);
5770*4882a593Smuzhiyun 		if (lock_depth < 0)
5771*4882a593Smuzhiyun 			check_lock_depth = 0;
5772*4882a593Smuzhiyun 		else
5773*4882a593Smuzhiyun 			lock_depth_exists = 1;
5774*4882a593Smuzhiyun 	}
5775*4882a593Smuzhiyun 
5776*4882a593Smuzhiyun 	/* migrate_disable may not always exist */
5777*4882a593Smuzhiyun 	if (migrate_disable_exists)
5778*4882a593Smuzhiyun 		migrate_disable = parse_common_migrate_disable(tep, data);
5779*4882a593Smuzhiyun 	else if (check_migrate_disable) {
5780*4882a593Smuzhiyun 		migrate_disable = parse_common_migrate_disable(tep, data);
5781*4882a593Smuzhiyun 		if (migrate_disable < 0)
5782*4882a593Smuzhiyun 			check_migrate_disable = 0;
5783*4882a593Smuzhiyun 		else
5784*4882a593Smuzhiyun 			migrate_disable_exists = 1;
5785*4882a593Smuzhiyun 	}
5786*4882a593Smuzhiyun 
5787*4882a593Smuzhiyun 	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
5788*4882a593Smuzhiyun 	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
5789*4882a593Smuzhiyun 
5790*4882a593Smuzhiyun 	trace_seq_printf(&sq, "%c%c%c",
5791*4882a593Smuzhiyun 	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
5792*4882a593Smuzhiyun 	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
5793*4882a593Smuzhiyun 	       'X' : '.',
5794*4882a593Smuzhiyun 	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
5795*4882a593Smuzhiyun 	       'N' : '.',
5796*4882a593Smuzhiyun 	       (hardirq && softirq) ? 'H' :
5797*4882a593Smuzhiyun 	       hardirq ? 'h' : softirq ? 's' : '.');
5798*4882a593Smuzhiyun 
5799*4882a593Smuzhiyun 	if (pc)
5800*4882a593Smuzhiyun 		trace_seq_printf(&sq, "%x", pc);
5801*4882a593Smuzhiyun 	else
5802*4882a593Smuzhiyun 		trace_seq_printf(&sq, ".");
5803*4882a593Smuzhiyun 
5804*4882a593Smuzhiyun 	if (migrate_disable_exists) {
5805*4882a593Smuzhiyun 		if (migrate_disable < 0)
5806*4882a593Smuzhiyun 			trace_seq_printf(&sq, ".");
5807*4882a593Smuzhiyun 		else
5808*4882a593Smuzhiyun 			trace_seq_printf(&sq, "%d", migrate_disable);
5809*4882a593Smuzhiyun 	}
5810*4882a593Smuzhiyun 
5811*4882a593Smuzhiyun 	if (lock_depth_exists) {
5812*4882a593Smuzhiyun 		if (lock_depth < 0)
5813*4882a593Smuzhiyun 			trace_seq_printf(&sq, ".");
5814*4882a593Smuzhiyun 		else
5815*4882a593Smuzhiyun 			trace_seq_printf(&sq, "%d", lock_depth);
5816*4882a593Smuzhiyun 	}
5817*4882a593Smuzhiyun 
5818*4882a593Smuzhiyun 	if (sq.state == TRACE_SEQ__MEM_ALLOC_FAILED) {
5819*4882a593Smuzhiyun 		s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
5820*4882a593Smuzhiyun 		return;
5821*4882a593Smuzhiyun 	}
5822*4882a593Smuzhiyun 
5823*4882a593Smuzhiyun 	trace_seq_terminate(&sq);
5824*4882a593Smuzhiyun 	trace_seq_puts(s, sq.buffer);
5825*4882a593Smuzhiyun 	trace_seq_destroy(&sq);
5826*4882a593Smuzhiyun 	trace_seq_terminate(s);
5827*4882a593Smuzhiyun }
5828*4882a593Smuzhiyun 
5829*4882a593Smuzhiyun /**
5830*4882a593Smuzhiyun  * tep_data_type - parse out the given event type
5831*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5832*4882a593Smuzhiyun  * @rec: the record to read from
5833*4882a593Smuzhiyun  *
5834*4882a593Smuzhiyun  * This returns the event id from the @rec.
5835*4882a593Smuzhiyun  */
tep_data_type(struct tep_handle * tep,struct tep_record * rec)5836*4882a593Smuzhiyun int tep_data_type(struct tep_handle *tep, struct tep_record *rec)
5837*4882a593Smuzhiyun {
5838*4882a593Smuzhiyun 	return trace_parse_common_type(tep, rec->data);
5839*4882a593Smuzhiyun }
5840*4882a593Smuzhiyun 
5841*4882a593Smuzhiyun /**
5842*4882a593Smuzhiyun  * tep_data_pid - parse the PID from record
5843*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5844*4882a593Smuzhiyun  * @rec: the record to parse
5845*4882a593Smuzhiyun  *
5846*4882a593Smuzhiyun  * This returns the PID from a record.
5847*4882a593Smuzhiyun  */
tep_data_pid(struct tep_handle * tep,struct tep_record * rec)5848*4882a593Smuzhiyun int tep_data_pid(struct tep_handle *tep, struct tep_record *rec)
5849*4882a593Smuzhiyun {
5850*4882a593Smuzhiyun 	return parse_common_pid(tep, rec->data);
5851*4882a593Smuzhiyun }
5852*4882a593Smuzhiyun 
5853*4882a593Smuzhiyun /**
5854*4882a593Smuzhiyun  * tep_data_preempt_count - parse the preempt count from the record
5855*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5856*4882a593Smuzhiyun  * @rec: the record to parse
5857*4882a593Smuzhiyun  *
5858*4882a593Smuzhiyun  * This returns the preempt count from a record.
5859*4882a593Smuzhiyun  */
tep_data_preempt_count(struct tep_handle * tep,struct tep_record * rec)5860*4882a593Smuzhiyun int tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec)
5861*4882a593Smuzhiyun {
5862*4882a593Smuzhiyun 	return parse_common_pc(tep, rec->data);
5863*4882a593Smuzhiyun }
5864*4882a593Smuzhiyun 
5865*4882a593Smuzhiyun /**
5866*4882a593Smuzhiyun  * tep_data_flags - parse the latency flags from the record
5867*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5868*4882a593Smuzhiyun  * @rec: the record to parse
5869*4882a593Smuzhiyun  *
5870*4882a593Smuzhiyun  * This returns the latency flags from a record.
5871*4882a593Smuzhiyun  *
5872*4882a593Smuzhiyun  *  Use trace_flag_type enum for the flags (see event-parse.h).
5873*4882a593Smuzhiyun  */
tep_data_flags(struct tep_handle * tep,struct tep_record * rec)5874*4882a593Smuzhiyun int tep_data_flags(struct tep_handle *tep, struct tep_record *rec)
5875*4882a593Smuzhiyun {
5876*4882a593Smuzhiyun 	return parse_common_flags(tep, rec->data);
5877*4882a593Smuzhiyun }
5878*4882a593Smuzhiyun 
5879*4882a593Smuzhiyun /**
5880*4882a593Smuzhiyun  * tep_data_comm_from_pid - return the command line from PID
5881*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5882*4882a593Smuzhiyun  * @pid: the PID of the task to search for
5883*4882a593Smuzhiyun  *
5884*4882a593Smuzhiyun  * This returns a pointer to the command line that has the given
5885*4882a593Smuzhiyun  * @pid.
5886*4882a593Smuzhiyun  */
tep_data_comm_from_pid(struct tep_handle * tep,int pid)5887*4882a593Smuzhiyun const char *tep_data_comm_from_pid(struct tep_handle *tep, int pid)
5888*4882a593Smuzhiyun {
5889*4882a593Smuzhiyun 	const char *comm;
5890*4882a593Smuzhiyun 
5891*4882a593Smuzhiyun 	comm = find_cmdline(tep, pid);
5892*4882a593Smuzhiyun 	return comm;
5893*4882a593Smuzhiyun }
5894*4882a593Smuzhiyun 
5895*4882a593Smuzhiyun static struct tep_cmdline *
pid_from_cmdlist(struct tep_handle * tep,const char * comm,struct tep_cmdline * next)5896*4882a593Smuzhiyun pid_from_cmdlist(struct tep_handle *tep, const char *comm, struct tep_cmdline *next)
5897*4882a593Smuzhiyun {
5898*4882a593Smuzhiyun 	struct cmdline_list *cmdlist = (struct cmdline_list *)next;
5899*4882a593Smuzhiyun 
5900*4882a593Smuzhiyun 	if (cmdlist)
5901*4882a593Smuzhiyun 		cmdlist = cmdlist->next;
5902*4882a593Smuzhiyun 	else
5903*4882a593Smuzhiyun 		cmdlist = tep->cmdlist;
5904*4882a593Smuzhiyun 
5905*4882a593Smuzhiyun 	while (cmdlist && strcmp(cmdlist->comm, comm) != 0)
5906*4882a593Smuzhiyun 		cmdlist = cmdlist->next;
5907*4882a593Smuzhiyun 
5908*4882a593Smuzhiyun 	return (struct tep_cmdline *)cmdlist;
5909*4882a593Smuzhiyun }
5910*4882a593Smuzhiyun 
5911*4882a593Smuzhiyun /**
5912*4882a593Smuzhiyun  * tep_data_pid_from_comm - return the pid from a given comm
5913*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5914*4882a593Smuzhiyun  * @comm: the cmdline to find the pid from
5915*4882a593Smuzhiyun  * @next: the cmdline structure to find the next comm
5916*4882a593Smuzhiyun  *
5917*4882a593Smuzhiyun  * This returns the cmdline structure that holds a pid for a given
5918*4882a593Smuzhiyun  * comm, or NULL if none found. As there may be more than one pid for
5919*4882a593Smuzhiyun  * a given comm, the result of this call can be passed back into
5920*4882a593Smuzhiyun  * a recurring call in the @next parameter, and then it will find the
5921*4882a593Smuzhiyun  * next pid.
5922*4882a593Smuzhiyun  * Also, it does a linear search, so it may be slow.
5923*4882a593Smuzhiyun  */
tep_data_pid_from_comm(struct tep_handle * tep,const char * comm,struct tep_cmdline * next)5924*4882a593Smuzhiyun struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *tep, const char *comm,
5925*4882a593Smuzhiyun 					   struct tep_cmdline *next)
5926*4882a593Smuzhiyun {
5927*4882a593Smuzhiyun 	struct tep_cmdline *cmdline;
5928*4882a593Smuzhiyun 
5929*4882a593Smuzhiyun 	/*
5930*4882a593Smuzhiyun 	 * If the cmdlines have not been converted yet, then use
5931*4882a593Smuzhiyun 	 * the list.
5932*4882a593Smuzhiyun 	 */
5933*4882a593Smuzhiyun 	if (!tep->cmdlines)
5934*4882a593Smuzhiyun 		return pid_from_cmdlist(tep, comm, next);
5935*4882a593Smuzhiyun 
5936*4882a593Smuzhiyun 	if (next) {
5937*4882a593Smuzhiyun 		/*
5938*4882a593Smuzhiyun 		 * The next pointer could have been still from
5939*4882a593Smuzhiyun 		 * a previous call before cmdlines were created
5940*4882a593Smuzhiyun 		 */
5941*4882a593Smuzhiyun 		if (next < tep->cmdlines ||
5942*4882a593Smuzhiyun 		    next >= tep->cmdlines + tep->cmdline_count)
5943*4882a593Smuzhiyun 			next = NULL;
5944*4882a593Smuzhiyun 		else
5945*4882a593Smuzhiyun 			cmdline  = next++;
5946*4882a593Smuzhiyun 	}
5947*4882a593Smuzhiyun 
5948*4882a593Smuzhiyun 	if (!next)
5949*4882a593Smuzhiyun 		cmdline = tep->cmdlines;
5950*4882a593Smuzhiyun 
5951*4882a593Smuzhiyun 	while (cmdline < tep->cmdlines + tep->cmdline_count) {
5952*4882a593Smuzhiyun 		if (strcmp(cmdline->comm, comm) == 0)
5953*4882a593Smuzhiyun 			return cmdline;
5954*4882a593Smuzhiyun 		cmdline++;
5955*4882a593Smuzhiyun 	}
5956*4882a593Smuzhiyun 	return NULL;
5957*4882a593Smuzhiyun }
5958*4882a593Smuzhiyun 
5959*4882a593Smuzhiyun /**
5960*4882a593Smuzhiyun  * tep_cmdline_pid - return the pid associated to a given cmdline
5961*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
5962*4882a593Smuzhiyun  * @cmdline: The cmdline structure to get the pid from
5963*4882a593Smuzhiyun  *
5964*4882a593Smuzhiyun  * Returns the pid for a give cmdline. If @cmdline is NULL, then
5965*4882a593Smuzhiyun  * -1 is returned.
5966*4882a593Smuzhiyun  */
tep_cmdline_pid(struct tep_handle * tep,struct tep_cmdline * cmdline)5967*4882a593Smuzhiyun int tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline)
5968*4882a593Smuzhiyun {
5969*4882a593Smuzhiyun 	struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline;
5970*4882a593Smuzhiyun 
5971*4882a593Smuzhiyun 	if (!cmdline)
5972*4882a593Smuzhiyun 		return -1;
5973*4882a593Smuzhiyun 
5974*4882a593Smuzhiyun 	/*
5975*4882a593Smuzhiyun 	 * If cmdlines have not been created yet, or cmdline is
5976*4882a593Smuzhiyun 	 * not part of the array, then treat it as a cmdlist instead.
5977*4882a593Smuzhiyun 	 */
5978*4882a593Smuzhiyun 	if (!tep->cmdlines ||
5979*4882a593Smuzhiyun 	    cmdline < tep->cmdlines ||
5980*4882a593Smuzhiyun 	    cmdline >= tep->cmdlines + tep->cmdline_count)
5981*4882a593Smuzhiyun 		return cmdlist->pid;
5982*4882a593Smuzhiyun 
5983*4882a593Smuzhiyun 	return cmdline->pid;
5984*4882a593Smuzhiyun }
5985*4882a593Smuzhiyun 
5986*4882a593Smuzhiyun /*
5987*4882a593Smuzhiyun  * This parses the raw @data using the given @event information and
5988*4882a593Smuzhiyun  * writes the print format into the trace_seq.
5989*4882a593Smuzhiyun  */
print_event_info(struct trace_seq * s,char * format,bool raw,struct tep_event * event,struct tep_record * record)5990*4882a593Smuzhiyun static void print_event_info(struct trace_seq *s, char *format, bool raw,
5991*4882a593Smuzhiyun 			     struct tep_event *event, struct tep_record *record)
5992*4882a593Smuzhiyun {
5993*4882a593Smuzhiyun 	int print_pretty = 1;
5994*4882a593Smuzhiyun 
5995*4882a593Smuzhiyun 	if (raw || (event->flags & TEP_EVENT_FL_PRINTRAW))
5996*4882a593Smuzhiyun 		tep_print_fields(s, record->data, record->size, event);
5997*4882a593Smuzhiyun 	else {
5998*4882a593Smuzhiyun 
5999*4882a593Smuzhiyun 		if (event->handler && !(event->flags & TEP_EVENT_FL_NOHANDLE))
6000*4882a593Smuzhiyun 			print_pretty = event->handler(s, record, event,
6001*4882a593Smuzhiyun 						      event->context);
6002*4882a593Smuzhiyun 
6003*4882a593Smuzhiyun 		if (print_pretty)
6004*4882a593Smuzhiyun 			pretty_print(s, record->data, record->size, event);
6005*4882a593Smuzhiyun 	}
6006*4882a593Smuzhiyun 
6007*4882a593Smuzhiyun 	trace_seq_terminate(s);
6008*4882a593Smuzhiyun }
6009*4882a593Smuzhiyun 
6010*4882a593Smuzhiyun /**
6011*4882a593Smuzhiyun  * tep_find_event_by_record - return the event from a given record
6012*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
6013*4882a593Smuzhiyun  * @record: The record to get the event from
6014*4882a593Smuzhiyun  *
6015*4882a593Smuzhiyun  * Returns the associated event for a given record, or NULL if non is
6016*4882a593Smuzhiyun  * is found.
6017*4882a593Smuzhiyun  */
6018*4882a593Smuzhiyun struct tep_event *
tep_find_event_by_record(struct tep_handle * tep,struct tep_record * record)6019*4882a593Smuzhiyun tep_find_event_by_record(struct tep_handle *tep, struct tep_record *record)
6020*4882a593Smuzhiyun {
6021*4882a593Smuzhiyun 	int type;
6022*4882a593Smuzhiyun 
6023*4882a593Smuzhiyun 	if (record->size < 0) {
6024*4882a593Smuzhiyun 		do_warning("ug! negative record size %d", record->size);
6025*4882a593Smuzhiyun 		return NULL;
6026*4882a593Smuzhiyun 	}
6027*4882a593Smuzhiyun 
6028*4882a593Smuzhiyun 	type = trace_parse_common_type(tep, record->data);
6029*4882a593Smuzhiyun 
6030*4882a593Smuzhiyun 	return tep_find_event(tep, type);
6031*4882a593Smuzhiyun }
6032*4882a593Smuzhiyun 
6033*4882a593Smuzhiyun /*
6034*4882a593Smuzhiyun  * Writes the timestamp of the record into @s. Time divisor and precision can be
6035*4882a593Smuzhiyun  * specified as part of printf @format string. Example:
6036*4882a593Smuzhiyun  *	"%3.1000d" - divide the time by 1000 and print the first 3 digits
6037*4882a593Smuzhiyun  *	before the dot. Thus, the timestamp "123456000" will be printed as
6038*4882a593Smuzhiyun  *	"123.456"
6039*4882a593Smuzhiyun  */
print_event_time(struct tep_handle * tep,struct trace_seq * s,char * format,struct tep_event * event,struct tep_record * record)6040*4882a593Smuzhiyun static void print_event_time(struct tep_handle *tep, struct trace_seq *s,
6041*4882a593Smuzhiyun 				 char *format, struct tep_event *event,
6042*4882a593Smuzhiyun 				 struct tep_record *record)
6043*4882a593Smuzhiyun {
6044*4882a593Smuzhiyun 	unsigned long long time;
6045*4882a593Smuzhiyun 	char *divstr;
6046*4882a593Smuzhiyun 	int prec = 0, pr;
6047*4882a593Smuzhiyun 	int div = 0;
6048*4882a593Smuzhiyun 	int p10 = 1;
6049*4882a593Smuzhiyun 
6050*4882a593Smuzhiyun 	if (isdigit(*(format + 1)))
6051*4882a593Smuzhiyun 		prec = atoi(format + 1);
6052*4882a593Smuzhiyun 	divstr = strchr(format, '.');
6053*4882a593Smuzhiyun 	if (divstr && isdigit(*(divstr + 1)))
6054*4882a593Smuzhiyun 		div = atoi(divstr + 1);
6055*4882a593Smuzhiyun 	time = record->ts;
6056*4882a593Smuzhiyun 	if (div) {
6057*4882a593Smuzhiyun 		time += div / 2;
6058*4882a593Smuzhiyun 		time /= div;
6059*4882a593Smuzhiyun 	}
6060*4882a593Smuzhiyun 	pr = prec;
6061*4882a593Smuzhiyun 	while (pr--)
6062*4882a593Smuzhiyun 		p10 *= 10;
6063*4882a593Smuzhiyun 
6064*4882a593Smuzhiyun 	if (p10 > 1 && p10 < time)
6065*4882a593Smuzhiyun 		trace_seq_printf(s, "%5llu.%0*llu", time / p10, prec, time % p10);
6066*4882a593Smuzhiyun 	else
6067*4882a593Smuzhiyun 		trace_seq_printf(s, "%12llu", time);
6068*4882a593Smuzhiyun }
6069*4882a593Smuzhiyun 
6070*4882a593Smuzhiyun struct print_event_type {
6071*4882a593Smuzhiyun 	enum {
6072*4882a593Smuzhiyun 		EVENT_TYPE_INT = 1,
6073*4882a593Smuzhiyun 		EVENT_TYPE_STRING,
6074*4882a593Smuzhiyun 		EVENT_TYPE_UNKNOWN,
6075*4882a593Smuzhiyun 	} type;
6076*4882a593Smuzhiyun 	char format[32];
6077*4882a593Smuzhiyun };
6078*4882a593Smuzhiyun 
print_string(struct tep_handle * tep,struct trace_seq * s,struct tep_record * record,struct tep_event * event,const char * arg,struct print_event_type * type)6079*4882a593Smuzhiyun static void print_string(struct tep_handle *tep, struct trace_seq *s,
6080*4882a593Smuzhiyun 			 struct tep_record *record, struct tep_event *event,
6081*4882a593Smuzhiyun 			 const char *arg, struct print_event_type *type)
6082*4882a593Smuzhiyun {
6083*4882a593Smuzhiyun 	const char *comm;
6084*4882a593Smuzhiyun 	int pid;
6085*4882a593Smuzhiyun 
6086*4882a593Smuzhiyun 	if (strncmp(arg, TEP_PRINT_LATENCY, strlen(TEP_PRINT_LATENCY)) == 0) {
6087*4882a593Smuzhiyun 		data_latency_format(tep, s, type->format, record);
6088*4882a593Smuzhiyun 	} else if (strncmp(arg, TEP_PRINT_COMM, strlen(TEP_PRINT_COMM)) == 0) {
6089*4882a593Smuzhiyun 		pid = parse_common_pid(tep, record->data);
6090*4882a593Smuzhiyun 		comm = find_cmdline(tep, pid);
6091*4882a593Smuzhiyun 		trace_seq_printf(s, type->format, comm);
6092*4882a593Smuzhiyun 	} else if (strncmp(arg, TEP_PRINT_INFO_RAW, strlen(TEP_PRINT_INFO_RAW)) == 0) {
6093*4882a593Smuzhiyun 		print_event_info(s, type->format, true, event, record);
6094*4882a593Smuzhiyun 	} else if (strncmp(arg, TEP_PRINT_INFO, strlen(TEP_PRINT_INFO)) == 0) {
6095*4882a593Smuzhiyun 		print_event_info(s, type->format, false, event, record);
6096*4882a593Smuzhiyun 	} else if  (strncmp(arg, TEP_PRINT_NAME, strlen(TEP_PRINT_NAME)) == 0) {
6097*4882a593Smuzhiyun 		trace_seq_printf(s, type->format, event->name);
6098*4882a593Smuzhiyun 	} else {
6099*4882a593Smuzhiyun 		trace_seq_printf(s, "[UNKNOWN TEP TYPE %s]", arg);
6100*4882a593Smuzhiyun 	}
6101*4882a593Smuzhiyun 
6102*4882a593Smuzhiyun }
6103*4882a593Smuzhiyun 
print_int(struct tep_handle * tep,struct trace_seq * s,struct tep_record * record,struct tep_event * event,int arg,struct print_event_type * type)6104*4882a593Smuzhiyun static void print_int(struct tep_handle *tep, struct trace_seq *s,
6105*4882a593Smuzhiyun 		      struct tep_record *record, struct tep_event *event,
6106*4882a593Smuzhiyun 		      int arg, struct print_event_type *type)
6107*4882a593Smuzhiyun {
6108*4882a593Smuzhiyun 	int param;
6109*4882a593Smuzhiyun 
6110*4882a593Smuzhiyun 	switch (arg) {
6111*4882a593Smuzhiyun 	case TEP_PRINT_CPU:
6112*4882a593Smuzhiyun 		param = record->cpu;
6113*4882a593Smuzhiyun 		break;
6114*4882a593Smuzhiyun 	case TEP_PRINT_PID:
6115*4882a593Smuzhiyun 		param = parse_common_pid(tep, record->data);
6116*4882a593Smuzhiyun 		break;
6117*4882a593Smuzhiyun 	case TEP_PRINT_TIME:
6118*4882a593Smuzhiyun 		return print_event_time(tep, s, type->format, event, record);
6119*4882a593Smuzhiyun 	default:
6120*4882a593Smuzhiyun 		return;
6121*4882a593Smuzhiyun 	}
6122*4882a593Smuzhiyun 	trace_seq_printf(s, type->format, param);
6123*4882a593Smuzhiyun }
6124*4882a593Smuzhiyun 
tep_print_event_param_type(char * format,struct print_event_type * type)6125*4882a593Smuzhiyun static int tep_print_event_param_type(char *format,
6126*4882a593Smuzhiyun 				      struct print_event_type *type)
6127*4882a593Smuzhiyun {
6128*4882a593Smuzhiyun 	char *str = format + 1;
6129*4882a593Smuzhiyun 	int i = 1;
6130*4882a593Smuzhiyun 
6131*4882a593Smuzhiyun 	type->type = EVENT_TYPE_UNKNOWN;
6132*4882a593Smuzhiyun 	while (*str) {
6133*4882a593Smuzhiyun 		switch (*str) {
6134*4882a593Smuzhiyun 		case 'd':
6135*4882a593Smuzhiyun 		case 'u':
6136*4882a593Smuzhiyun 		case 'i':
6137*4882a593Smuzhiyun 		case 'x':
6138*4882a593Smuzhiyun 		case 'X':
6139*4882a593Smuzhiyun 		case 'o':
6140*4882a593Smuzhiyun 			type->type = EVENT_TYPE_INT;
6141*4882a593Smuzhiyun 			break;
6142*4882a593Smuzhiyun 		case 's':
6143*4882a593Smuzhiyun 			type->type = EVENT_TYPE_STRING;
6144*4882a593Smuzhiyun 			break;
6145*4882a593Smuzhiyun 		}
6146*4882a593Smuzhiyun 		str++;
6147*4882a593Smuzhiyun 		i++;
6148*4882a593Smuzhiyun 		if (type->type != EVENT_TYPE_UNKNOWN)
6149*4882a593Smuzhiyun 			break;
6150*4882a593Smuzhiyun 	}
6151*4882a593Smuzhiyun 	memset(type->format, 0, 32);
6152*4882a593Smuzhiyun 	memcpy(type->format, format, i < 32 ? i : 31);
6153*4882a593Smuzhiyun 	return i;
6154*4882a593Smuzhiyun }
6155*4882a593Smuzhiyun 
6156*4882a593Smuzhiyun /**
6157*4882a593Smuzhiyun  * tep_print_event - Write various event information
6158*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
6159*4882a593Smuzhiyun  * @s: the trace_seq to write to
6160*4882a593Smuzhiyun  * @record: The record to get the event from
6161*4882a593Smuzhiyun  * @format: a printf format string. Supported event fileds:
6162*4882a593Smuzhiyun  *	TEP_PRINT_PID, "%d" - event PID
6163*4882a593Smuzhiyun  *	TEP_PRINT_CPU, "%d" - event CPU
6164*4882a593Smuzhiyun  *	TEP_PRINT_COMM, "%s" - event command string
6165*4882a593Smuzhiyun  *	TEP_PRINT_NAME, "%s" - event name
6166*4882a593Smuzhiyun  *	TEP_PRINT_LATENCY, "%s" - event latency
6167*4882a593Smuzhiyun  *	TEP_PRINT_TIME, %d - event time stamp. A divisor and precision
6168*4882a593Smuzhiyun  *			can be specified as part of this format string:
6169*4882a593Smuzhiyun  *			"%precision.divisord". Example:
6170*4882a593Smuzhiyun  *			"%3.1000d" - divide the time by 1000 and print the first
6171*4882a593Smuzhiyun  *			3 digits before the dot. Thus, the time stamp
6172*4882a593Smuzhiyun  *			"123456000" will be printed as "123.456"
6173*4882a593Smuzhiyun  *	TEP_PRINT_INFO, "%s" - event information. If any width is specified in
6174*4882a593Smuzhiyun  *			the format string, the event information will be printed
6175*4882a593Smuzhiyun  *			in raw format.
6176*4882a593Smuzhiyun  * Writes the specified event information into @s.
6177*4882a593Smuzhiyun  */
tep_print_event(struct tep_handle * tep,struct trace_seq * s,struct tep_record * record,const char * fmt,...)6178*4882a593Smuzhiyun void tep_print_event(struct tep_handle *tep, struct trace_seq *s,
6179*4882a593Smuzhiyun 		     struct tep_record *record, const char *fmt, ...)
6180*4882a593Smuzhiyun {
6181*4882a593Smuzhiyun 	struct print_event_type type;
6182*4882a593Smuzhiyun 	char *format = strdup(fmt);
6183*4882a593Smuzhiyun 	char *current = format;
6184*4882a593Smuzhiyun 	char *str = format;
6185*4882a593Smuzhiyun 	int offset;
6186*4882a593Smuzhiyun 	va_list args;
6187*4882a593Smuzhiyun 	struct tep_event *event;
6188*4882a593Smuzhiyun 
6189*4882a593Smuzhiyun 	if (!format)
6190*4882a593Smuzhiyun 		return;
6191*4882a593Smuzhiyun 
6192*4882a593Smuzhiyun 	event = tep_find_event_by_record(tep, record);
6193*4882a593Smuzhiyun 	va_start(args, fmt);
6194*4882a593Smuzhiyun 	while (*current) {
6195*4882a593Smuzhiyun 		current = strchr(str, '%');
6196*4882a593Smuzhiyun 		if (!current) {
6197*4882a593Smuzhiyun 			trace_seq_puts(s, str);
6198*4882a593Smuzhiyun 			break;
6199*4882a593Smuzhiyun 		}
6200*4882a593Smuzhiyun 		memset(&type, 0, sizeof(type));
6201*4882a593Smuzhiyun 		offset = tep_print_event_param_type(current, &type);
6202*4882a593Smuzhiyun 		*current = '\0';
6203*4882a593Smuzhiyun 		trace_seq_puts(s, str);
6204*4882a593Smuzhiyun 		current += offset;
6205*4882a593Smuzhiyun 		switch (type.type) {
6206*4882a593Smuzhiyun 		case EVENT_TYPE_STRING:
6207*4882a593Smuzhiyun 			print_string(tep, s, record, event,
6208*4882a593Smuzhiyun 				     va_arg(args, char*), &type);
6209*4882a593Smuzhiyun 			break;
6210*4882a593Smuzhiyun 		case EVENT_TYPE_INT:
6211*4882a593Smuzhiyun 			print_int(tep, s, record, event,
6212*4882a593Smuzhiyun 				  va_arg(args, int), &type);
6213*4882a593Smuzhiyun 			break;
6214*4882a593Smuzhiyun 		case EVENT_TYPE_UNKNOWN:
6215*4882a593Smuzhiyun 		default:
6216*4882a593Smuzhiyun 			trace_seq_printf(s, "[UNKNOWN TYPE]");
6217*4882a593Smuzhiyun 			break;
6218*4882a593Smuzhiyun 		}
6219*4882a593Smuzhiyun 		str = current;
6220*4882a593Smuzhiyun 
6221*4882a593Smuzhiyun 	}
6222*4882a593Smuzhiyun 	va_end(args);
6223*4882a593Smuzhiyun 	free(format);
6224*4882a593Smuzhiyun }
6225*4882a593Smuzhiyun 
events_id_cmp(const void * a,const void * b)6226*4882a593Smuzhiyun static int events_id_cmp(const void *a, const void *b)
6227*4882a593Smuzhiyun {
6228*4882a593Smuzhiyun 	struct tep_event * const * ea = a;
6229*4882a593Smuzhiyun 	struct tep_event * const * eb = b;
6230*4882a593Smuzhiyun 
6231*4882a593Smuzhiyun 	if ((*ea)->id < (*eb)->id)
6232*4882a593Smuzhiyun 		return -1;
6233*4882a593Smuzhiyun 
6234*4882a593Smuzhiyun 	if ((*ea)->id > (*eb)->id)
6235*4882a593Smuzhiyun 		return 1;
6236*4882a593Smuzhiyun 
6237*4882a593Smuzhiyun 	return 0;
6238*4882a593Smuzhiyun }
6239*4882a593Smuzhiyun 
events_name_cmp(const void * a,const void * b)6240*4882a593Smuzhiyun static int events_name_cmp(const void *a, const void *b)
6241*4882a593Smuzhiyun {
6242*4882a593Smuzhiyun 	struct tep_event * const * ea = a;
6243*4882a593Smuzhiyun 	struct tep_event * const * eb = b;
6244*4882a593Smuzhiyun 	int res;
6245*4882a593Smuzhiyun 
6246*4882a593Smuzhiyun 	res = strcmp((*ea)->name, (*eb)->name);
6247*4882a593Smuzhiyun 	if (res)
6248*4882a593Smuzhiyun 		return res;
6249*4882a593Smuzhiyun 
6250*4882a593Smuzhiyun 	res = strcmp((*ea)->system, (*eb)->system);
6251*4882a593Smuzhiyun 	if (res)
6252*4882a593Smuzhiyun 		return res;
6253*4882a593Smuzhiyun 
6254*4882a593Smuzhiyun 	return events_id_cmp(a, b);
6255*4882a593Smuzhiyun }
6256*4882a593Smuzhiyun 
events_system_cmp(const void * a,const void * b)6257*4882a593Smuzhiyun static int events_system_cmp(const void *a, const void *b)
6258*4882a593Smuzhiyun {
6259*4882a593Smuzhiyun 	struct tep_event * const * ea = a;
6260*4882a593Smuzhiyun 	struct tep_event * const * eb = b;
6261*4882a593Smuzhiyun 	int res;
6262*4882a593Smuzhiyun 
6263*4882a593Smuzhiyun 	res = strcmp((*ea)->system, (*eb)->system);
6264*4882a593Smuzhiyun 	if (res)
6265*4882a593Smuzhiyun 		return res;
6266*4882a593Smuzhiyun 
6267*4882a593Smuzhiyun 	res = strcmp((*ea)->name, (*eb)->name);
6268*4882a593Smuzhiyun 	if (res)
6269*4882a593Smuzhiyun 		return res;
6270*4882a593Smuzhiyun 
6271*4882a593Smuzhiyun 	return events_id_cmp(a, b);
6272*4882a593Smuzhiyun }
6273*4882a593Smuzhiyun 
list_events_copy(struct tep_handle * tep)6274*4882a593Smuzhiyun static struct tep_event **list_events_copy(struct tep_handle *tep)
6275*4882a593Smuzhiyun {
6276*4882a593Smuzhiyun 	struct tep_event **events;
6277*4882a593Smuzhiyun 
6278*4882a593Smuzhiyun 	if (!tep)
6279*4882a593Smuzhiyun 		return NULL;
6280*4882a593Smuzhiyun 
6281*4882a593Smuzhiyun 	events = malloc(sizeof(*events) * (tep->nr_events + 1));
6282*4882a593Smuzhiyun 	if (!events)
6283*4882a593Smuzhiyun 		return NULL;
6284*4882a593Smuzhiyun 
6285*4882a593Smuzhiyun 	memcpy(events, tep->events, sizeof(*events) * tep->nr_events);
6286*4882a593Smuzhiyun 	events[tep->nr_events] = NULL;
6287*4882a593Smuzhiyun 	return events;
6288*4882a593Smuzhiyun }
6289*4882a593Smuzhiyun 
list_events_sort(struct tep_event ** events,int nr_events,enum tep_event_sort_type sort_type)6290*4882a593Smuzhiyun static void list_events_sort(struct tep_event **events, int nr_events,
6291*4882a593Smuzhiyun 			     enum tep_event_sort_type sort_type)
6292*4882a593Smuzhiyun {
6293*4882a593Smuzhiyun 	int (*sort)(const void *a, const void *b);
6294*4882a593Smuzhiyun 
6295*4882a593Smuzhiyun 	switch (sort_type) {
6296*4882a593Smuzhiyun 	case TEP_EVENT_SORT_ID:
6297*4882a593Smuzhiyun 		sort = events_id_cmp;
6298*4882a593Smuzhiyun 		break;
6299*4882a593Smuzhiyun 	case TEP_EVENT_SORT_NAME:
6300*4882a593Smuzhiyun 		sort = events_name_cmp;
6301*4882a593Smuzhiyun 		break;
6302*4882a593Smuzhiyun 	case TEP_EVENT_SORT_SYSTEM:
6303*4882a593Smuzhiyun 		sort = events_system_cmp;
6304*4882a593Smuzhiyun 		break;
6305*4882a593Smuzhiyun 	default:
6306*4882a593Smuzhiyun 		sort = NULL;
6307*4882a593Smuzhiyun 	}
6308*4882a593Smuzhiyun 
6309*4882a593Smuzhiyun 	if (sort)
6310*4882a593Smuzhiyun 		qsort(events, nr_events, sizeof(*events), sort);
6311*4882a593Smuzhiyun }
6312*4882a593Smuzhiyun 
6313*4882a593Smuzhiyun /**
6314*4882a593Smuzhiyun  * tep_list_events - Get events, sorted by given criteria.
6315*4882a593Smuzhiyun  * @tep: a handle to the tep context
6316*4882a593Smuzhiyun  * @sort_type: desired sort order of the events in the array
6317*4882a593Smuzhiyun  *
6318*4882a593Smuzhiyun  * Returns an array of pointers to all events, sorted by the given
6319*4882a593Smuzhiyun  * @sort_type criteria. The last element of the array is NULL. The returned
6320*4882a593Smuzhiyun  * memory must not be freed, it is managed by the library.
6321*4882a593Smuzhiyun  * The function is not thread safe.
6322*4882a593Smuzhiyun  */
tep_list_events(struct tep_handle * tep,enum tep_event_sort_type sort_type)6323*4882a593Smuzhiyun struct tep_event **tep_list_events(struct tep_handle *tep,
6324*4882a593Smuzhiyun 				   enum tep_event_sort_type sort_type)
6325*4882a593Smuzhiyun {
6326*4882a593Smuzhiyun 	struct tep_event **events;
6327*4882a593Smuzhiyun 
6328*4882a593Smuzhiyun 	if (!tep)
6329*4882a593Smuzhiyun 		return NULL;
6330*4882a593Smuzhiyun 
6331*4882a593Smuzhiyun 	events = tep->sort_events;
6332*4882a593Smuzhiyun 	if (events && tep->last_type == sort_type)
6333*4882a593Smuzhiyun 		return events;
6334*4882a593Smuzhiyun 
6335*4882a593Smuzhiyun 	if (!events) {
6336*4882a593Smuzhiyun 		events = list_events_copy(tep);
6337*4882a593Smuzhiyun 		if (!events)
6338*4882a593Smuzhiyun 			return NULL;
6339*4882a593Smuzhiyun 
6340*4882a593Smuzhiyun 		tep->sort_events = events;
6341*4882a593Smuzhiyun 
6342*4882a593Smuzhiyun 		/* the internal events are sorted by id */
6343*4882a593Smuzhiyun 		if (sort_type == TEP_EVENT_SORT_ID) {
6344*4882a593Smuzhiyun 			tep->last_type = sort_type;
6345*4882a593Smuzhiyun 			return events;
6346*4882a593Smuzhiyun 		}
6347*4882a593Smuzhiyun 	}
6348*4882a593Smuzhiyun 
6349*4882a593Smuzhiyun 	list_events_sort(events, tep->nr_events, sort_type);
6350*4882a593Smuzhiyun 	tep->last_type = sort_type;
6351*4882a593Smuzhiyun 
6352*4882a593Smuzhiyun 	return events;
6353*4882a593Smuzhiyun }
6354*4882a593Smuzhiyun 
6355*4882a593Smuzhiyun 
6356*4882a593Smuzhiyun /**
6357*4882a593Smuzhiyun  * tep_list_events_copy - Thread safe version of tep_list_events()
6358*4882a593Smuzhiyun  * @tep: a handle to the tep context
6359*4882a593Smuzhiyun  * @sort_type: desired sort order of the events in the array
6360*4882a593Smuzhiyun  *
6361*4882a593Smuzhiyun  * Returns an array of pointers to all events, sorted by the given
6362*4882a593Smuzhiyun  * @sort_type criteria. The last element of the array is NULL. The returned
6363*4882a593Smuzhiyun  * array is newly allocated inside the function and must be freed by the caller
6364*4882a593Smuzhiyun  */
tep_list_events_copy(struct tep_handle * tep,enum tep_event_sort_type sort_type)6365*4882a593Smuzhiyun struct tep_event **tep_list_events_copy(struct tep_handle *tep,
6366*4882a593Smuzhiyun 					enum tep_event_sort_type sort_type)
6367*4882a593Smuzhiyun {
6368*4882a593Smuzhiyun 	struct tep_event **events;
6369*4882a593Smuzhiyun 
6370*4882a593Smuzhiyun 	if (!tep)
6371*4882a593Smuzhiyun 		return NULL;
6372*4882a593Smuzhiyun 
6373*4882a593Smuzhiyun 	events = list_events_copy(tep);
6374*4882a593Smuzhiyun 	if (!events)
6375*4882a593Smuzhiyun 		return NULL;
6376*4882a593Smuzhiyun 
6377*4882a593Smuzhiyun 	/* the internal events are sorted by id */
6378*4882a593Smuzhiyun 	if (sort_type == TEP_EVENT_SORT_ID)
6379*4882a593Smuzhiyun 		return events;
6380*4882a593Smuzhiyun 
6381*4882a593Smuzhiyun 	list_events_sort(events, tep->nr_events, sort_type);
6382*4882a593Smuzhiyun 
6383*4882a593Smuzhiyun 	return events;
6384*4882a593Smuzhiyun }
6385*4882a593Smuzhiyun 
6386*4882a593Smuzhiyun static struct tep_format_field **
get_event_fields(const char * type,const char * name,int count,struct tep_format_field * list)6387*4882a593Smuzhiyun get_event_fields(const char *type, const char *name,
6388*4882a593Smuzhiyun 		 int count, struct tep_format_field *list)
6389*4882a593Smuzhiyun {
6390*4882a593Smuzhiyun 	struct tep_format_field **fields;
6391*4882a593Smuzhiyun 	struct tep_format_field *field;
6392*4882a593Smuzhiyun 	int i = 0;
6393*4882a593Smuzhiyun 
6394*4882a593Smuzhiyun 	fields = malloc(sizeof(*fields) * (count + 1));
6395*4882a593Smuzhiyun 	if (!fields)
6396*4882a593Smuzhiyun 		return NULL;
6397*4882a593Smuzhiyun 
6398*4882a593Smuzhiyun 	for (field = list; field; field = field->next) {
6399*4882a593Smuzhiyun 		fields[i++] = field;
6400*4882a593Smuzhiyun 		if (i == count + 1) {
6401*4882a593Smuzhiyun 			do_warning("event %s has more %s fields than specified",
6402*4882a593Smuzhiyun 				name, type);
6403*4882a593Smuzhiyun 			i--;
6404*4882a593Smuzhiyun 			break;
6405*4882a593Smuzhiyun 		}
6406*4882a593Smuzhiyun 	}
6407*4882a593Smuzhiyun 
6408*4882a593Smuzhiyun 	if (i != count)
6409*4882a593Smuzhiyun 		do_warning("event %s has less %s fields than specified",
6410*4882a593Smuzhiyun 			name, type);
6411*4882a593Smuzhiyun 
6412*4882a593Smuzhiyun 	fields[i] = NULL;
6413*4882a593Smuzhiyun 
6414*4882a593Smuzhiyun 	return fields;
6415*4882a593Smuzhiyun }
6416*4882a593Smuzhiyun 
6417*4882a593Smuzhiyun /**
6418*4882a593Smuzhiyun  * tep_event_common_fields - return a list of common fields for an event
6419*4882a593Smuzhiyun  * @event: the event to return the common fields of.
6420*4882a593Smuzhiyun  *
6421*4882a593Smuzhiyun  * Returns an allocated array of fields. The last item in the array is NULL.
6422*4882a593Smuzhiyun  * The array must be freed with free().
6423*4882a593Smuzhiyun  */
tep_event_common_fields(struct tep_event * event)6424*4882a593Smuzhiyun struct tep_format_field **tep_event_common_fields(struct tep_event *event)
6425*4882a593Smuzhiyun {
6426*4882a593Smuzhiyun 	return get_event_fields("common", event->name,
6427*4882a593Smuzhiyun 				event->format.nr_common,
6428*4882a593Smuzhiyun 				event->format.common_fields);
6429*4882a593Smuzhiyun }
6430*4882a593Smuzhiyun 
6431*4882a593Smuzhiyun /**
6432*4882a593Smuzhiyun  * tep_event_fields - return a list of event specific fields for an event
6433*4882a593Smuzhiyun  * @event: the event to return the fields of.
6434*4882a593Smuzhiyun  *
6435*4882a593Smuzhiyun  * Returns an allocated array of fields. The last item in the array is NULL.
6436*4882a593Smuzhiyun  * The array must be freed with free().
6437*4882a593Smuzhiyun  */
tep_event_fields(struct tep_event * event)6438*4882a593Smuzhiyun struct tep_format_field **tep_event_fields(struct tep_event *event)
6439*4882a593Smuzhiyun {
6440*4882a593Smuzhiyun 	return get_event_fields("event", event->name,
6441*4882a593Smuzhiyun 				event->format.nr_fields,
6442*4882a593Smuzhiyun 				event->format.fields);
6443*4882a593Smuzhiyun }
6444*4882a593Smuzhiyun 
print_fields(struct trace_seq * s,struct tep_print_flag_sym * field)6445*4882a593Smuzhiyun static void print_fields(struct trace_seq *s, struct tep_print_flag_sym *field)
6446*4882a593Smuzhiyun {
6447*4882a593Smuzhiyun 	trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
6448*4882a593Smuzhiyun 	if (field->next) {
6449*4882a593Smuzhiyun 		trace_seq_puts(s, ", ");
6450*4882a593Smuzhiyun 		print_fields(s, field->next);
6451*4882a593Smuzhiyun 	}
6452*4882a593Smuzhiyun }
6453*4882a593Smuzhiyun 
6454*4882a593Smuzhiyun /* for debugging */
print_args(struct tep_print_arg * args)6455*4882a593Smuzhiyun static void print_args(struct tep_print_arg *args)
6456*4882a593Smuzhiyun {
6457*4882a593Smuzhiyun 	int print_paren = 1;
6458*4882a593Smuzhiyun 	struct trace_seq s;
6459*4882a593Smuzhiyun 
6460*4882a593Smuzhiyun 	switch (args->type) {
6461*4882a593Smuzhiyun 	case TEP_PRINT_NULL:
6462*4882a593Smuzhiyun 		printf("null");
6463*4882a593Smuzhiyun 		break;
6464*4882a593Smuzhiyun 	case TEP_PRINT_ATOM:
6465*4882a593Smuzhiyun 		printf("%s", args->atom.atom);
6466*4882a593Smuzhiyun 		break;
6467*4882a593Smuzhiyun 	case TEP_PRINT_FIELD:
6468*4882a593Smuzhiyun 		printf("REC->%s", args->field.name);
6469*4882a593Smuzhiyun 		break;
6470*4882a593Smuzhiyun 	case TEP_PRINT_FLAGS:
6471*4882a593Smuzhiyun 		printf("__print_flags(");
6472*4882a593Smuzhiyun 		print_args(args->flags.field);
6473*4882a593Smuzhiyun 		printf(", %s, ", args->flags.delim);
6474*4882a593Smuzhiyun 		trace_seq_init(&s);
6475*4882a593Smuzhiyun 		print_fields(&s, args->flags.flags);
6476*4882a593Smuzhiyun 		trace_seq_do_printf(&s);
6477*4882a593Smuzhiyun 		trace_seq_destroy(&s);
6478*4882a593Smuzhiyun 		printf(")");
6479*4882a593Smuzhiyun 		break;
6480*4882a593Smuzhiyun 	case TEP_PRINT_SYMBOL:
6481*4882a593Smuzhiyun 		printf("__print_symbolic(");
6482*4882a593Smuzhiyun 		print_args(args->symbol.field);
6483*4882a593Smuzhiyun 		printf(", ");
6484*4882a593Smuzhiyun 		trace_seq_init(&s);
6485*4882a593Smuzhiyun 		print_fields(&s, args->symbol.symbols);
6486*4882a593Smuzhiyun 		trace_seq_do_printf(&s);
6487*4882a593Smuzhiyun 		trace_seq_destroy(&s);
6488*4882a593Smuzhiyun 		printf(")");
6489*4882a593Smuzhiyun 		break;
6490*4882a593Smuzhiyun 	case TEP_PRINT_HEX:
6491*4882a593Smuzhiyun 		printf("__print_hex(");
6492*4882a593Smuzhiyun 		print_args(args->hex.field);
6493*4882a593Smuzhiyun 		printf(", ");
6494*4882a593Smuzhiyun 		print_args(args->hex.size);
6495*4882a593Smuzhiyun 		printf(")");
6496*4882a593Smuzhiyun 		break;
6497*4882a593Smuzhiyun 	case TEP_PRINT_HEX_STR:
6498*4882a593Smuzhiyun 		printf("__print_hex_str(");
6499*4882a593Smuzhiyun 		print_args(args->hex.field);
6500*4882a593Smuzhiyun 		printf(", ");
6501*4882a593Smuzhiyun 		print_args(args->hex.size);
6502*4882a593Smuzhiyun 		printf(")");
6503*4882a593Smuzhiyun 		break;
6504*4882a593Smuzhiyun 	case TEP_PRINT_INT_ARRAY:
6505*4882a593Smuzhiyun 		printf("__print_array(");
6506*4882a593Smuzhiyun 		print_args(args->int_array.field);
6507*4882a593Smuzhiyun 		printf(", ");
6508*4882a593Smuzhiyun 		print_args(args->int_array.count);
6509*4882a593Smuzhiyun 		printf(", ");
6510*4882a593Smuzhiyun 		print_args(args->int_array.el_size);
6511*4882a593Smuzhiyun 		printf(")");
6512*4882a593Smuzhiyun 		break;
6513*4882a593Smuzhiyun 	case TEP_PRINT_STRING:
6514*4882a593Smuzhiyun 	case TEP_PRINT_BSTRING:
6515*4882a593Smuzhiyun 		printf("__get_str(%s)", args->string.string);
6516*4882a593Smuzhiyun 		break;
6517*4882a593Smuzhiyun 	case TEP_PRINT_BITMASK:
6518*4882a593Smuzhiyun 		printf("__get_bitmask(%s)", args->bitmask.bitmask);
6519*4882a593Smuzhiyun 		break;
6520*4882a593Smuzhiyun 	case TEP_PRINT_TYPE:
6521*4882a593Smuzhiyun 		printf("(%s)", args->typecast.type);
6522*4882a593Smuzhiyun 		print_args(args->typecast.item);
6523*4882a593Smuzhiyun 		break;
6524*4882a593Smuzhiyun 	case TEP_PRINT_OP:
6525*4882a593Smuzhiyun 		if (strcmp(args->op.op, ":") == 0)
6526*4882a593Smuzhiyun 			print_paren = 0;
6527*4882a593Smuzhiyun 		if (print_paren)
6528*4882a593Smuzhiyun 			printf("(");
6529*4882a593Smuzhiyun 		print_args(args->op.left);
6530*4882a593Smuzhiyun 		printf(" %s ", args->op.op);
6531*4882a593Smuzhiyun 		print_args(args->op.right);
6532*4882a593Smuzhiyun 		if (print_paren)
6533*4882a593Smuzhiyun 			printf(")");
6534*4882a593Smuzhiyun 		break;
6535*4882a593Smuzhiyun 	default:
6536*4882a593Smuzhiyun 		/* we should warn... */
6537*4882a593Smuzhiyun 		return;
6538*4882a593Smuzhiyun 	}
6539*4882a593Smuzhiyun 	if (args->next) {
6540*4882a593Smuzhiyun 		printf("\n");
6541*4882a593Smuzhiyun 		print_args(args->next);
6542*4882a593Smuzhiyun 	}
6543*4882a593Smuzhiyun }
6544*4882a593Smuzhiyun 
parse_header_field(const char * field,int * offset,int * size,int mandatory)6545*4882a593Smuzhiyun static void parse_header_field(const char *field,
6546*4882a593Smuzhiyun 			       int *offset, int *size, int mandatory)
6547*4882a593Smuzhiyun {
6548*4882a593Smuzhiyun 	unsigned long long save_input_buf_ptr;
6549*4882a593Smuzhiyun 	unsigned long long save_input_buf_siz;
6550*4882a593Smuzhiyun 	char *token;
6551*4882a593Smuzhiyun 	int type;
6552*4882a593Smuzhiyun 
6553*4882a593Smuzhiyun 	save_input_buf_ptr = input_buf_ptr;
6554*4882a593Smuzhiyun 	save_input_buf_siz = input_buf_siz;
6555*4882a593Smuzhiyun 
6556*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_ITEM, "field") < 0)
6557*4882a593Smuzhiyun 		return;
6558*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
6559*4882a593Smuzhiyun 		return;
6560*4882a593Smuzhiyun 
6561*4882a593Smuzhiyun 	/* type */
6562*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
6563*4882a593Smuzhiyun 		goto fail;
6564*4882a593Smuzhiyun 	free_token(token);
6565*4882a593Smuzhiyun 
6566*4882a593Smuzhiyun 	/*
6567*4882a593Smuzhiyun 	 * If this is not a mandatory field, then test it first.
6568*4882a593Smuzhiyun 	 */
6569*4882a593Smuzhiyun 	if (mandatory) {
6570*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_ITEM, field) < 0)
6571*4882a593Smuzhiyun 			return;
6572*4882a593Smuzhiyun 	} else {
6573*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
6574*4882a593Smuzhiyun 			goto fail;
6575*4882a593Smuzhiyun 		if (strcmp(token, field) != 0)
6576*4882a593Smuzhiyun 			goto discard;
6577*4882a593Smuzhiyun 		free_token(token);
6578*4882a593Smuzhiyun 	}
6579*4882a593Smuzhiyun 
6580*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ";") < 0)
6581*4882a593Smuzhiyun 		return;
6582*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_ITEM, "offset") < 0)
6583*4882a593Smuzhiyun 		return;
6584*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
6585*4882a593Smuzhiyun 		return;
6586*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
6587*4882a593Smuzhiyun 		goto fail;
6588*4882a593Smuzhiyun 	*offset = atoi(token);
6589*4882a593Smuzhiyun 	free_token(token);
6590*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ";") < 0)
6591*4882a593Smuzhiyun 		return;
6592*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_ITEM, "size") < 0)
6593*4882a593Smuzhiyun 		return;
6594*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ":") < 0)
6595*4882a593Smuzhiyun 		return;
6596*4882a593Smuzhiyun 	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
6597*4882a593Smuzhiyun 		goto fail;
6598*4882a593Smuzhiyun 	*size = atoi(token);
6599*4882a593Smuzhiyun 	free_token(token);
6600*4882a593Smuzhiyun 	if (read_expected(TEP_EVENT_OP, ";") < 0)
6601*4882a593Smuzhiyun 		return;
6602*4882a593Smuzhiyun 	type = read_token(&token);
6603*4882a593Smuzhiyun 	if (type != TEP_EVENT_NEWLINE) {
6604*4882a593Smuzhiyun 		/* newer versions of the kernel have a "signed" type */
6605*4882a593Smuzhiyun 		if (type != TEP_EVENT_ITEM)
6606*4882a593Smuzhiyun 			goto fail;
6607*4882a593Smuzhiyun 
6608*4882a593Smuzhiyun 		if (strcmp(token, "signed") != 0)
6609*4882a593Smuzhiyun 			goto fail;
6610*4882a593Smuzhiyun 
6611*4882a593Smuzhiyun 		free_token(token);
6612*4882a593Smuzhiyun 
6613*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ":") < 0)
6614*4882a593Smuzhiyun 			return;
6615*4882a593Smuzhiyun 
6616*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_ITEM, &token))
6617*4882a593Smuzhiyun 			goto fail;
6618*4882a593Smuzhiyun 
6619*4882a593Smuzhiyun 		free_token(token);
6620*4882a593Smuzhiyun 		if (read_expected(TEP_EVENT_OP, ";") < 0)
6621*4882a593Smuzhiyun 			return;
6622*4882a593Smuzhiyun 
6623*4882a593Smuzhiyun 		if (read_expect_type(TEP_EVENT_NEWLINE, &token))
6624*4882a593Smuzhiyun 			goto fail;
6625*4882a593Smuzhiyun 	}
6626*4882a593Smuzhiyun  fail:
6627*4882a593Smuzhiyun 	free_token(token);
6628*4882a593Smuzhiyun 	return;
6629*4882a593Smuzhiyun 
6630*4882a593Smuzhiyun  discard:
6631*4882a593Smuzhiyun 	input_buf_ptr = save_input_buf_ptr;
6632*4882a593Smuzhiyun 	input_buf_siz = save_input_buf_siz;
6633*4882a593Smuzhiyun 	*offset = 0;
6634*4882a593Smuzhiyun 	*size = 0;
6635*4882a593Smuzhiyun 	free_token(token);
6636*4882a593Smuzhiyun }
6637*4882a593Smuzhiyun 
6638*4882a593Smuzhiyun /**
6639*4882a593Smuzhiyun  * tep_parse_header_page - parse the data stored in the header page
6640*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
6641*4882a593Smuzhiyun  * @buf: the buffer storing the header page format string
6642*4882a593Smuzhiyun  * @size: the size of @buf
6643*4882a593Smuzhiyun  * @long_size: the long size to use if there is no header
6644*4882a593Smuzhiyun  *
6645*4882a593Smuzhiyun  * This parses the header page format for information on the
6646*4882a593Smuzhiyun  * ring buffer used. The @buf should be copied from
6647*4882a593Smuzhiyun  *
6648*4882a593Smuzhiyun  * /sys/kernel/debug/tracing/events/header_page
6649*4882a593Smuzhiyun  */
tep_parse_header_page(struct tep_handle * tep,char * buf,unsigned long size,int long_size)6650*4882a593Smuzhiyun int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size,
6651*4882a593Smuzhiyun 			  int long_size)
6652*4882a593Smuzhiyun {
6653*4882a593Smuzhiyun 	int ignore;
6654*4882a593Smuzhiyun 
6655*4882a593Smuzhiyun 	if (!size) {
6656*4882a593Smuzhiyun 		/*
6657*4882a593Smuzhiyun 		 * Old kernels did not have header page info.
6658*4882a593Smuzhiyun 		 * Sorry but we just use what we find here in user space.
6659*4882a593Smuzhiyun 		 */
6660*4882a593Smuzhiyun 		tep->header_page_ts_size = sizeof(long long);
6661*4882a593Smuzhiyun 		tep->header_page_size_size = long_size;
6662*4882a593Smuzhiyun 		tep->header_page_data_offset = sizeof(long long) + long_size;
6663*4882a593Smuzhiyun 		tep->old_format = 1;
6664*4882a593Smuzhiyun 		return -1;
6665*4882a593Smuzhiyun 	}
6666*4882a593Smuzhiyun 	init_input_buf(buf, size);
6667*4882a593Smuzhiyun 
6668*4882a593Smuzhiyun 	parse_header_field("timestamp", &tep->header_page_ts_offset,
6669*4882a593Smuzhiyun 			   &tep->header_page_ts_size, 1);
6670*4882a593Smuzhiyun 	parse_header_field("commit", &tep->header_page_size_offset,
6671*4882a593Smuzhiyun 			   &tep->header_page_size_size, 1);
6672*4882a593Smuzhiyun 	parse_header_field("overwrite", &tep->header_page_overwrite,
6673*4882a593Smuzhiyun 			   &ignore, 0);
6674*4882a593Smuzhiyun 	parse_header_field("data", &tep->header_page_data_offset,
6675*4882a593Smuzhiyun 			   &tep->header_page_data_size, 1);
6676*4882a593Smuzhiyun 
6677*4882a593Smuzhiyun 	return 0;
6678*4882a593Smuzhiyun }
6679*4882a593Smuzhiyun 
event_matches(struct tep_event * event,int id,const char * sys_name,const char * event_name)6680*4882a593Smuzhiyun static int event_matches(struct tep_event *event,
6681*4882a593Smuzhiyun 			 int id, const char *sys_name,
6682*4882a593Smuzhiyun 			 const char *event_name)
6683*4882a593Smuzhiyun {
6684*4882a593Smuzhiyun 	if (id >= 0 && id != event->id)
6685*4882a593Smuzhiyun 		return 0;
6686*4882a593Smuzhiyun 
6687*4882a593Smuzhiyun 	if (event_name && (strcmp(event_name, event->name) != 0))
6688*4882a593Smuzhiyun 		return 0;
6689*4882a593Smuzhiyun 
6690*4882a593Smuzhiyun 	if (sys_name && (strcmp(sys_name, event->system) != 0))
6691*4882a593Smuzhiyun 		return 0;
6692*4882a593Smuzhiyun 
6693*4882a593Smuzhiyun 	return 1;
6694*4882a593Smuzhiyun }
6695*4882a593Smuzhiyun 
free_handler(struct event_handler * handle)6696*4882a593Smuzhiyun static void free_handler(struct event_handler *handle)
6697*4882a593Smuzhiyun {
6698*4882a593Smuzhiyun 	free((void *)handle->sys_name);
6699*4882a593Smuzhiyun 	free((void *)handle->event_name);
6700*4882a593Smuzhiyun 	free(handle);
6701*4882a593Smuzhiyun }
6702*4882a593Smuzhiyun 
find_event_handle(struct tep_handle * tep,struct tep_event * event)6703*4882a593Smuzhiyun static int find_event_handle(struct tep_handle *tep, struct tep_event *event)
6704*4882a593Smuzhiyun {
6705*4882a593Smuzhiyun 	struct event_handler *handle, **next;
6706*4882a593Smuzhiyun 
6707*4882a593Smuzhiyun 	for (next = &tep->handlers; *next;
6708*4882a593Smuzhiyun 	     next = &(*next)->next) {
6709*4882a593Smuzhiyun 		handle = *next;
6710*4882a593Smuzhiyun 		if (event_matches(event, handle->id,
6711*4882a593Smuzhiyun 				  handle->sys_name,
6712*4882a593Smuzhiyun 				  handle->event_name))
6713*4882a593Smuzhiyun 			break;
6714*4882a593Smuzhiyun 	}
6715*4882a593Smuzhiyun 
6716*4882a593Smuzhiyun 	if (!(*next))
6717*4882a593Smuzhiyun 		return 0;
6718*4882a593Smuzhiyun 
6719*4882a593Smuzhiyun 	pr_stat("overriding event (%d) %s:%s with new print handler",
6720*4882a593Smuzhiyun 		event->id, event->system, event->name);
6721*4882a593Smuzhiyun 
6722*4882a593Smuzhiyun 	event->handler = handle->func;
6723*4882a593Smuzhiyun 	event->context = handle->context;
6724*4882a593Smuzhiyun 
6725*4882a593Smuzhiyun 	*next = handle->next;
6726*4882a593Smuzhiyun 	free_handler(handle);
6727*4882a593Smuzhiyun 
6728*4882a593Smuzhiyun 	return 1;
6729*4882a593Smuzhiyun }
6730*4882a593Smuzhiyun 
6731*4882a593Smuzhiyun /**
6732*4882a593Smuzhiyun  * parse_format - parse the event format
6733*4882a593Smuzhiyun  * @buf: the buffer storing the event format string
6734*4882a593Smuzhiyun  * @size: the size of @buf
6735*4882a593Smuzhiyun  * @sys: the system the event belongs to
6736*4882a593Smuzhiyun  *
6737*4882a593Smuzhiyun  * This parses the event format and creates an event structure
6738*4882a593Smuzhiyun  * to quickly parse raw data for a given event.
6739*4882a593Smuzhiyun  *
6740*4882a593Smuzhiyun  * These files currently come from:
6741*4882a593Smuzhiyun  *
6742*4882a593Smuzhiyun  * /sys/kernel/debug/tracing/events/.../.../format
6743*4882a593Smuzhiyun  */
parse_format(struct tep_event ** eventp,struct tep_handle * tep,const char * buf,unsigned long size,const char * sys)6744*4882a593Smuzhiyun static enum tep_errno parse_format(struct tep_event **eventp,
6745*4882a593Smuzhiyun 				   struct tep_handle *tep, const char *buf,
6746*4882a593Smuzhiyun 				   unsigned long size, const char *sys)
6747*4882a593Smuzhiyun {
6748*4882a593Smuzhiyun 	struct tep_event *event;
6749*4882a593Smuzhiyun 	int ret;
6750*4882a593Smuzhiyun 
6751*4882a593Smuzhiyun 	init_input_buf(buf, size);
6752*4882a593Smuzhiyun 
6753*4882a593Smuzhiyun 	*eventp = event = alloc_event();
6754*4882a593Smuzhiyun 	if (!event)
6755*4882a593Smuzhiyun 		return TEP_ERRNO__MEM_ALLOC_FAILED;
6756*4882a593Smuzhiyun 
6757*4882a593Smuzhiyun 	event->name = event_read_name();
6758*4882a593Smuzhiyun 	if (!event->name) {
6759*4882a593Smuzhiyun 		/* Bad event? */
6760*4882a593Smuzhiyun 		ret = TEP_ERRNO__MEM_ALLOC_FAILED;
6761*4882a593Smuzhiyun 		goto event_alloc_failed;
6762*4882a593Smuzhiyun 	}
6763*4882a593Smuzhiyun 
6764*4882a593Smuzhiyun 	if (strcmp(sys, "ftrace") == 0) {
6765*4882a593Smuzhiyun 		event->flags |= TEP_EVENT_FL_ISFTRACE;
6766*4882a593Smuzhiyun 
6767*4882a593Smuzhiyun 		if (strcmp(event->name, "bprint") == 0)
6768*4882a593Smuzhiyun 			event->flags |= TEP_EVENT_FL_ISBPRINT;
6769*4882a593Smuzhiyun 	}
6770*4882a593Smuzhiyun 
6771*4882a593Smuzhiyun 	event->id = event_read_id();
6772*4882a593Smuzhiyun 	if (event->id < 0) {
6773*4882a593Smuzhiyun 		ret = TEP_ERRNO__READ_ID_FAILED;
6774*4882a593Smuzhiyun 		/*
6775*4882a593Smuzhiyun 		 * This isn't an allocation error actually.
6776*4882a593Smuzhiyun 		 * But as the ID is critical, just bail out.
6777*4882a593Smuzhiyun 		 */
6778*4882a593Smuzhiyun 		goto event_alloc_failed;
6779*4882a593Smuzhiyun 	}
6780*4882a593Smuzhiyun 
6781*4882a593Smuzhiyun 	event->system = strdup(sys);
6782*4882a593Smuzhiyun 	if (!event->system) {
6783*4882a593Smuzhiyun 		ret = TEP_ERRNO__MEM_ALLOC_FAILED;
6784*4882a593Smuzhiyun 		goto event_alloc_failed;
6785*4882a593Smuzhiyun 	}
6786*4882a593Smuzhiyun 
6787*4882a593Smuzhiyun 	/* Add tep to event so that it can be referenced */
6788*4882a593Smuzhiyun 	event->tep = tep;
6789*4882a593Smuzhiyun 
6790*4882a593Smuzhiyun 	ret = event_read_format(event);
6791*4882a593Smuzhiyun 	if (ret < 0) {
6792*4882a593Smuzhiyun 		ret = TEP_ERRNO__READ_FORMAT_FAILED;
6793*4882a593Smuzhiyun 		goto event_parse_failed;
6794*4882a593Smuzhiyun 	}
6795*4882a593Smuzhiyun 
6796*4882a593Smuzhiyun 	/*
6797*4882a593Smuzhiyun 	 * If the event has an override, don't print warnings if the event
6798*4882a593Smuzhiyun 	 * print format fails to parse.
6799*4882a593Smuzhiyun 	 */
6800*4882a593Smuzhiyun 	if (tep && find_event_handle(tep, event))
6801*4882a593Smuzhiyun 		show_warning = 0;
6802*4882a593Smuzhiyun 
6803*4882a593Smuzhiyun 	ret = event_read_print(event);
6804*4882a593Smuzhiyun 	show_warning = 1;
6805*4882a593Smuzhiyun 
6806*4882a593Smuzhiyun 	if (ret < 0) {
6807*4882a593Smuzhiyun 		ret = TEP_ERRNO__READ_PRINT_FAILED;
6808*4882a593Smuzhiyun 		goto event_parse_failed;
6809*4882a593Smuzhiyun 	}
6810*4882a593Smuzhiyun 
6811*4882a593Smuzhiyun 	if (!ret && (event->flags & TEP_EVENT_FL_ISFTRACE)) {
6812*4882a593Smuzhiyun 		struct tep_format_field *field;
6813*4882a593Smuzhiyun 		struct tep_print_arg *arg, **list;
6814*4882a593Smuzhiyun 
6815*4882a593Smuzhiyun 		/* old ftrace had no args */
6816*4882a593Smuzhiyun 		list = &event->print_fmt.args;
6817*4882a593Smuzhiyun 		for (field = event->format.fields; field; field = field->next) {
6818*4882a593Smuzhiyun 			arg = alloc_arg();
6819*4882a593Smuzhiyun 			if (!arg) {
6820*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
6821*4882a593Smuzhiyun 				return TEP_ERRNO__OLD_FTRACE_ARG_FAILED;
6822*4882a593Smuzhiyun 			}
6823*4882a593Smuzhiyun 			arg->type = TEP_PRINT_FIELD;
6824*4882a593Smuzhiyun 			arg->field.name = strdup(field->name);
6825*4882a593Smuzhiyun 			if (!arg->field.name) {
6826*4882a593Smuzhiyun 				event->flags |= TEP_EVENT_FL_FAILED;
6827*4882a593Smuzhiyun 				free_arg(arg);
6828*4882a593Smuzhiyun 				return TEP_ERRNO__OLD_FTRACE_ARG_FAILED;
6829*4882a593Smuzhiyun 			}
6830*4882a593Smuzhiyun 			arg->field.field = field;
6831*4882a593Smuzhiyun 			*list = arg;
6832*4882a593Smuzhiyun 			list = &arg->next;
6833*4882a593Smuzhiyun 		}
6834*4882a593Smuzhiyun 	}
6835*4882a593Smuzhiyun 
6836*4882a593Smuzhiyun 	if (!(event->flags & TEP_EVENT_FL_ISBPRINT))
6837*4882a593Smuzhiyun 		event->print_fmt.print_cache = parse_args(event,
6838*4882a593Smuzhiyun 							  event->print_fmt.format,
6839*4882a593Smuzhiyun 							  event->print_fmt.args);
6840*4882a593Smuzhiyun 
6841*4882a593Smuzhiyun 	return 0;
6842*4882a593Smuzhiyun 
6843*4882a593Smuzhiyun  event_parse_failed:
6844*4882a593Smuzhiyun 	event->flags |= TEP_EVENT_FL_FAILED;
6845*4882a593Smuzhiyun 	return ret;
6846*4882a593Smuzhiyun 
6847*4882a593Smuzhiyun  event_alloc_failed:
6848*4882a593Smuzhiyun 	free(event->system);
6849*4882a593Smuzhiyun 	free(event->name);
6850*4882a593Smuzhiyun 	free(event);
6851*4882a593Smuzhiyun 	*eventp = NULL;
6852*4882a593Smuzhiyun 	return ret;
6853*4882a593Smuzhiyun }
6854*4882a593Smuzhiyun 
6855*4882a593Smuzhiyun static enum tep_errno
__parse_event(struct tep_handle * tep,struct tep_event ** eventp,const char * buf,unsigned long size,const char * sys)6856*4882a593Smuzhiyun __parse_event(struct tep_handle *tep,
6857*4882a593Smuzhiyun 	      struct tep_event **eventp,
6858*4882a593Smuzhiyun 	      const char *buf, unsigned long size,
6859*4882a593Smuzhiyun 	      const char *sys)
6860*4882a593Smuzhiyun {
6861*4882a593Smuzhiyun 	int ret = parse_format(eventp, tep, buf, size, sys);
6862*4882a593Smuzhiyun 	struct tep_event *event = *eventp;
6863*4882a593Smuzhiyun 
6864*4882a593Smuzhiyun 	if (event == NULL)
6865*4882a593Smuzhiyun 		return ret;
6866*4882a593Smuzhiyun 
6867*4882a593Smuzhiyun 	if (tep && add_event(tep, event)) {
6868*4882a593Smuzhiyun 		ret = TEP_ERRNO__MEM_ALLOC_FAILED;
6869*4882a593Smuzhiyun 		goto event_add_failed;
6870*4882a593Smuzhiyun 	}
6871*4882a593Smuzhiyun 
6872*4882a593Smuzhiyun #define PRINT_ARGS 0
6873*4882a593Smuzhiyun 	if (PRINT_ARGS && event->print_fmt.args)
6874*4882a593Smuzhiyun 		print_args(event->print_fmt.args);
6875*4882a593Smuzhiyun 
6876*4882a593Smuzhiyun 	return 0;
6877*4882a593Smuzhiyun 
6878*4882a593Smuzhiyun event_add_failed:
6879*4882a593Smuzhiyun 	free_tep_event(event);
6880*4882a593Smuzhiyun 	return ret;
6881*4882a593Smuzhiyun }
6882*4882a593Smuzhiyun 
6883*4882a593Smuzhiyun /**
6884*4882a593Smuzhiyun  * tep_parse_format - parse the event format
6885*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
6886*4882a593Smuzhiyun  * @eventp: returned format
6887*4882a593Smuzhiyun  * @buf: the buffer storing the event format string
6888*4882a593Smuzhiyun  * @size: the size of @buf
6889*4882a593Smuzhiyun  * @sys: the system the event belongs to
6890*4882a593Smuzhiyun  *
6891*4882a593Smuzhiyun  * This parses the event format and creates an event structure
6892*4882a593Smuzhiyun  * to quickly parse raw data for a given event.
6893*4882a593Smuzhiyun  *
6894*4882a593Smuzhiyun  * These files currently come from:
6895*4882a593Smuzhiyun  *
6896*4882a593Smuzhiyun  * /sys/kernel/debug/tracing/events/.../.../format
6897*4882a593Smuzhiyun  */
tep_parse_format(struct tep_handle * tep,struct tep_event ** eventp,const char * buf,unsigned long size,const char * sys)6898*4882a593Smuzhiyun enum tep_errno tep_parse_format(struct tep_handle *tep,
6899*4882a593Smuzhiyun 				struct tep_event **eventp,
6900*4882a593Smuzhiyun 				const char *buf,
6901*4882a593Smuzhiyun 				unsigned long size, const char *sys)
6902*4882a593Smuzhiyun {
6903*4882a593Smuzhiyun 	return __parse_event(tep, eventp, buf, size, sys);
6904*4882a593Smuzhiyun }
6905*4882a593Smuzhiyun 
6906*4882a593Smuzhiyun /**
6907*4882a593Smuzhiyun  * tep_parse_event - parse the event format
6908*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
6909*4882a593Smuzhiyun  * @buf: the buffer storing the event format string
6910*4882a593Smuzhiyun  * @size: the size of @buf
6911*4882a593Smuzhiyun  * @sys: the system the event belongs to
6912*4882a593Smuzhiyun  *
6913*4882a593Smuzhiyun  * This parses the event format and creates an event structure
6914*4882a593Smuzhiyun  * to quickly parse raw data for a given event.
6915*4882a593Smuzhiyun  *
6916*4882a593Smuzhiyun  * These files currently come from:
6917*4882a593Smuzhiyun  *
6918*4882a593Smuzhiyun  * /sys/kernel/debug/tracing/events/.../.../format
6919*4882a593Smuzhiyun  */
tep_parse_event(struct tep_handle * tep,const char * buf,unsigned long size,const char * sys)6920*4882a593Smuzhiyun enum tep_errno tep_parse_event(struct tep_handle *tep, const char *buf,
6921*4882a593Smuzhiyun 			       unsigned long size, const char *sys)
6922*4882a593Smuzhiyun {
6923*4882a593Smuzhiyun 	struct tep_event *event = NULL;
6924*4882a593Smuzhiyun 	return __parse_event(tep, &event, buf, size, sys);
6925*4882a593Smuzhiyun }
6926*4882a593Smuzhiyun 
get_field_val(struct trace_seq * s,struct tep_format_field * field,const char * name,struct tep_record * record,unsigned long long * val,int err)6927*4882a593Smuzhiyun int get_field_val(struct trace_seq *s, struct tep_format_field *field,
6928*4882a593Smuzhiyun 		  const char *name, struct tep_record *record,
6929*4882a593Smuzhiyun 		  unsigned long long *val, int err)
6930*4882a593Smuzhiyun {
6931*4882a593Smuzhiyun 	if (!field) {
6932*4882a593Smuzhiyun 		if (err)
6933*4882a593Smuzhiyun 			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
6934*4882a593Smuzhiyun 		return -1;
6935*4882a593Smuzhiyun 	}
6936*4882a593Smuzhiyun 
6937*4882a593Smuzhiyun 	if (tep_read_number_field(field, record->data, val)) {
6938*4882a593Smuzhiyun 		if (err)
6939*4882a593Smuzhiyun 			trace_seq_printf(s, " %s=INVALID", name);
6940*4882a593Smuzhiyun 		return -1;
6941*4882a593Smuzhiyun 	}
6942*4882a593Smuzhiyun 
6943*4882a593Smuzhiyun 	return 0;
6944*4882a593Smuzhiyun }
6945*4882a593Smuzhiyun 
6946*4882a593Smuzhiyun /**
6947*4882a593Smuzhiyun  * tep_get_field_raw - return the raw pointer into the data field
6948*4882a593Smuzhiyun  * @s: The seq to print to on error
6949*4882a593Smuzhiyun  * @event: the event that the field is for
6950*4882a593Smuzhiyun  * @name: The name of the field
6951*4882a593Smuzhiyun  * @record: The record with the field name.
6952*4882a593Smuzhiyun  * @len: place to store the field length.
6953*4882a593Smuzhiyun  * @err: print default error if failed.
6954*4882a593Smuzhiyun  *
6955*4882a593Smuzhiyun  * Returns a pointer into record->data of the field and places
6956*4882a593Smuzhiyun  * the length of the field in @len.
6957*4882a593Smuzhiyun  *
6958*4882a593Smuzhiyun  * On failure, it returns NULL.
6959*4882a593Smuzhiyun  */
tep_get_field_raw(struct trace_seq * s,struct tep_event * event,const char * name,struct tep_record * record,int * len,int err)6960*4882a593Smuzhiyun void *tep_get_field_raw(struct trace_seq *s, struct tep_event *event,
6961*4882a593Smuzhiyun 			const char *name, struct tep_record *record,
6962*4882a593Smuzhiyun 			int *len, int err)
6963*4882a593Smuzhiyun {
6964*4882a593Smuzhiyun 	struct tep_format_field *field;
6965*4882a593Smuzhiyun 	void *data = record->data;
6966*4882a593Smuzhiyun 	unsigned offset;
6967*4882a593Smuzhiyun 	int dummy;
6968*4882a593Smuzhiyun 
6969*4882a593Smuzhiyun 	if (!event)
6970*4882a593Smuzhiyun 		return NULL;
6971*4882a593Smuzhiyun 
6972*4882a593Smuzhiyun 	field = tep_find_field(event, name);
6973*4882a593Smuzhiyun 
6974*4882a593Smuzhiyun 	if (!field) {
6975*4882a593Smuzhiyun 		if (err)
6976*4882a593Smuzhiyun 			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
6977*4882a593Smuzhiyun 		return NULL;
6978*4882a593Smuzhiyun 	}
6979*4882a593Smuzhiyun 
6980*4882a593Smuzhiyun 	/* Allow @len to be NULL */
6981*4882a593Smuzhiyun 	if (!len)
6982*4882a593Smuzhiyun 		len = &dummy;
6983*4882a593Smuzhiyun 
6984*4882a593Smuzhiyun 	offset = field->offset;
6985*4882a593Smuzhiyun 	if (field->flags & TEP_FIELD_IS_DYNAMIC) {
6986*4882a593Smuzhiyun 		offset = tep_read_number(event->tep,
6987*4882a593Smuzhiyun 					 data + offset, field->size);
6988*4882a593Smuzhiyun 		*len = offset >> 16;
6989*4882a593Smuzhiyun 		offset &= 0xffff;
6990*4882a593Smuzhiyun 	} else
6991*4882a593Smuzhiyun 		*len = field->size;
6992*4882a593Smuzhiyun 
6993*4882a593Smuzhiyun 	return data + offset;
6994*4882a593Smuzhiyun }
6995*4882a593Smuzhiyun 
6996*4882a593Smuzhiyun /**
6997*4882a593Smuzhiyun  * tep_get_field_val - find a field and return its value
6998*4882a593Smuzhiyun  * @s: The seq to print to on error
6999*4882a593Smuzhiyun  * @event: the event that the field is for
7000*4882a593Smuzhiyun  * @name: The name of the field
7001*4882a593Smuzhiyun  * @record: The record with the field name.
7002*4882a593Smuzhiyun  * @val: place to store the value of the field.
7003*4882a593Smuzhiyun  * @err: print default error if failed.
7004*4882a593Smuzhiyun  *
7005*4882a593Smuzhiyun  * Returns 0 on success -1 on field not found.
7006*4882a593Smuzhiyun  */
tep_get_field_val(struct trace_seq * s,struct tep_event * event,const char * name,struct tep_record * record,unsigned long long * val,int err)7007*4882a593Smuzhiyun int tep_get_field_val(struct trace_seq *s, struct tep_event *event,
7008*4882a593Smuzhiyun 		      const char *name, struct tep_record *record,
7009*4882a593Smuzhiyun 		      unsigned long long *val, int err)
7010*4882a593Smuzhiyun {
7011*4882a593Smuzhiyun 	struct tep_format_field *field;
7012*4882a593Smuzhiyun 
7013*4882a593Smuzhiyun 	if (!event)
7014*4882a593Smuzhiyun 		return -1;
7015*4882a593Smuzhiyun 
7016*4882a593Smuzhiyun 	field = tep_find_field(event, name);
7017*4882a593Smuzhiyun 
7018*4882a593Smuzhiyun 	return get_field_val(s, field, name, record, val, err);
7019*4882a593Smuzhiyun }
7020*4882a593Smuzhiyun 
7021*4882a593Smuzhiyun /**
7022*4882a593Smuzhiyun  * tep_get_common_field_val - find a common field and return its value
7023*4882a593Smuzhiyun  * @s: The seq to print to on error
7024*4882a593Smuzhiyun  * @event: the event that the field is for
7025*4882a593Smuzhiyun  * @name: The name of the field
7026*4882a593Smuzhiyun  * @record: The record with the field name.
7027*4882a593Smuzhiyun  * @val: place to store the value of the field.
7028*4882a593Smuzhiyun  * @err: print default error if failed.
7029*4882a593Smuzhiyun  *
7030*4882a593Smuzhiyun  * Returns 0 on success -1 on field not found.
7031*4882a593Smuzhiyun  */
tep_get_common_field_val(struct trace_seq * s,struct tep_event * event,const char * name,struct tep_record * record,unsigned long long * val,int err)7032*4882a593Smuzhiyun int tep_get_common_field_val(struct trace_seq *s, struct tep_event *event,
7033*4882a593Smuzhiyun 			     const char *name, struct tep_record *record,
7034*4882a593Smuzhiyun 			     unsigned long long *val, int err)
7035*4882a593Smuzhiyun {
7036*4882a593Smuzhiyun 	struct tep_format_field *field;
7037*4882a593Smuzhiyun 
7038*4882a593Smuzhiyun 	if (!event)
7039*4882a593Smuzhiyun 		return -1;
7040*4882a593Smuzhiyun 
7041*4882a593Smuzhiyun 	field = tep_find_common_field(event, name);
7042*4882a593Smuzhiyun 
7043*4882a593Smuzhiyun 	return get_field_val(s, field, name, record, val, err);
7044*4882a593Smuzhiyun }
7045*4882a593Smuzhiyun 
7046*4882a593Smuzhiyun /**
7047*4882a593Smuzhiyun  * tep_get_any_field_val - find a any field and return its value
7048*4882a593Smuzhiyun  * @s: The seq to print to on error
7049*4882a593Smuzhiyun  * @event: the event that the field is for
7050*4882a593Smuzhiyun  * @name: The name of the field
7051*4882a593Smuzhiyun  * @record: The record with the field name.
7052*4882a593Smuzhiyun  * @val: place to store the value of the field.
7053*4882a593Smuzhiyun  * @err: print default error if failed.
7054*4882a593Smuzhiyun  *
7055*4882a593Smuzhiyun  * Returns 0 on success -1 on field not found.
7056*4882a593Smuzhiyun  */
tep_get_any_field_val(struct trace_seq * s,struct tep_event * event,const char * name,struct tep_record * record,unsigned long long * val,int err)7057*4882a593Smuzhiyun int tep_get_any_field_val(struct trace_seq *s, struct tep_event *event,
7058*4882a593Smuzhiyun 			  const char *name, struct tep_record *record,
7059*4882a593Smuzhiyun 			  unsigned long long *val, int err)
7060*4882a593Smuzhiyun {
7061*4882a593Smuzhiyun 	struct tep_format_field *field;
7062*4882a593Smuzhiyun 
7063*4882a593Smuzhiyun 	if (!event)
7064*4882a593Smuzhiyun 		return -1;
7065*4882a593Smuzhiyun 
7066*4882a593Smuzhiyun 	field = tep_find_any_field(event, name);
7067*4882a593Smuzhiyun 
7068*4882a593Smuzhiyun 	return get_field_val(s, field, name, record, val, err);
7069*4882a593Smuzhiyun }
7070*4882a593Smuzhiyun 
7071*4882a593Smuzhiyun /**
7072*4882a593Smuzhiyun  * tep_print_num_field - print a field and a format
7073*4882a593Smuzhiyun  * @s: The seq to print to
7074*4882a593Smuzhiyun  * @fmt: The printf format to print the field with.
7075*4882a593Smuzhiyun  * @event: the event that the field is for
7076*4882a593Smuzhiyun  * @name: The name of the field
7077*4882a593Smuzhiyun  * @record: The record with the field name.
7078*4882a593Smuzhiyun  * @err: print default error if failed.
7079*4882a593Smuzhiyun  *
7080*4882a593Smuzhiyun  * Returns positive value on success, negative in case of an error,
7081*4882a593Smuzhiyun  * or 0 if buffer is full.
7082*4882a593Smuzhiyun  */
tep_print_num_field(struct trace_seq * s,const char * fmt,struct tep_event * event,const char * name,struct tep_record * record,int err)7083*4882a593Smuzhiyun int tep_print_num_field(struct trace_seq *s, const char *fmt,
7084*4882a593Smuzhiyun 			struct tep_event *event, const char *name,
7085*4882a593Smuzhiyun 			struct tep_record *record, int err)
7086*4882a593Smuzhiyun {
7087*4882a593Smuzhiyun 	struct tep_format_field *field = tep_find_field(event, name);
7088*4882a593Smuzhiyun 	unsigned long long val;
7089*4882a593Smuzhiyun 
7090*4882a593Smuzhiyun 	if (!field)
7091*4882a593Smuzhiyun 		goto failed;
7092*4882a593Smuzhiyun 
7093*4882a593Smuzhiyun 	if (tep_read_number_field(field, record->data, &val))
7094*4882a593Smuzhiyun 		goto failed;
7095*4882a593Smuzhiyun 
7096*4882a593Smuzhiyun 	return trace_seq_printf(s, fmt, val);
7097*4882a593Smuzhiyun 
7098*4882a593Smuzhiyun  failed:
7099*4882a593Smuzhiyun 	if (err)
7100*4882a593Smuzhiyun 		trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
7101*4882a593Smuzhiyun 	return -1;
7102*4882a593Smuzhiyun }
7103*4882a593Smuzhiyun 
7104*4882a593Smuzhiyun /**
7105*4882a593Smuzhiyun  * tep_print_func_field - print a field and a format for function pointers
7106*4882a593Smuzhiyun  * @s: The seq to print to
7107*4882a593Smuzhiyun  * @fmt: The printf format to print the field with.
7108*4882a593Smuzhiyun  * @event: the event that the field is for
7109*4882a593Smuzhiyun  * @name: The name of the field
7110*4882a593Smuzhiyun  * @record: The record with the field name.
7111*4882a593Smuzhiyun  * @err: print default error if failed.
7112*4882a593Smuzhiyun  *
7113*4882a593Smuzhiyun  * Returns positive value on success, negative in case of an error,
7114*4882a593Smuzhiyun  * or 0 if buffer is full.
7115*4882a593Smuzhiyun  */
tep_print_func_field(struct trace_seq * s,const char * fmt,struct tep_event * event,const char * name,struct tep_record * record,int err)7116*4882a593Smuzhiyun int tep_print_func_field(struct trace_seq *s, const char *fmt,
7117*4882a593Smuzhiyun 			 struct tep_event *event, const char *name,
7118*4882a593Smuzhiyun 			 struct tep_record *record, int err)
7119*4882a593Smuzhiyun {
7120*4882a593Smuzhiyun 	struct tep_format_field *field = tep_find_field(event, name);
7121*4882a593Smuzhiyun 	struct tep_handle *tep = event->tep;
7122*4882a593Smuzhiyun 	unsigned long long val;
7123*4882a593Smuzhiyun 	struct func_map *func;
7124*4882a593Smuzhiyun 	char tmp[128];
7125*4882a593Smuzhiyun 
7126*4882a593Smuzhiyun 	if (!field)
7127*4882a593Smuzhiyun 		goto failed;
7128*4882a593Smuzhiyun 
7129*4882a593Smuzhiyun 	if (tep_read_number_field(field, record->data, &val))
7130*4882a593Smuzhiyun 		goto failed;
7131*4882a593Smuzhiyun 
7132*4882a593Smuzhiyun 	func = find_func(tep, val);
7133*4882a593Smuzhiyun 
7134*4882a593Smuzhiyun 	if (func)
7135*4882a593Smuzhiyun 		snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val);
7136*4882a593Smuzhiyun 	else
7137*4882a593Smuzhiyun 		sprintf(tmp, "0x%08llx", val);
7138*4882a593Smuzhiyun 
7139*4882a593Smuzhiyun 	return trace_seq_printf(s, fmt, tmp);
7140*4882a593Smuzhiyun 
7141*4882a593Smuzhiyun  failed:
7142*4882a593Smuzhiyun 	if (err)
7143*4882a593Smuzhiyun 		trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
7144*4882a593Smuzhiyun 	return -1;
7145*4882a593Smuzhiyun }
7146*4882a593Smuzhiyun 
free_func_handle(struct tep_function_handler * func)7147*4882a593Smuzhiyun static void free_func_handle(struct tep_function_handler *func)
7148*4882a593Smuzhiyun {
7149*4882a593Smuzhiyun 	struct func_params *params;
7150*4882a593Smuzhiyun 
7151*4882a593Smuzhiyun 	free(func->name);
7152*4882a593Smuzhiyun 
7153*4882a593Smuzhiyun 	while (func->params) {
7154*4882a593Smuzhiyun 		params = func->params;
7155*4882a593Smuzhiyun 		func->params = params->next;
7156*4882a593Smuzhiyun 		free(params);
7157*4882a593Smuzhiyun 	}
7158*4882a593Smuzhiyun 
7159*4882a593Smuzhiyun 	free(func);
7160*4882a593Smuzhiyun }
7161*4882a593Smuzhiyun 
7162*4882a593Smuzhiyun /**
7163*4882a593Smuzhiyun  * tep_register_print_function - register a helper function
7164*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
7165*4882a593Smuzhiyun  * @func: the function to process the helper function
7166*4882a593Smuzhiyun  * @ret_type: the return type of the helper function
7167*4882a593Smuzhiyun  * @name: the name of the helper function
7168*4882a593Smuzhiyun  * @parameters: A list of enum tep_func_arg_type
7169*4882a593Smuzhiyun  *
7170*4882a593Smuzhiyun  * Some events may have helper functions in the print format arguments.
7171*4882a593Smuzhiyun  * This allows a plugin to dynamically create a way to process one
7172*4882a593Smuzhiyun  * of these functions.
7173*4882a593Smuzhiyun  *
7174*4882a593Smuzhiyun  * The @parameters is a variable list of tep_func_arg_type enums that
7175*4882a593Smuzhiyun  * must end with TEP_FUNC_ARG_VOID.
7176*4882a593Smuzhiyun  */
tep_register_print_function(struct tep_handle * tep,tep_func_handler func,enum tep_func_arg_type ret_type,char * name,...)7177*4882a593Smuzhiyun int tep_register_print_function(struct tep_handle *tep,
7178*4882a593Smuzhiyun 				tep_func_handler func,
7179*4882a593Smuzhiyun 				enum tep_func_arg_type ret_type,
7180*4882a593Smuzhiyun 				char *name, ...)
7181*4882a593Smuzhiyun {
7182*4882a593Smuzhiyun 	struct tep_function_handler *func_handle;
7183*4882a593Smuzhiyun 	struct func_params **next_param;
7184*4882a593Smuzhiyun 	struct func_params *param;
7185*4882a593Smuzhiyun 	enum tep_func_arg_type type;
7186*4882a593Smuzhiyun 	va_list ap;
7187*4882a593Smuzhiyun 	int ret;
7188*4882a593Smuzhiyun 
7189*4882a593Smuzhiyun 	func_handle = find_func_handler(tep, name);
7190*4882a593Smuzhiyun 	if (func_handle) {
7191*4882a593Smuzhiyun 		/*
7192*4882a593Smuzhiyun 		 * This is most like caused by the users own
7193*4882a593Smuzhiyun 		 * plugins updating the function. This overrides the
7194*4882a593Smuzhiyun 		 * system defaults.
7195*4882a593Smuzhiyun 		 */
7196*4882a593Smuzhiyun 		pr_stat("override of function helper '%s'", name);
7197*4882a593Smuzhiyun 		remove_func_handler(tep, name);
7198*4882a593Smuzhiyun 	}
7199*4882a593Smuzhiyun 
7200*4882a593Smuzhiyun 	func_handle = calloc(1, sizeof(*func_handle));
7201*4882a593Smuzhiyun 	if (!func_handle) {
7202*4882a593Smuzhiyun 		do_warning("Failed to allocate function handler");
7203*4882a593Smuzhiyun 		return TEP_ERRNO__MEM_ALLOC_FAILED;
7204*4882a593Smuzhiyun 	}
7205*4882a593Smuzhiyun 
7206*4882a593Smuzhiyun 	func_handle->ret_type = ret_type;
7207*4882a593Smuzhiyun 	func_handle->name = strdup(name);
7208*4882a593Smuzhiyun 	func_handle->func = func;
7209*4882a593Smuzhiyun 	if (!func_handle->name) {
7210*4882a593Smuzhiyun 		do_warning("Failed to allocate function name");
7211*4882a593Smuzhiyun 		free(func_handle);
7212*4882a593Smuzhiyun 		return TEP_ERRNO__MEM_ALLOC_FAILED;
7213*4882a593Smuzhiyun 	}
7214*4882a593Smuzhiyun 
7215*4882a593Smuzhiyun 	next_param = &(func_handle->params);
7216*4882a593Smuzhiyun 	va_start(ap, name);
7217*4882a593Smuzhiyun 	for (;;) {
7218*4882a593Smuzhiyun 		type = va_arg(ap, enum tep_func_arg_type);
7219*4882a593Smuzhiyun 		if (type == TEP_FUNC_ARG_VOID)
7220*4882a593Smuzhiyun 			break;
7221*4882a593Smuzhiyun 
7222*4882a593Smuzhiyun 		if (type >= TEP_FUNC_ARG_MAX_TYPES) {
7223*4882a593Smuzhiyun 			do_warning("Invalid argument type %d", type);
7224*4882a593Smuzhiyun 			ret = TEP_ERRNO__INVALID_ARG_TYPE;
7225*4882a593Smuzhiyun 			goto out_free;
7226*4882a593Smuzhiyun 		}
7227*4882a593Smuzhiyun 
7228*4882a593Smuzhiyun 		param = malloc(sizeof(*param));
7229*4882a593Smuzhiyun 		if (!param) {
7230*4882a593Smuzhiyun 			do_warning("Failed to allocate function param");
7231*4882a593Smuzhiyun 			ret = TEP_ERRNO__MEM_ALLOC_FAILED;
7232*4882a593Smuzhiyun 			goto out_free;
7233*4882a593Smuzhiyun 		}
7234*4882a593Smuzhiyun 		param->type = type;
7235*4882a593Smuzhiyun 		param->next = NULL;
7236*4882a593Smuzhiyun 
7237*4882a593Smuzhiyun 		*next_param = param;
7238*4882a593Smuzhiyun 		next_param = &(param->next);
7239*4882a593Smuzhiyun 
7240*4882a593Smuzhiyun 		func_handle->nr_args++;
7241*4882a593Smuzhiyun 	}
7242*4882a593Smuzhiyun 	va_end(ap);
7243*4882a593Smuzhiyun 
7244*4882a593Smuzhiyun 	func_handle->next = tep->func_handlers;
7245*4882a593Smuzhiyun 	tep->func_handlers = func_handle;
7246*4882a593Smuzhiyun 
7247*4882a593Smuzhiyun 	return 0;
7248*4882a593Smuzhiyun  out_free:
7249*4882a593Smuzhiyun 	va_end(ap);
7250*4882a593Smuzhiyun 	free_func_handle(func_handle);
7251*4882a593Smuzhiyun 	return ret;
7252*4882a593Smuzhiyun }
7253*4882a593Smuzhiyun 
7254*4882a593Smuzhiyun /**
7255*4882a593Smuzhiyun  * tep_unregister_print_function - unregister a helper function
7256*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
7257*4882a593Smuzhiyun  * @func: the function to process the helper function
7258*4882a593Smuzhiyun  * @name: the name of the helper function
7259*4882a593Smuzhiyun  *
7260*4882a593Smuzhiyun  * This function removes existing print handler for function @name.
7261*4882a593Smuzhiyun  *
7262*4882a593Smuzhiyun  * Returns 0 if the handler was removed successully, -1 otherwise.
7263*4882a593Smuzhiyun  */
tep_unregister_print_function(struct tep_handle * tep,tep_func_handler func,char * name)7264*4882a593Smuzhiyun int tep_unregister_print_function(struct tep_handle *tep,
7265*4882a593Smuzhiyun 				  tep_func_handler func, char *name)
7266*4882a593Smuzhiyun {
7267*4882a593Smuzhiyun 	struct tep_function_handler *func_handle;
7268*4882a593Smuzhiyun 
7269*4882a593Smuzhiyun 	func_handle = find_func_handler(tep, name);
7270*4882a593Smuzhiyun 	if (func_handle && func_handle->func == func) {
7271*4882a593Smuzhiyun 		remove_func_handler(tep, name);
7272*4882a593Smuzhiyun 		return 0;
7273*4882a593Smuzhiyun 	}
7274*4882a593Smuzhiyun 	return -1;
7275*4882a593Smuzhiyun }
7276*4882a593Smuzhiyun 
search_event(struct tep_handle * tep,int id,const char * sys_name,const char * event_name)7277*4882a593Smuzhiyun static struct tep_event *search_event(struct tep_handle *tep, int id,
7278*4882a593Smuzhiyun 				      const char *sys_name,
7279*4882a593Smuzhiyun 				      const char *event_name)
7280*4882a593Smuzhiyun {
7281*4882a593Smuzhiyun 	struct tep_event *event;
7282*4882a593Smuzhiyun 
7283*4882a593Smuzhiyun 	if (id >= 0) {
7284*4882a593Smuzhiyun 		/* search by id */
7285*4882a593Smuzhiyun 		event = tep_find_event(tep, id);
7286*4882a593Smuzhiyun 		if (!event)
7287*4882a593Smuzhiyun 			return NULL;
7288*4882a593Smuzhiyun 		if (event_name && (strcmp(event_name, event->name) != 0))
7289*4882a593Smuzhiyun 			return NULL;
7290*4882a593Smuzhiyun 		if (sys_name && (strcmp(sys_name, event->system) != 0))
7291*4882a593Smuzhiyun 			return NULL;
7292*4882a593Smuzhiyun 	} else {
7293*4882a593Smuzhiyun 		event = tep_find_event_by_name(tep, sys_name, event_name);
7294*4882a593Smuzhiyun 		if (!event)
7295*4882a593Smuzhiyun 			return NULL;
7296*4882a593Smuzhiyun 	}
7297*4882a593Smuzhiyun 	return event;
7298*4882a593Smuzhiyun }
7299*4882a593Smuzhiyun 
7300*4882a593Smuzhiyun /**
7301*4882a593Smuzhiyun  * tep_register_event_handler - register a way to parse an event
7302*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
7303*4882a593Smuzhiyun  * @id: the id of the event to register
7304*4882a593Smuzhiyun  * @sys_name: the system name the event belongs to
7305*4882a593Smuzhiyun  * @event_name: the name of the event
7306*4882a593Smuzhiyun  * @func: the function to call to parse the event information
7307*4882a593Smuzhiyun  * @context: the data to be passed to @func
7308*4882a593Smuzhiyun  *
7309*4882a593Smuzhiyun  * This function allows a developer to override the parsing of
7310*4882a593Smuzhiyun  * a given event. If for some reason the default print format
7311*4882a593Smuzhiyun  * is not sufficient, this function will register a function
7312*4882a593Smuzhiyun  * for an event to be used to parse the data instead.
7313*4882a593Smuzhiyun  *
7314*4882a593Smuzhiyun  * If @id is >= 0, then it is used to find the event.
7315*4882a593Smuzhiyun  * else @sys_name and @event_name are used.
7316*4882a593Smuzhiyun  *
7317*4882a593Smuzhiyun  * Returns:
7318*4882a593Smuzhiyun  *  TEP_REGISTER_SUCCESS_OVERWRITE if an existing handler is overwritten
7319*4882a593Smuzhiyun  *  TEP_REGISTER_SUCCESS if a new handler is registered successfully
7320*4882a593Smuzhiyun  *  negative TEP_ERRNO_... in case of an error
7321*4882a593Smuzhiyun  *
7322*4882a593Smuzhiyun  */
tep_register_event_handler(struct tep_handle * tep,int id,const char * sys_name,const char * event_name,tep_event_handler_func func,void * context)7323*4882a593Smuzhiyun int tep_register_event_handler(struct tep_handle *tep, int id,
7324*4882a593Smuzhiyun 			       const char *sys_name, const char *event_name,
7325*4882a593Smuzhiyun 			       tep_event_handler_func func, void *context)
7326*4882a593Smuzhiyun {
7327*4882a593Smuzhiyun 	struct tep_event *event;
7328*4882a593Smuzhiyun 	struct event_handler *handle;
7329*4882a593Smuzhiyun 
7330*4882a593Smuzhiyun 	event = search_event(tep, id, sys_name, event_name);
7331*4882a593Smuzhiyun 	if (event == NULL)
7332*4882a593Smuzhiyun 		goto not_found;
7333*4882a593Smuzhiyun 
7334*4882a593Smuzhiyun 	pr_stat("overriding event (%d) %s:%s with new print handler",
7335*4882a593Smuzhiyun 		event->id, event->system, event->name);
7336*4882a593Smuzhiyun 
7337*4882a593Smuzhiyun 	event->handler = func;
7338*4882a593Smuzhiyun 	event->context = context;
7339*4882a593Smuzhiyun 	return TEP_REGISTER_SUCCESS_OVERWRITE;
7340*4882a593Smuzhiyun 
7341*4882a593Smuzhiyun  not_found:
7342*4882a593Smuzhiyun 	/* Save for later use. */
7343*4882a593Smuzhiyun 	handle = calloc(1, sizeof(*handle));
7344*4882a593Smuzhiyun 	if (!handle) {
7345*4882a593Smuzhiyun 		do_warning("Failed to allocate event handler");
7346*4882a593Smuzhiyun 		return TEP_ERRNO__MEM_ALLOC_FAILED;
7347*4882a593Smuzhiyun 	}
7348*4882a593Smuzhiyun 
7349*4882a593Smuzhiyun 	handle->id = id;
7350*4882a593Smuzhiyun 	if (event_name)
7351*4882a593Smuzhiyun 		handle->event_name = strdup(event_name);
7352*4882a593Smuzhiyun 	if (sys_name)
7353*4882a593Smuzhiyun 		handle->sys_name = strdup(sys_name);
7354*4882a593Smuzhiyun 
7355*4882a593Smuzhiyun 	if ((event_name && !handle->event_name) ||
7356*4882a593Smuzhiyun 	    (sys_name && !handle->sys_name)) {
7357*4882a593Smuzhiyun 		do_warning("Failed to allocate event/sys name");
7358*4882a593Smuzhiyun 		free((void *)handle->event_name);
7359*4882a593Smuzhiyun 		free((void *)handle->sys_name);
7360*4882a593Smuzhiyun 		free(handle);
7361*4882a593Smuzhiyun 		return TEP_ERRNO__MEM_ALLOC_FAILED;
7362*4882a593Smuzhiyun 	}
7363*4882a593Smuzhiyun 
7364*4882a593Smuzhiyun 	handle->func = func;
7365*4882a593Smuzhiyun 	handle->next = tep->handlers;
7366*4882a593Smuzhiyun 	tep->handlers = handle;
7367*4882a593Smuzhiyun 	handle->context = context;
7368*4882a593Smuzhiyun 
7369*4882a593Smuzhiyun 	return TEP_REGISTER_SUCCESS;
7370*4882a593Smuzhiyun }
7371*4882a593Smuzhiyun 
handle_matches(struct event_handler * handler,int id,const char * sys_name,const char * event_name,tep_event_handler_func func,void * context)7372*4882a593Smuzhiyun static int handle_matches(struct event_handler *handler, int id,
7373*4882a593Smuzhiyun 			  const char *sys_name, const char *event_name,
7374*4882a593Smuzhiyun 			  tep_event_handler_func func, void *context)
7375*4882a593Smuzhiyun {
7376*4882a593Smuzhiyun 	if (id >= 0 && id != handler->id)
7377*4882a593Smuzhiyun 		return 0;
7378*4882a593Smuzhiyun 
7379*4882a593Smuzhiyun 	if (event_name && (strcmp(event_name, handler->event_name) != 0))
7380*4882a593Smuzhiyun 		return 0;
7381*4882a593Smuzhiyun 
7382*4882a593Smuzhiyun 	if (sys_name && (strcmp(sys_name, handler->sys_name) != 0))
7383*4882a593Smuzhiyun 		return 0;
7384*4882a593Smuzhiyun 
7385*4882a593Smuzhiyun 	if (func != handler->func || context != handler->context)
7386*4882a593Smuzhiyun 		return 0;
7387*4882a593Smuzhiyun 
7388*4882a593Smuzhiyun 	return 1;
7389*4882a593Smuzhiyun }
7390*4882a593Smuzhiyun 
7391*4882a593Smuzhiyun /**
7392*4882a593Smuzhiyun  * tep_unregister_event_handler - unregister an existing event handler
7393*4882a593Smuzhiyun  * @tep: a handle to the trace event parser context
7394*4882a593Smuzhiyun  * @id: the id of the event to unregister
7395*4882a593Smuzhiyun  * @sys_name: the system name the handler belongs to
7396*4882a593Smuzhiyun  * @event_name: the name of the event handler
7397*4882a593Smuzhiyun  * @func: the function to call to parse the event information
7398*4882a593Smuzhiyun  * @context: the data to be passed to @func
7399*4882a593Smuzhiyun  *
7400*4882a593Smuzhiyun  * This function removes existing event handler (parser).
7401*4882a593Smuzhiyun  *
7402*4882a593Smuzhiyun  * If @id is >= 0, then it is used to find the event.
7403*4882a593Smuzhiyun  * else @sys_name and @event_name are used.
7404*4882a593Smuzhiyun  *
7405*4882a593Smuzhiyun  * Returns 0 if handler was removed successfully, -1 if event was not found.
7406*4882a593Smuzhiyun  */
tep_unregister_event_handler(struct tep_handle * tep,int id,const char * sys_name,const char * event_name,tep_event_handler_func func,void * context)7407*4882a593Smuzhiyun int tep_unregister_event_handler(struct tep_handle *tep, int id,
7408*4882a593Smuzhiyun 				 const char *sys_name, const char *event_name,
7409*4882a593Smuzhiyun 				 tep_event_handler_func func, void *context)
7410*4882a593Smuzhiyun {
7411*4882a593Smuzhiyun 	struct tep_event *event;
7412*4882a593Smuzhiyun 	struct event_handler *handle;
7413*4882a593Smuzhiyun 	struct event_handler **next;
7414*4882a593Smuzhiyun 
7415*4882a593Smuzhiyun 	event = search_event(tep, id, sys_name, event_name);
7416*4882a593Smuzhiyun 	if (event == NULL)
7417*4882a593Smuzhiyun 		goto not_found;
7418*4882a593Smuzhiyun 
7419*4882a593Smuzhiyun 	if (event->handler == func && event->context == context) {
7420*4882a593Smuzhiyun 		pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.",
7421*4882a593Smuzhiyun 			event->id, event->system, event->name);
7422*4882a593Smuzhiyun 
7423*4882a593Smuzhiyun 		event->handler = NULL;
7424*4882a593Smuzhiyun 		event->context = NULL;
7425*4882a593Smuzhiyun 		return 0;
7426*4882a593Smuzhiyun 	}
7427*4882a593Smuzhiyun 
7428*4882a593Smuzhiyun not_found:
7429*4882a593Smuzhiyun 	for (next = &tep->handlers; *next; next = &(*next)->next) {
7430*4882a593Smuzhiyun 		handle = *next;
7431*4882a593Smuzhiyun 		if (handle_matches(handle, id, sys_name, event_name,
7432*4882a593Smuzhiyun 				   func, context))
7433*4882a593Smuzhiyun 			break;
7434*4882a593Smuzhiyun 	}
7435*4882a593Smuzhiyun 
7436*4882a593Smuzhiyun 	if (!(*next))
7437*4882a593Smuzhiyun 		return -1;
7438*4882a593Smuzhiyun 
7439*4882a593Smuzhiyun 	*next = handle->next;
7440*4882a593Smuzhiyun 	free_handler(handle);
7441*4882a593Smuzhiyun 
7442*4882a593Smuzhiyun 	return 0;
7443*4882a593Smuzhiyun }
7444*4882a593Smuzhiyun 
7445*4882a593Smuzhiyun /**
7446*4882a593Smuzhiyun  * tep_alloc - create a tep handle
7447*4882a593Smuzhiyun  */
tep_alloc(void)7448*4882a593Smuzhiyun struct tep_handle *tep_alloc(void)
7449*4882a593Smuzhiyun {
7450*4882a593Smuzhiyun 	struct tep_handle *tep = calloc(1, sizeof(*tep));
7451*4882a593Smuzhiyun 
7452*4882a593Smuzhiyun 	if (tep) {
7453*4882a593Smuzhiyun 		tep->ref_count = 1;
7454*4882a593Smuzhiyun 		tep->host_bigendian = tep_is_bigendian();
7455*4882a593Smuzhiyun 	}
7456*4882a593Smuzhiyun 
7457*4882a593Smuzhiyun 	return tep;
7458*4882a593Smuzhiyun }
7459*4882a593Smuzhiyun 
tep_ref(struct tep_handle * tep)7460*4882a593Smuzhiyun void tep_ref(struct tep_handle *tep)
7461*4882a593Smuzhiyun {
7462*4882a593Smuzhiyun 	tep->ref_count++;
7463*4882a593Smuzhiyun }
7464*4882a593Smuzhiyun 
tep_get_ref(struct tep_handle * tep)7465*4882a593Smuzhiyun int tep_get_ref(struct tep_handle *tep)
7466*4882a593Smuzhiyun {
7467*4882a593Smuzhiyun 	if (tep)
7468*4882a593Smuzhiyun 		return tep->ref_count;
7469*4882a593Smuzhiyun 	return 0;
7470*4882a593Smuzhiyun }
7471*4882a593Smuzhiyun 
free_tep_format_field(struct tep_format_field * field)7472*4882a593Smuzhiyun __hidden void free_tep_format_field(struct tep_format_field *field)
7473*4882a593Smuzhiyun {
7474*4882a593Smuzhiyun 	free(field->type);
7475*4882a593Smuzhiyun 	if (field->alias != field->name)
7476*4882a593Smuzhiyun 		free(field->alias);
7477*4882a593Smuzhiyun 	free(field->name);
7478*4882a593Smuzhiyun 	free(field);
7479*4882a593Smuzhiyun }
7480*4882a593Smuzhiyun 
free_format_fields(struct tep_format_field * field)7481*4882a593Smuzhiyun static void free_format_fields(struct tep_format_field *field)
7482*4882a593Smuzhiyun {
7483*4882a593Smuzhiyun 	struct tep_format_field *next;
7484*4882a593Smuzhiyun 
7485*4882a593Smuzhiyun 	while (field) {
7486*4882a593Smuzhiyun 		next = field->next;
7487*4882a593Smuzhiyun 		free_tep_format_field(field);
7488*4882a593Smuzhiyun 		field = next;
7489*4882a593Smuzhiyun 	}
7490*4882a593Smuzhiyun }
7491*4882a593Smuzhiyun 
free_formats(struct tep_format * format)7492*4882a593Smuzhiyun static void free_formats(struct tep_format *format)
7493*4882a593Smuzhiyun {
7494*4882a593Smuzhiyun 	free_format_fields(format->common_fields);
7495*4882a593Smuzhiyun 	free_format_fields(format->fields);
7496*4882a593Smuzhiyun }
7497*4882a593Smuzhiyun 
free_tep_event(struct tep_event * event)7498*4882a593Smuzhiyun __hidden void free_tep_event(struct tep_event *event)
7499*4882a593Smuzhiyun {
7500*4882a593Smuzhiyun 	free(event->name);
7501*4882a593Smuzhiyun 	free(event->system);
7502*4882a593Smuzhiyun 
7503*4882a593Smuzhiyun 	free_formats(&event->format);
7504*4882a593Smuzhiyun 
7505*4882a593Smuzhiyun 	free(event->print_fmt.format);
7506*4882a593Smuzhiyun 	free_args(event->print_fmt.args);
7507*4882a593Smuzhiyun 	free_parse_args(event->print_fmt.print_cache);
7508*4882a593Smuzhiyun 	free(event);
7509*4882a593Smuzhiyun }
7510*4882a593Smuzhiyun 
7511*4882a593Smuzhiyun /**
7512*4882a593Smuzhiyun  * tep_free - free a tep handle
7513*4882a593Smuzhiyun  * @tep: the tep handle to free
7514*4882a593Smuzhiyun  */
tep_free(struct tep_handle * tep)7515*4882a593Smuzhiyun void tep_free(struct tep_handle *tep)
7516*4882a593Smuzhiyun {
7517*4882a593Smuzhiyun 	struct cmdline_list *cmdlist, *cmdnext;
7518*4882a593Smuzhiyun 	struct func_list *funclist, *funcnext;
7519*4882a593Smuzhiyun 	struct printk_list *printklist, *printknext;
7520*4882a593Smuzhiyun 	struct tep_function_handler *func_handler;
7521*4882a593Smuzhiyun 	struct event_handler *handle;
7522*4882a593Smuzhiyun 	int i;
7523*4882a593Smuzhiyun 
7524*4882a593Smuzhiyun 	if (!tep)
7525*4882a593Smuzhiyun 		return;
7526*4882a593Smuzhiyun 
7527*4882a593Smuzhiyun 	cmdlist = tep->cmdlist;
7528*4882a593Smuzhiyun 	funclist = tep->funclist;
7529*4882a593Smuzhiyun 	printklist = tep->printklist;
7530*4882a593Smuzhiyun 
7531*4882a593Smuzhiyun 	tep->ref_count--;
7532*4882a593Smuzhiyun 	if (tep->ref_count)
7533*4882a593Smuzhiyun 		return;
7534*4882a593Smuzhiyun 
7535*4882a593Smuzhiyun 	if (tep->cmdlines) {
7536*4882a593Smuzhiyun 		for (i = 0; i < tep->cmdline_count; i++)
7537*4882a593Smuzhiyun 			free(tep->cmdlines[i].comm);
7538*4882a593Smuzhiyun 		free(tep->cmdlines);
7539*4882a593Smuzhiyun 	}
7540*4882a593Smuzhiyun 
7541*4882a593Smuzhiyun 	while (cmdlist) {
7542*4882a593Smuzhiyun 		cmdnext = cmdlist->next;
7543*4882a593Smuzhiyun 		free(cmdlist->comm);
7544*4882a593Smuzhiyun 		free(cmdlist);
7545*4882a593Smuzhiyun 		cmdlist = cmdnext;
7546*4882a593Smuzhiyun 	}
7547*4882a593Smuzhiyun 
7548*4882a593Smuzhiyun 	if (tep->func_map) {
7549*4882a593Smuzhiyun 		for (i = 0; i < (int)tep->func_count; i++) {
7550*4882a593Smuzhiyun 			free(tep->func_map[i].func);
7551*4882a593Smuzhiyun 			free(tep->func_map[i].mod);
7552*4882a593Smuzhiyun 		}
7553*4882a593Smuzhiyun 		free(tep->func_map);
7554*4882a593Smuzhiyun 	}
7555*4882a593Smuzhiyun 
7556*4882a593Smuzhiyun 	while (funclist) {
7557*4882a593Smuzhiyun 		funcnext = funclist->next;
7558*4882a593Smuzhiyun 		free(funclist->func);
7559*4882a593Smuzhiyun 		free(funclist->mod);
7560*4882a593Smuzhiyun 		free(funclist);
7561*4882a593Smuzhiyun 		funclist = funcnext;
7562*4882a593Smuzhiyun 	}
7563*4882a593Smuzhiyun 
7564*4882a593Smuzhiyun 	while (tep->func_handlers) {
7565*4882a593Smuzhiyun 		func_handler = tep->func_handlers;
7566*4882a593Smuzhiyun 		tep->func_handlers = func_handler->next;
7567*4882a593Smuzhiyun 		free_func_handle(func_handler);
7568*4882a593Smuzhiyun 	}
7569*4882a593Smuzhiyun 
7570*4882a593Smuzhiyun 	if (tep->printk_map) {
7571*4882a593Smuzhiyun 		for (i = 0; i < (int)tep->printk_count; i++)
7572*4882a593Smuzhiyun 			free(tep->printk_map[i].printk);
7573*4882a593Smuzhiyun 		free(tep->printk_map);
7574*4882a593Smuzhiyun 	}
7575*4882a593Smuzhiyun 
7576*4882a593Smuzhiyun 	while (printklist) {
7577*4882a593Smuzhiyun 		printknext = printklist->next;
7578*4882a593Smuzhiyun 		free(printklist->printk);
7579*4882a593Smuzhiyun 		free(printklist);
7580*4882a593Smuzhiyun 		printklist = printknext;
7581*4882a593Smuzhiyun 	}
7582*4882a593Smuzhiyun 
7583*4882a593Smuzhiyun 	for (i = 0; i < tep->nr_events; i++)
7584*4882a593Smuzhiyun 		free_tep_event(tep->events[i]);
7585*4882a593Smuzhiyun 
7586*4882a593Smuzhiyun 	while (tep->handlers) {
7587*4882a593Smuzhiyun 		handle = tep->handlers;
7588*4882a593Smuzhiyun 		tep->handlers = handle->next;
7589*4882a593Smuzhiyun 		free_handler(handle);
7590*4882a593Smuzhiyun 	}
7591*4882a593Smuzhiyun 
7592*4882a593Smuzhiyun 	free(tep->events);
7593*4882a593Smuzhiyun 	free(tep->sort_events);
7594*4882a593Smuzhiyun 	free(tep->func_resolver);
7595*4882a593Smuzhiyun 	free_tep_plugin_paths(tep);
7596*4882a593Smuzhiyun 
7597*4882a593Smuzhiyun 	free(tep);
7598*4882a593Smuzhiyun }
7599*4882a593Smuzhiyun 
tep_unref(struct tep_handle * tep)7600*4882a593Smuzhiyun void tep_unref(struct tep_handle *tep)
7601*4882a593Smuzhiyun {
7602*4882a593Smuzhiyun 	tep_free(tep);
7603*4882a593Smuzhiyun }
7604