1*287e80b3SSadaf Ebrahimi // SPDX-License-Identifier: LGPL-2.1
2*287e80b3SSadaf Ebrahimi /*
3*287e80b3SSadaf Ebrahimi * Copyright (C) 2021 VMware Inc, Steven Rostedt <[email protected]>
4*287e80b3SSadaf Ebrahimi *
5*287e80b3SSadaf Ebrahimi * Updates:
6*287e80b3SSadaf Ebrahimi * Copyright (C) 2021, VMware, Tzvetomir Stoyanov <[email protected]>
7*287e80b3SSadaf Ebrahimi *
8*287e80b3SSadaf Ebrahimi */
9*287e80b3SSadaf Ebrahimi #include <stdio.h>
10*287e80b3SSadaf Ebrahimi #include <stdlib.h>
11*287e80b3SSadaf Ebrahimi #include <dirent.h>
12*287e80b3SSadaf Ebrahimi #include <unistd.h>
13*287e80b3SSadaf Ebrahimi #include <errno.h>
14*287e80b3SSadaf Ebrahimi #include <fcntl.h>
15*287e80b3SSadaf Ebrahimi #include <limits.h>
16*287e80b3SSadaf Ebrahimi
17*287e80b3SSadaf Ebrahimi #include "tracefs.h"
18*287e80b3SSadaf Ebrahimi #include "tracefs-local.h"
19*287e80b3SSadaf Ebrahimi
20*287e80b3SSadaf Ebrahimi #define DYNEVENTS_EVENTS "dynamic_events"
21*287e80b3SSadaf Ebrahimi #define KPROBE_EVENTS "kprobe_events"
22*287e80b3SSadaf Ebrahimi #define UPROBE_EVENTS "uprobe_events"
23*287e80b3SSadaf Ebrahimi #define SYNTH_EVENTS "synthetic_events"
24*287e80b3SSadaf Ebrahimi #define DYNEVENTS_DEFAULT_GROUP "dynamic"
25*287e80b3SSadaf Ebrahimi
26*287e80b3SSadaf Ebrahimi #define EVENT_INDEX(B) (ffs(B) - 1)
27*287e80b3SSadaf Ebrahimi
28*287e80b3SSadaf Ebrahimi struct dyn_events_desc;
29*287e80b3SSadaf Ebrahimi static int dyn_generic_parse(struct dyn_events_desc *,
30*287e80b3SSadaf Ebrahimi const char *, char *, struct tracefs_dynevent **);
31*287e80b3SSadaf Ebrahimi static int dyn_synth_parse(struct dyn_events_desc *,
32*287e80b3SSadaf Ebrahimi const char *, char *, struct tracefs_dynevent **);
33*287e80b3SSadaf Ebrahimi static int dyn_generic_del(struct dyn_events_desc *, struct tracefs_dynevent *);
34*287e80b3SSadaf Ebrahimi static int dyn_synth_del(struct dyn_events_desc *, struct tracefs_dynevent *);
35*287e80b3SSadaf Ebrahimi
36*287e80b3SSadaf Ebrahimi struct dyn_events_desc {
37*287e80b3SSadaf Ebrahimi enum tracefs_dynevent_type type;
38*287e80b3SSadaf Ebrahimi const char *file;
39*287e80b3SSadaf Ebrahimi const char *prefix;
40*287e80b3SSadaf Ebrahimi int (*del)(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn);
41*287e80b3SSadaf Ebrahimi int (*parse)(struct dyn_events_desc *desc, const char *group,
42*287e80b3SSadaf Ebrahimi char *line, struct tracefs_dynevent **ret_dyn);
43*287e80b3SSadaf Ebrahimi } dynevents[] = {
44*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_KPROBE, KPROBE_EVENTS, "p", dyn_generic_del, dyn_generic_parse},
45*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_KRETPROBE, KPROBE_EVENTS, "r", dyn_generic_del, dyn_generic_parse},
46*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_UPROBE, UPROBE_EVENTS, "p", dyn_generic_del, dyn_generic_parse},
47*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_URETPROBE, UPROBE_EVENTS, "r", dyn_generic_del, dyn_generic_parse},
48*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_EPROBE, "", "e", dyn_generic_del, dyn_generic_parse},
49*287e80b3SSadaf Ebrahimi {TRACEFS_DYNEVENT_SYNTH, SYNTH_EVENTS, "", dyn_synth_del, dyn_synth_parse},
50*287e80b3SSadaf Ebrahimi };
51*287e80b3SSadaf Ebrahimi
52*287e80b3SSadaf Ebrahimi
53*287e80b3SSadaf Ebrahimi
dyn_generic_del(struct dyn_events_desc * desc,struct tracefs_dynevent * dyn)54*287e80b3SSadaf Ebrahimi static int dyn_generic_del(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn)
55*287e80b3SSadaf Ebrahimi {
56*287e80b3SSadaf Ebrahimi char *str;
57*287e80b3SSadaf Ebrahimi int ret;
58*287e80b3SSadaf Ebrahimi
59*287e80b3SSadaf Ebrahimi if (dyn->system)
60*287e80b3SSadaf Ebrahimi ret = asprintf(&str, "-:%s/%s", dyn->system, dyn->event);
61*287e80b3SSadaf Ebrahimi else
62*287e80b3SSadaf Ebrahimi ret = asprintf(&str, "-:%s", dyn->event);
63*287e80b3SSadaf Ebrahimi
64*287e80b3SSadaf Ebrahimi if (ret < 0)
65*287e80b3SSadaf Ebrahimi return -1;
66*287e80b3SSadaf Ebrahimi
67*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_append(NULL, desc->file, str);
68*287e80b3SSadaf Ebrahimi free(str);
69*287e80b3SSadaf Ebrahimi
70*287e80b3SSadaf Ebrahimi return ret < 0 ? ret : 0;
71*287e80b3SSadaf Ebrahimi }
72*287e80b3SSadaf Ebrahimi
73*287e80b3SSadaf Ebrahimi /**
74*287e80b3SSadaf Ebrahimi * tracefs_dynevent_free - Free a dynamic event context
75*287e80b3SSadaf Ebrahimi * @devent: Pointer to a dynamic event context
76*287e80b3SSadaf Ebrahimi *
77*287e80b3SSadaf Ebrahimi * The dynamic event, described by this context, is not
78*287e80b3SSadaf Ebrahimi * removed from the system by this API. It only frees the memory.
79*287e80b3SSadaf Ebrahimi */
tracefs_dynevent_free(struct tracefs_dynevent * devent)80*287e80b3SSadaf Ebrahimi void tracefs_dynevent_free(struct tracefs_dynevent *devent)
81*287e80b3SSadaf Ebrahimi {
82*287e80b3SSadaf Ebrahimi if (!devent)
83*287e80b3SSadaf Ebrahimi return;
84*287e80b3SSadaf Ebrahimi free(devent->system);
85*287e80b3SSadaf Ebrahimi free(devent->event);
86*287e80b3SSadaf Ebrahimi free(devent->address);
87*287e80b3SSadaf Ebrahimi free(devent->format);
88*287e80b3SSadaf Ebrahimi free(devent->prefix);
89*287e80b3SSadaf Ebrahimi free(devent->trace_file);
90*287e80b3SSadaf Ebrahimi free(devent);
91*287e80b3SSadaf Ebrahimi }
92*287e80b3SSadaf Ebrahimi
parse_prefix(char * word,char ** prefix,char ** system,char ** name)93*287e80b3SSadaf Ebrahimi static void parse_prefix(char *word, char **prefix, char **system, char **name)
94*287e80b3SSadaf Ebrahimi {
95*287e80b3SSadaf Ebrahimi char *sav;
96*287e80b3SSadaf Ebrahimi
97*287e80b3SSadaf Ebrahimi *prefix = NULL;
98*287e80b3SSadaf Ebrahimi *system = NULL;
99*287e80b3SSadaf Ebrahimi *name = NULL;
100*287e80b3SSadaf Ebrahimi
101*287e80b3SSadaf Ebrahimi *prefix = strtok_r(word, ":", &sav);
102*287e80b3SSadaf Ebrahimi *system = strtok_r(NULL, "/", &sav);
103*287e80b3SSadaf Ebrahimi if (!(*system))
104*287e80b3SSadaf Ebrahimi return;
105*287e80b3SSadaf Ebrahimi
106*287e80b3SSadaf Ebrahimi *name = strtok_r(NULL, " \t", &sav);
107*287e80b3SSadaf Ebrahimi if (!(*name)) {
108*287e80b3SSadaf Ebrahimi *name = *system;
109*287e80b3SSadaf Ebrahimi *system = NULL;
110*287e80b3SSadaf Ebrahimi }
111*287e80b3SSadaf Ebrahimi }
112*287e80b3SSadaf Ebrahimi
113*287e80b3SSadaf Ebrahimi /*
114*287e80b3SSadaf Ebrahimi * Parse lines from dynamic_events, kprobe_events and uprobe_events files
115*287e80b3SSadaf Ebrahimi * PREFIX[:[SYSTEM/]EVENT] [ADDRSS] [FORMAT]
116*287e80b3SSadaf Ebrahimi */
dyn_generic_parse(struct dyn_events_desc * desc,const char * group,char * line,struct tracefs_dynevent ** ret_dyn)117*287e80b3SSadaf Ebrahimi static int dyn_generic_parse(struct dyn_events_desc *desc, const char *group,
118*287e80b3SSadaf Ebrahimi char *line, struct tracefs_dynevent **ret_dyn)
119*287e80b3SSadaf Ebrahimi {
120*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *dyn;
121*287e80b3SSadaf Ebrahimi char *word;
122*287e80b3SSadaf Ebrahimi char *format = NULL;
123*287e80b3SSadaf Ebrahimi char *address = NULL;
124*287e80b3SSadaf Ebrahimi char *system;
125*287e80b3SSadaf Ebrahimi char *prefix;
126*287e80b3SSadaf Ebrahimi char *event;
127*287e80b3SSadaf Ebrahimi char *sav;
128*287e80b3SSadaf Ebrahimi
129*287e80b3SSadaf Ebrahimi if (strncmp(line, desc->prefix, strlen(desc->prefix)))
130*287e80b3SSadaf Ebrahimi return -1;
131*287e80b3SSadaf Ebrahimi
132*287e80b3SSadaf Ebrahimi word = strtok_r(line, " \t", &sav);
133*287e80b3SSadaf Ebrahimi if (!word || *word == '\0')
134*287e80b3SSadaf Ebrahimi return -1;
135*287e80b3SSadaf Ebrahimi
136*287e80b3SSadaf Ebrahimi parse_prefix(word, &prefix, &system, &event);
137*287e80b3SSadaf Ebrahimi if (!prefix)
138*287e80b3SSadaf Ebrahimi return -1;
139*287e80b3SSadaf Ebrahimi
140*287e80b3SSadaf Ebrahimi if (desc->type != TRACEFS_DYNEVENT_SYNTH) {
141*287e80b3SSadaf Ebrahimi address = strtok_r(NULL, " \t", &sav);
142*287e80b3SSadaf Ebrahimi if (!address || *address == '\0')
143*287e80b3SSadaf Ebrahimi return -1;
144*287e80b3SSadaf Ebrahimi }
145*287e80b3SSadaf Ebrahimi
146*287e80b3SSadaf Ebrahimi format = strtok_r(NULL, "", &sav);
147*287e80b3SSadaf Ebrahimi
148*287e80b3SSadaf Ebrahimi /* KPROBEs and UPROBEs share the same prefix, check the format */
149*287e80b3SSadaf Ebrahimi if (desc->type & (TRACEFS_DYNEVENT_UPROBE | TRACEFS_DYNEVENT_URETPROBE)) {
150*287e80b3SSadaf Ebrahimi if (!strchr(address, '/'))
151*287e80b3SSadaf Ebrahimi return -1;
152*287e80b3SSadaf Ebrahimi }
153*287e80b3SSadaf Ebrahimi
154*287e80b3SSadaf Ebrahimi if (group && (!system || strcmp(group, system) != 0))
155*287e80b3SSadaf Ebrahimi return -1;
156*287e80b3SSadaf Ebrahimi
157*287e80b3SSadaf Ebrahimi if (!ret_dyn)
158*287e80b3SSadaf Ebrahimi return 0;
159*287e80b3SSadaf Ebrahimi
160*287e80b3SSadaf Ebrahimi dyn = calloc(1, sizeof(*dyn));
161*287e80b3SSadaf Ebrahimi if (!dyn)
162*287e80b3SSadaf Ebrahimi return -1;
163*287e80b3SSadaf Ebrahimi
164*287e80b3SSadaf Ebrahimi dyn->type = desc->type;
165*287e80b3SSadaf Ebrahimi dyn->trace_file = strdup(desc->file);
166*287e80b3SSadaf Ebrahimi if (!dyn->trace_file)
167*287e80b3SSadaf Ebrahimi goto error;
168*287e80b3SSadaf Ebrahimi
169*287e80b3SSadaf Ebrahimi dyn->prefix = strdup(prefix);
170*287e80b3SSadaf Ebrahimi if (!dyn->prefix)
171*287e80b3SSadaf Ebrahimi goto error;
172*287e80b3SSadaf Ebrahimi
173*287e80b3SSadaf Ebrahimi if (system) {
174*287e80b3SSadaf Ebrahimi dyn->system = strdup(system);
175*287e80b3SSadaf Ebrahimi if (!dyn->system)
176*287e80b3SSadaf Ebrahimi goto error;
177*287e80b3SSadaf Ebrahimi }
178*287e80b3SSadaf Ebrahimi
179*287e80b3SSadaf Ebrahimi if (event) {
180*287e80b3SSadaf Ebrahimi dyn->event = strdup(event);
181*287e80b3SSadaf Ebrahimi if (!dyn->event)
182*287e80b3SSadaf Ebrahimi goto error;
183*287e80b3SSadaf Ebrahimi }
184*287e80b3SSadaf Ebrahimi
185*287e80b3SSadaf Ebrahimi if (address) {
186*287e80b3SSadaf Ebrahimi dyn->address = strdup(address);
187*287e80b3SSadaf Ebrahimi if (!dyn->address)
188*287e80b3SSadaf Ebrahimi goto error;
189*287e80b3SSadaf Ebrahimi }
190*287e80b3SSadaf Ebrahimi
191*287e80b3SSadaf Ebrahimi if (format) {
192*287e80b3SSadaf Ebrahimi dyn->format = strdup(format);
193*287e80b3SSadaf Ebrahimi if (!dyn->format)
194*287e80b3SSadaf Ebrahimi goto error;
195*287e80b3SSadaf Ebrahimi }
196*287e80b3SSadaf Ebrahimi
197*287e80b3SSadaf Ebrahimi *ret_dyn = dyn;
198*287e80b3SSadaf Ebrahimi return 0;
199*287e80b3SSadaf Ebrahimi error:
200*287e80b3SSadaf Ebrahimi tracefs_dynevent_free(dyn);
201*287e80b3SSadaf Ebrahimi return -1;
202*287e80b3SSadaf Ebrahimi }
203*287e80b3SSadaf Ebrahimi
dyn_synth_del(struct dyn_events_desc * desc,struct tracefs_dynevent * dyn)204*287e80b3SSadaf Ebrahimi static int dyn_synth_del(struct dyn_events_desc *desc, struct tracefs_dynevent *dyn)
205*287e80b3SSadaf Ebrahimi {
206*287e80b3SSadaf Ebrahimi char *str;
207*287e80b3SSadaf Ebrahimi int ret;
208*287e80b3SSadaf Ebrahimi
209*287e80b3SSadaf Ebrahimi if (!strcmp(desc->file, DYNEVENTS_EVENTS))
210*287e80b3SSadaf Ebrahimi return dyn_generic_del(desc, dyn);
211*287e80b3SSadaf Ebrahimi
212*287e80b3SSadaf Ebrahimi ret = asprintf(&str, "!%s", dyn->event);
213*287e80b3SSadaf Ebrahimi if (ret < 0)
214*287e80b3SSadaf Ebrahimi return -1;
215*287e80b3SSadaf Ebrahimi
216*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_append(NULL, desc->file, str);
217*287e80b3SSadaf Ebrahimi free(str);
218*287e80b3SSadaf Ebrahimi
219*287e80b3SSadaf Ebrahimi return ret < 0 ? ret : 0;
220*287e80b3SSadaf Ebrahimi }
221*287e80b3SSadaf Ebrahimi
222*287e80b3SSadaf Ebrahimi /*
223*287e80b3SSadaf Ebrahimi * Parse lines from synthetic_events file
224*287e80b3SSadaf Ebrahimi * EVENT ARG [ARG]
225*287e80b3SSadaf Ebrahimi */
dyn_synth_parse(struct dyn_events_desc * desc,const char * group,char * line,struct tracefs_dynevent ** ret_dyn)226*287e80b3SSadaf Ebrahimi static int dyn_synth_parse(struct dyn_events_desc *desc, const char *group,
227*287e80b3SSadaf Ebrahimi char *line, struct tracefs_dynevent **ret_dyn)
228*287e80b3SSadaf Ebrahimi {
229*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *dyn;
230*287e80b3SSadaf Ebrahimi char *format;
231*287e80b3SSadaf Ebrahimi char *event;
232*287e80b3SSadaf Ebrahimi char *sav;
233*287e80b3SSadaf Ebrahimi
234*287e80b3SSadaf Ebrahimi if (!strcmp(desc->file, DYNEVENTS_EVENTS))
235*287e80b3SSadaf Ebrahimi return dyn_generic_parse(desc, group, line, ret_dyn);
236*287e80b3SSadaf Ebrahimi
237*287e80b3SSadaf Ebrahimi /* synthetic_events file has slightly different syntax */
238*287e80b3SSadaf Ebrahimi event = strtok_r(line, " \t", &sav);
239*287e80b3SSadaf Ebrahimi if (!event || *event == '\0')
240*287e80b3SSadaf Ebrahimi return -1;
241*287e80b3SSadaf Ebrahimi
242*287e80b3SSadaf Ebrahimi format = strtok_r(NULL, "", &sav);
243*287e80b3SSadaf Ebrahimi if (!format || *format == '\0')
244*287e80b3SSadaf Ebrahimi return -1;
245*287e80b3SSadaf Ebrahimi
246*287e80b3SSadaf Ebrahimi if (!ret_dyn)
247*287e80b3SSadaf Ebrahimi return 0;
248*287e80b3SSadaf Ebrahimi
249*287e80b3SSadaf Ebrahimi dyn = calloc(1, sizeof(*dyn));
250*287e80b3SSadaf Ebrahimi if (!dyn)
251*287e80b3SSadaf Ebrahimi return -1;
252*287e80b3SSadaf Ebrahimi
253*287e80b3SSadaf Ebrahimi dyn->type = desc->type;
254*287e80b3SSadaf Ebrahimi dyn->trace_file = strdup(desc->file);
255*287e80b3SSadaf Ebrahimi if (!dyn->trace_file)
256*287e80b3SSadaf Ebrahimi goto error;
257*287e80b3SSadaf Ebrahimi
258*287e80b3SSadaf Ebrahimi dyn->event = strdup(event);
259*287e80b3SSadaf Ebrahimi if (!dyn->event)
260*287e80b3SSadaf Ebrahimi goto error;
261*287e80b3SSadaf Ebrahimi
262*287e80b3SSadaf Ebrahimi dyn->format = strdup(format+1);
263*287e80b3SSadaf Ebrahimi if (!dyn->format)
264*287e80b3SSadaf Ebrahimi goto error;
265*287e80b3SSadaf Ebrahimi
266*287e80b3SSadaf Ebrahimi *ret_dyn = dyn;
267*287e80b3SSadaf Ebrahimi return 0;
268*287e80b3SSadaf Ebrahimi error:
269*287e80b3SSadaf Ebrahimi tracefs_dynevent_free(dyn);
270*287e80b3SSadaf Ebrahimi return -1;
271*287e80b3SSadaf Ebrahimi }
272*287e80b3SSadaf Ebrahimi
init_devent_desc(void)273*287e80b3SSadaf Ebrahimi static void init_devent_desc(void)
274*287e80b3SSadaf Ebrahimi {
275*287e80b3SSadaf Ebrahimi int i;
276*287e80b3SSadaf Ebrahimi
277*287e80b3SSadaf Ebrahimi BUILD_BUG_ON(ARRAY_SIZE(dynevents) != EVENT_INDEX(TRACEFS_DYNEVENT_MAX));
278*287e80b3SSadaf Ebrahimi
279*287e80b3SSadaf Ebrahimi if (!tracefs_file_exists(NULL, DYNEVENTS_EVENTS))
280*287e80b3SSadaf Ebrahimi return;
281*287e80b3SSadaf Ebrahimi
282*287e80b3SSadaf Ebrahimi /* Use ftrace dynamic_events, if available */
283*287e80b3SSadaf Ebrahimi for (i = 0; i < EVENT_INDEX(TRACEFS_DYNEVENT_MAX); i++)
284*287e80b3SSadaf Ebrahimi dynevents[i].file = DYNEVENTS_EVENTS;
285*287e80b3SSadaf Ebrahimi
286*287e80b3SSadaf Ebrahimi dynevents[EVENT_INDEX(TRACEFS_DYNEVENT_SYNTH)].prefix = "s";
287*287e80b3SSadaf Ebrahimi }
288*287e80b3SSadaf Ebrahimi
get_devent_desc(enum tracefs_dynevent_type type)289*287e80b3SSadaf Ebrahimi static struct dyn_events_desc *get_devent_desc(enum tracefs_dynevent_type type)
290*287e80b3SSadaf Ebrahimi {
291*287e80b3SSadaf Ebrahimi
292*287e80b3SSadaf Ebrahimi static bool init;
293*287e80b3SSadaf Ebrahimi
294*287e80b3SSadaf Ebrahimi if (type >= TRACEFS_DYNEVENT_MAX)
295*287e80b3SSadaf Ebrahimi return NULL;
296*287e80b3SSadaf Ebrahimi
297*287e80b3SSadaf Ebrahimi if (!init) {
298*287e80b3SSadaf Ebrahimi init_devent_desc();
299*287e80b3SSadaf Ebrahimi init = true;
300*287e80b3SSadaf Ebrahimi }
301*287e80b3SSadaf Ebrahimi
302*287e80b3SSadaf Ebrahimi return &dynevents[EVENT_INDEX(type)];
303*287e80b3SSadaf Ebrahimi }
304*287e80b3SSadaf Ebrahimi
305*287e80b3SSadaf Ebrahimi /**
306*287e80b3SSadaf Ebrahimi * dynevent_alloc - Allocate new dynamic event
307*287e80b3SSadaf Ebrahimi * @type: Type of the dynamic event
308*287e80b3SSadaf Ebrahimi * @system: The system name (NULL for the default dynamic)
309*287e80b3SSadaf Ebrahimi * @event: Name of the event
310*287e80b3SSadaf Ebrahimi * @addr: The function and offset (or address) to insert the probe
311*287e80b3SSadaf Ebrahimi * @format: The format string to define the probe.
312*287e80b3SSadaf Ebrahimi *
313*287e80b3SSadaf Ebrahimi * Allocate a dynamic event context that will be in the @system group
314*287e80b3SSadaf Ebrahimi * (or dynamic if @system is NULL). Have the name of @event and
315*287e80b3SSadaf Ebrahimi * will be associated to @addr, if applicable for that event type
316*287e80b3SSadaf Ebrahimi * (function name, with or without offset, or a address). And the @format will
317*287e80b3SSadaf Ebrahimi * define the format of the kprobe.
318*287e80b3SSadaf Ebrahimi * The dynamic event is not created in the system.
319*287e80b3SSadaf Ebrahimi *
320*287e80b3SSadaf Ebrahimi * Return a pointer to a dynamic event context on success, or NULL on error.
321*287e80b3SSadaf Ebrahimi * The returned pointer must be freed with tracefs_dynevent_free()
322*287e80b3SSadaf Ebrahimi *
323*287e80b3SSadaf Ebrahimi * errno will be set to EINVAL if event is NULL.
324*287e80b3SSadaf Ebrahimi */
325*287e80b3SSadaf Ebrahimi __hidden struct tracefs_dynevent *
dynevent_alloc(enum tracefs_dynevent_type type,const char * system,const char * event,const char * address,const char * format)326*287e80b3SSadaf Ebrahimi dynevent_alloc(enum tracefs_dynevent_type type, const char *system,
327*287e80b3SSadaf Ebrahimi const char *event, const char *address, const char *format)
328*287e80b3SSadaf Ebrahimi {
329*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *devent;
330*287e80b3SSadaf Ebrahimi struct dyn_events_desc *desc;
331*287e80b3SSadaf Ebrahimi
332*287e80b3SSadaf Ebrahimi if (!event) {
333*287e80b3SSadaf Ebrahimi errno = EINVAL;
334*287e80b3SSadaf Ebrahimi return NULL;
335*287e80b3SSadaf Ebrahimi }
336*287e80b3SSadaf Ebrahimi
337*287e80b3SSadaf Ebrahimi desc = get_devent_desc(type);
338*287e80b3SSadaf Ebrahimi if (!desc || !desc->file) {
339*287e80b3SSadaf Ebrahimi errno = ENOTSUP;
340*287e80b3SSadaf Ebrahimi return NULL;
341*287e80b3SSadaf Ebrahimi }
342*287e80b3SSadaf Ebrahimi
343*287e80b3SSadaf Ebrahimi devent = calloc(1, sizeof(*devent));
344*287e80b3SSadaf Ebrahimi if (!devent)
345*287e80b3SSadaf Ebrahimi return NULL;
346*287e80b3SSadaf Ebrahimi
347*287e80b3SSadaf Ebrahimi devent->type = type;
348*287e80b3SSadaf Ebrahimi devent->trace_file = strdup(desc->file);
349*287e80b3SSadaf Ebrahimi if (!devent->trace_file)
350*287e80b3SSadaf Ebrahimi goto err;
351*287e80b3SSadaf Ebrahimi
352*287e80b3SSadaf Ebrahimi if (!system)
353*287e80b3SSadaf Ebrahimi system = DYNEVENTS_DEFAULT_GROUP;
354*287e80b3SSadaf Ebrahimi devent->system = strdup(system);
355*287e80b3SSadaf Ebrahimi if (!devent->system)
356*287e80b3SSadaf Ebrahimi goto err;
357*287e80b3SSadaf Ebrahimi
358*287e80b3SSadaf Ebrahimi devent->event = strdup(event);
359*287e80b3SSadaf Ebrahimi if (!devent->event)
360*287e80b3SSadaf Ebrahimi goto err;
361*287e80b3SSadaf Ebrahimi
362*287e80b3SSadaf Ebrahimi devent->prefix = strdup(desc->prefix);
363*287e80b3SSadaf Ebrahimi if (!devent->prefix)
364*287e80b3SSadaf Ebrahimi goto err;
365*287e80b3SSadaf Ebrahimi
366*287e80b3SSadaf Ebrahimi if (address) {
367*287e80b3SSadaf Ebrahimi devent->address = strdup(address);
368*287e80b3SSadaf Ebrahimi if (!devent->address)
369*287e80b3SSadaf Ebrahimi goto err;
370*287e80b3SSadaf Ebrahimi }
371*287e80b3SSadaf Ebrahimi if (format) {
372*287e80b3SSadaf Ebrahimi devent->format = strdup(format);
373*287e80b3SSadaf Ebrahimi if (!devent->format)
374*287e80b3SSadaf Ebrahimi goto err;
375*287e80b3SSadaf Ebrahimi }
376*287e80b3SSadaf Ebrahimi
377*287e80b3SSadaf Ebrahimi return devent;
378*287e80b3SSadaf Ebrahimi err:
379*287e80b3SSadaf Ebrahimi tracefs_dynevent_free(devent);
380*287e80b3SSadaf Ebrahimi return NULL;
381*287e80b3SSadaf Ebrahimi }
382*287e80b3SSadaf Ebrahimi
383*287e80b3SSadaf Ebrahimi /**
384*287e80b3SSadaf Ebrahimi * tracefs_dynevent_create - Create a dynamic event in the system
385*287e80b3SSadaf Ebrahimi * @devent: Pointer to a dynamic event context, describing the event
386*287e80b3SSadaf Ebrahimi *
387*287e80b3SSadaf Ebrahimi * Return 0 on success, or -1 on error.
388*287e80b3SSadaf Ebrahimi */
tracefs_dynevent_create(struct tracefs_dynevent * devent)389*287e80b3SSadaf Ebrahimi int tracefs_dynevent_create(struct tracefs_dynevent *devent)
390*287e80b3SSadaf Ebrahimi {
391*287e80b3SSadaf Ebrahimi char *str;
392*287e80b3SSadaf Ebrahimi int ret;
393*287e80b3SSadaf Ebrahimi
394*287e80b3SSadaf Ebrahimi if (!devent)
395*287e80b3SSadaf Ebrahimi return -1;
396*287e80b3SSadaf Ebrahimi
397*287e80b3SSadaf Ebrahimi if (devent->system && devent->system[0])
398*287e80b3SSadaf Ebrahimi ret = asprintf(&str, "%s%s%s/%s %s %s\n",
399*287e80b3SSadaf Ebrahimi devent->prefix, strlen(devent->prefix) ? ":" : "",
400*287e80b3SSadaf Ebrahimi devent->system, devent->event,
401*287e80b3SSadaf Ebrahimi devent->address ? devent->address : "",
402*287e80b3SSadaf Ebrahimi devent->format ? devent->format : "");
403*287e80b3SSadaf Ebrahimi else
404*287e80b3SSadaf Ebrahimi ret = asprintf(&str, "%s%s%s %s %s\n",
405*287e80b3SSadaf Ebrahimi devent->prefix, strlen(devent->prefix) ? ":" : "",
406*287e80b3SSadaf Ebrahimi devent->event,
407*287e80b3SSadaf Ebrahimi devent->address ? devent->address : "",
408*287e80b3SSadaf Ebrahimi devent->format ? devent->format : "");
409*287e80b3SSadaf Ebrahimi if (ret < 0)
410*287e80b3SSadaf Ebrahimi return -1;
411*287e80b3SSadaf Ebrahimi
412*287e80b3SSadaf Ebrahimi ret = tracefs_instance_file_append(NULL, devent->trace_file, str);
413*287e80b3SSadaf Ebrahimi free(str);
414*287e80b3SSadaf Ebrahimi
415*287e80b3SSadaf Ebrahimi return ret < 0 ? ret : 0;
416*287e80b3SSadaf Ebrahimi }
417*287e80b3SSadaf Ebrahimi
disable_events(const char * system,const char * event,char ** list)418*287e80b3SSadaf Ebrahimi static void disable_events(const char *system, const char *event,
419*287e80b3SSadaf Ebrahimi char **list)
420*287e80b3SSadaf Ebrahimi {
421*287e80b3SSadaf Ebrahimi struct tracefs_instance *instance;
422*287e80b3SSadaf Ebrahimi int i;
423*287e80b3SSadaf Ebrahimi
424*287e80b3SSadaf Ebrahimi /*
425*287e80b3SSadaf Ebrahimi * Note, this will not fail even on error.
426*287e80b3SSadaf Ebrahimi * That is because even if something fails, it may still
427*287e80b3SSadaf Ebrahimi * work enough to clear the kprobes. If that's the case
428*287e80b3SSadaf Ebrahimi * the clearing after the loop will succeed and the function
429*287e80b3SSadaf Ebrahimi * is a success, even though other parts had failed. If
430*287e80b3SSadaf Ebrahimi * one of the kprobe events is enabled in one of the
431*287e80b3SSadaf Ebrahimi * instances that fail, then the clearing will fail too
432*287e80b3SSadaf Ebrahimi * and the function will return an error.
433*287e80b3SSadaf Ebrahimi */
434*287e80b3SSadaf Ebrahimi
435*287e80b3SSadaf Ebrahimi tracefs_event_disable(NULL, system, event);
436*287e80b3SSadaf Ebrahimi /* No need to test results */
437*287e80b3SSadaf Ebrahimi
438*287e80b3SSadaf Ebrahimi if (!list)
439*287e80b3SSadaf Ebrahimi return;
440*287e80b3SSadaf Ebrahimi
441*287e80b3SSadaf Ebrahimi for (i = 0; list[i]; i++) {
442*287e80b3SSadaf Ebrahimi instance = tracefs_instance_alloc(NULL, list[i]);
443*287e80b3SSadaf Ebrahimi /* If this fails, try the next one */
444*287e80b3SSadaf Ebrahimi if (!instance)
445*287e80b3SSadaf Ebrahimi continue;
446*287e80b3SSadaf Ebrahimi tracefs_event_disable(instance, system, event);
447*287e80b3SSadaf Ebrahimi tracefs_instance_free(instance);
448*287e80b3SSadaf Ebrahimi }
449*287e80b3SSadaf Ebrahimi }
450*287e80b3SSadaf Ebrahimi
451*287e80b3SSadaf Ebrahimi /**
452*287e80b3SSadaf Ebrahimi * tracefs_dynevent_destroy - Remove a dynamic event from the system
453*287e80b3SSadaf Ebrahimi * @devent: A dynamic event context, describing the dynamic event that will be deleted.
454*287e80b3SSadaf Ebrahimi * @force: Will attempt to disable all events before removing them.
455*287e80b3SSadaf Ebrahimi *
456*287e80b3SSadaf Ebrahimi * The dynamic event context is not freed by this API. It only removes the event from the system.
457*287e80b3SSadaf Ebrahimi * If there are any enabled events, and @force is not set, then it will error with -1 and errno
458*287e80b3SSadaf Ebrahimi * to be EBUSY.
459*287e80b3SSadaf Ebrahimi *
460*287e80b3SSadaf Ebrahimi * Return 0 on success, or -1 on error.
461*287e80b3SSadaf Ebrahimi */
tracefs_dynevent_destroy(struct tracefs_dynevent * devent,bool force)462*287e80b3SSadaf Ebrahimi int tracefs_dynevent_destroy(struct tracefs_dynevent *devent, bool force)
463*287e80b3SSadaf Ebrahimi {
464*287e80b3SSadaf Ebrahimi struct dyn_events_desc *desc;
465*287e80b3SSadaf Ebrahimi char **instance_list;
466*287e80b3SSadaf Ebrahimi
467*287e80b3SSadaf Ebrahimi if (!devent)
468*287e80b3SSadaf Ebrahimi return -1;
469*287e80b3SSadaf Ebrahimi
470*287e80b3SSadaf Ebrahimi if (force) {
471*287e80b3SSadaf Ebrahimi instance_list = tracefs_instances(NULL);
472*287e80b3SSadaf Ebrahimi disable_events(devent->system, devent->event, instance_list);
473*287e80b3SSadaf Ebrahimi tracefs_list_free(instance_list);
474*287e80b3SSadaf Ebrahimi }
475*287e80b3SSadaf Ebrahimi
476*287e80b3SSadaf Ebrahimi desc = get_devent_desc(devent->type);
477*287e80b3SSadaf Ebrahimi if (!desc)
478*287e80b3SSadaf Ebrahimi return -1;
479*287e80b3SSadaf Ebrahimi
480*287e80b3SSadaf Ebrahimi return desc->del(desc, devent);
481*287e80b3SSadaf Ebrahimi }
482*287e80b3SSadaf Ebrahimi
get_all_dynevents(enum tracefs_dynevent_type type,const char * system,struct tracefs_dynevent *** ret_all)483*287e80b3SSadaf Ebrahimi static int get_all_dynevents(enum tracefs_dynevent_type type, const char *system,
484*287e80b3SSadaf Ebrahimi struct tracefs_dynevent ***ret_all)
485*287e80b3SSadaf Ebrahimi {
486*287e80b3SSadaf Ebrahimi struct dyn_events_desc *desc;
487*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *devent, **tmp, **all = NULL;
488*287e80b3SSadaf Ebrahimi char *content;
489*287e80b3SSadaf Ebrahimi int count = 0;
490*287e80b3SSadaf Ebrahimi char *line;
491*287e80b3SSadaf Ebrahimi char *next;
492*287e80b3SSadaf Ebrahimi int ret;
493*287e80b3SSadaf Ebrahimi
494*287e80b3SSadaf Ebrahimi desc = get_devent_desc(type);
495*287e80b3SSadaf Ebrahimi if (!desc)
496*287e80b3SSadaf Ebrahimi return -1;
497*287e80b3SSadaf Ebrahimi
498*287e80b3SSadaf Ebrahimi content = tracefs_instance_file_read(NULL, desc->file, NULL);
499*287e80b3SSadaf Ebrahimi if (!content)
500*287e80b3SSadaf Ebrahimi return -1;
501*287e80b3SSadaf Ebrahimi
502*287e80b3SSadaf Ebrahimi line = content;
503*287e80b3SSadaf Ebrahimi do {
504*287e80b3SSadaf Ebrahimi next = strchr(line, '\n');
505*287e80b3SSadaf Ebrahimi if (next)
506*287e80b3SSadaf Ebrahimi *next = '\0';
507*287e80b3SSadaf Ebrahimi ret = desc->parse(desc, system, line, ret_all ? &devent : NULL);
508*287e80b3SSadaf Ebrahimi if (!ret) {
509*287e80b3SSadaf Ebrahimi if (ret_all) {
510*287e80b3SSadaf Ebrahimi tmp = realloc(all, (count + 1) * sizeof(*tmp));
511*287e80b3SSadaf Ebrahimi if (!tmp)
512*287e80b3SSadaf Ebrahimi goto error;
513*287e80b3SSadaf Ebrahimi all = tmp;
514*287e80b3SSadaf Ebrahimi all[count] = devent;
515*287e80b3SSadaf Ebrahimi }
516*287e80b3SSadaf Ebrahimi count++;
517*287e80b3SSadaf Ebrahimi }
518*287e80b3SSadaf Ebrahimi line = next + 1;
519*287e80b3SSadaf Ebrahimi } while (next);
520*287e80b3SSadaf Ebrahimi
521*287e80b3SSadaf Ebrahimi free(content);
522*287e80b3SSadaf Ebrahimi if (ret_all)
523*287e80b3SSadaf Ebrahimi *ret_all = all;
524*287e80b3SSadaf Ebrahimi return count;
525*287e80b3SSadaf Ebrahimi
526*287e80b3SSadaf Ebrahimi error:
527*287e80b3SSadaf Ebrahimi free(content);
528*287e80b3SSadaf Ebrahimi free(all);
529*287e80b3SSadaf Ebrahimi return -1;
530*287e80b3SSadaf Ebrahimi }
531*287e80b3SSadaf Ebrahimi
532*287e80b3SSadaf Ebrahimi /**
533*287e80b3SSadaf Ebrahimi * tracefs_dynevent_list_free - Deletes an array of pointers to dynamic event contexts
534*287e80b3SSadaf Ebrahimi * @events: An array of pointers to dynamic event contexts. The last element of the array
535*287e80b3SSadaf Ebrahimi * must be a NULL pointer.
536*287e80b3SSadaf Ebrahimi */
tracefs_dynevent_list_free(struct tracefs_dynevent ** events)537*287e80b3SSadaf Ebrahimi void tracefs_dynevent_list_free(struct tracefs_dynevent **events)
538*287e80b3SSadaf Ebrahimi {
539*287e80b3SSadaf Ebrahimi int i;
540*287e80b3SSadaf Ebrahimi
541*287e80b3SSadaf Ebrahimi if (!events)
542*287e80b3SSadaf Ebrahimi return;
543*287e80b3SSadaf Ebrahimi
544*287e80b3SSadaf Ebrahimi for (i = 0; events[i]; i++)
545*287e80b3SSadaf Ebrahimi tracefs_dynevent_free(events[i]);
546*287e80b3SSadaf Ebrahimi
547*287e80b3SSadaf Ebrahimi free(events);
548*287e80b3SSadaf Ebrahimi }
549*287e80b3SSadaf Ebrahimi
550*287e80b3SSadaf Ebrahimi /**
551*287e80b3SSadaf Ebrahimi * tracefs_dynevent_get_all - return an array of pointers to dynamic events of given types
552*287e80b3SSadaf Ebrahimi * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types
553*287e80b3SSadaf Ebrahimi * are considered.
554*287e80b3SSadaf Ebrahimi * @system: Get events from that system only. If @system is NULL, events from all systems
555*287e80b3SSadaf Ebrahimi * are returned.
556*287e80b3SSadaf Ebrahimi *
557*287e80b3SSadaf Ebrahimi * Returns an array of pointers to dynamic events of given types that exist in the system.
558*287e80b3SSadaf Ebrahimi * The array must be freed with tracefs_dynevent_list_free(). If there are no events a NULL
559*287e80b3SSadaf Ebrahimi * pointer is returned.
560*287e80b3SSadaf Ebrahimi */
561*287e80b3SSadaf Ebrahimi struct tracefs_dynevent **
tracefs_dynevent_get_all(unsigned int types,const char * system)562*287e80b3SSadaf Ebrahimi tracefs_dynevent_get_all(unsigned int types, const char *system)
563*287e80b3SSadaf Ebrahimi {
564*287e80b3SSadaf Ebrahimi struct tracefs_dynevent **events, **tmp, **all_events = NULL;
565*287e80b3SSadaf Ebrahimi int count, all = 0;
566*287e80b3SSadaf Ebrahimi int i;
567*287e80b3SSadaf Ebrahimi
568*287e80b3SSadaf Ebrahimi for (i = 1; i < TRACEFS_DYNEVENT_MAX; i <<= 1) {
569*287e80b3SSadaf Ebrahimi if (types) {
570*287e80b3SSadaf Ebrahimi if (i > types)
571*287e80b3SSadaf Ebrahimi break;
572*287e80b3SSadaf Ebrahimi if (!(types & i))
573*287e80b3SSadaf Ebrahimi continue;
574*287e80b3SSadaf Ebrahimi }
575*287e80b3SSadaf Ebrahimi count = get_all_dynevents(i, system, &events);
576*287e80b3SSadaf Ebrahimi if (count > 0) {
577*287e80b3SSadaf Ebrahimi tmp = realloc(all_events, (all + count + 1) * sizeof(*tmp));
578*287e80b3SSadaf Ebrahimi if (!tmp)
579*287e80b3SSadaf Ebrahimi goto error;
580*287e80b3SSadaf Ebrahimi all_events = tmp;
581*287e80b3SSadaf Ebrahimi memcpy(all_events + all, events, count * sizeof(*events));
582*287e80b3SSadaf Ebrahimi all += count;
583*287e80b3SSadaf Ebrahimi /* Add a NULL pointer at the end */
584*287e80b3SSadaf Ebrahimi all_events[all] = NULL;
585*287e80b3SSadaf Ebrahimi free(events);
586*287e80b3SSadaf Ebrahimi }
587*287e80b3SSadaf Ebrahimi }
588*287e80b3SSadaf Ebrahimi
589*287e80b3SSadaf Ebrahimi return all_events;
590*287e80b3SSadaf Ebrahimi
591*287e80b3SSadaf Ebrahimi error:
592*287e80b3SSadaf Ebrahimi if (all_events) {
593*287e80b3SSadaf Ebrahimi for (i = 0; i < all; i++)
594*287e80b3SSadaf Ebrahimi free(all_events[i]);
595*287e80b3SSadaf Ebrahimi free(all_events);
596*287e80b3SSadaf Ebrahimi }
597*287e80b3SSadaf Ebrahimi return NULL;
598*287e80b3SSadaf Ebrahimi }
599*287e80b3SSadaf Ebrahimi
600*287e80b3SSadaf Ebrahimi /**
601*287e80b3SSadaf Ebrahimi * tracefs_dynevent_get - return a single dynamic event if it exists
602*287e80b3SSadaf Ebrahimi * @type; Dynamic event type
603*287e80b3SSadaf Ebrahimi * @system: Get events from that system only. May be NULL.
604*287e80b3SSadaf Ebrahimi * @event: Get event of the system type (may not be NULL)
605*287e80b3SSadaf Ebrahimi *
606*287e80b3SSadaf Ebrahimi * Returns the dynamic event of the given @type and @system for with the @event
607*287e80b3SSadaf Ebrahimi * name. If @system is NULL, it will return the first dynamic event that it finds
608*287e80b3SSadaf Ebrahimi * that matches the @event name.
609*287e80b3SSadaf Ebrahimi *
610*287e80b3SSadaf Ebrahimi * The returned event must be freed with tracefs_dynevent_free().
611*287e80b3SSadaf Ebrahimi * NULL is returned if no event match is found, or other error.
612*287e80b3SSadaf Ebrahimi */
613*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *
tracefs_dynevent_get(enum tracefs_dynevent_type type,const char * system,const char * event)614*287e80b3SSadaf Ebrahimi tracefs_dynevent_get(enum tracefs_dynevent_type type, const char *system,
615*287e80b3SSadaf Ebrahimi const char *event)
616*287e80b3SSadaf Ebrahimi {
617*287e80b3SSadaf Ebrahimi struct tracefs_dynevent **events;
618*287e80b3SSadaf Ebrahimi struct tracefs_dynevent *devent = NULL;
619*287e80b3SSadaf Ebrahimi int count;
620*287e80b3SSadaf Ebrahimi int i;
621*287e80b3SSadaf Ebrahimi
622*287e80b3SSadaf Ebrahimi if (!event) {
623*287e80b3SSadaf Ebrahimi errno = -EINVAL;
624*287e80b3SSadaf Ebrahimi return NULL;
625*287e80b3SSadaf Ebrahimi }
626*287e80b3SSadaf Ebrahimi
627*287e80b3SSadaf Ebrahimi count = get_all_dynevents(type, system, &events);
628*287e80b3SSadaf Ebrahimi if (count <= 0)
629*287e80b3SSadaf Ebrahimi return NULL;
630*287e80b3SSadaf Ebrahimi
631*287e80b3SSadaf Ebrahimi for (i = 0; i < count; i++) {
632*287e80b3SSadaf Ebrahimi if (strcmp(events[i]->event, event) == 0)
633*287e80b3SSadaf Ebrahimi break;
634*287e80b3SSadaf Ebrahimi }
635*287e80b3SSadaf Ebrahimi if (i < count) {
636*287e80b3SSadaf Ebrahimi devent = events[i];
637*287e80b3SSadaf Ebrahimi events[i] = NULL;
638*287e80b3SSadaf Ebrahimi }
639*287e80b3SSadaf Ebrahimi
640*287e80b3SSadaf Ebrahimi tracefs_dynevent_list_free(events);
641*287e80b3SSadaf Ebrahimi
642*287e80b3SSadaf Ebrahimi return devent;
643*287e80b3SSadaf Ebrahimi }
644*287e80b3SSadaf Ebrahimi
645*287e80b3SSadaf Ebrahimi /**
646*287e80b3SSadaf Ebrahimi * tracefs_dynevent_destroy_all - removes all dynamic events of given types from the system
647*287e80b3SSadaf Ebrahimi * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types
648*287e80b3SSadaf Ebrahimi * are considered.
649*287e80b3SSadaf Ebrahimi * @force: Will attempt to disable all events before removing them.
650*287e80b3SSadaf Ebrahimi *
651*287e80b3SSadaf Ebrahimi * Will remove all dynamic events of the given types from the system. If there are any enabled
652*287e80b3SSadaf Ebrahimi * events, and @force is not set, then the removal of these will fail. If @force is set, then
653*287e80b3SSadaf Ebrahimi * it will attempt to disable all the events in all instances before removing them.
654*287e80b3SSadaf Ebrahimi *
655*287e80b3SSadaf Ebrahimi * Returns zero if all requested events are removed successfully, or -1 if some of them are not
656*287e80b3SSadaf Ebrahimi * removed.
657*287e80b3SSadaf Ebrahimi */
tracefs_dynevent_destroy_all(unsigned int types,bool force)658*287e80b3SSadaf Ebrahimi int tracefs_dynevent_destroy_all(unsigned int types, bool force)
659*287e80b3SSadaf Ebrahimi {
660*287e80b3SSadaf Ebrahimi struct tracefs_dynevent **all;
661*287e80b3SSadaf Ebrahimi int ret = 0;
662*287e80b3SSadaf Ebrahimi int i;
663*287e80b3SSadaf Ebrahimi
664*287e80b3SSadaf Ebrahimi all = tracefs_dynevent_get_all(types, NULL);
665*287e80b3SSadaf Ebrahimi if (!all)
666*287e80b3SSadaf Ebrahimi return 0;
667*287e80b3SSadaf Ebrahimi
668*287e80b3SSadaf Ebrahimi for (i = 0; all[i]; i++) {
669*287e80b3SSadaf Ebrahimi if (tracefs_dynevent_destroy(all[i], force))
670*287e80b3SSadaf Ebrahimi ret = -1;
671*287e80b3SSadaf Ebrahimi }
672*287e80b3SSadaf Ebrahimi
673*287e80b3SSadaf Ebrahimi tracefs_dynevent_list_free(all);
674*287e80b3SSadaf Ebrahimi
675*287e80b3SSadaf Ebrahimi return ret;
676*287e80b3SSadaf Ebrahimi }
677*287e80b3SSadaf Ebrahimi
678*287e80b3SSadaf Ebrahimi /**
679*287e80b3SSadaf Ebrahimi * dynevent_get_count - Count dynamic events of given types and system
680*287e80b3SSadaf Ebrahimi * @types: Dynamic event type, or bitmask of dynamic event types. If 0 is passed, all types
681*287e80b3SSadaf Ebrahimi * are considered.
682*287e80b3SSadaf Ebrahimi * @system: Count events from that system only. If @system is NULL, events from all systems
683*287e80b3SSadaf Ebrahimi * are counted.
684*287e80b3SSadaf Ebrahimi *
685*287e80b3SSadaf Ebrahimi * Return the count of requested dynamic events
686*287e80b3SSadaf Ebrahimi */
dynevent_get_count(unsigned int types,const char * system)687*287e80b3SSadaf Ebrahimi __hidden int dynevent_get_count(unsigned int types, const char *system)
688*287e80b3SSadaf Ebrahimi {
689*287e80b3SSadaf Ebrahimi int count, all = 0;
690*287e80b3SSadaf Ebrahimi int i;
691*287e80b3SSadaf Ebrahimi
692*287e80b3SSadaf Ebrahimi for (i = 1; i < TRACEFS_DYNEVENT_MAX; i <<= 1) {
693*287e80b3SSadaf Ebrahimi if (types) {
694*287e80b3SSadaf Ebrahimi if (i > types)
695*287e80b3SSadaf Ebrahimi break;
696*287e80b3SSadaf Ebrahimi if (!(types & i))
697*287e80b3SSadaf Ebrahimi continue;
698*287e80b3SSadaf Ebrahimi }
699*287e80b3SSadaf Ebrahimi count = get_all_dynevents(i, system, NULL);
700*287e80b3SSadaf Ebrahimi if (count > 0)
701*287e80b3SSadaf Ebrahimi all += count;
702*287e80b3SSadaf Ebrahimi }
703*287e80b3SSadaf Ebrahimi
704*287e80b3SSadaf Ebrahimi return all;
705*287e80b3SSadaf Ebrahimi }
706*287e80b3SSadaf Ebrahimi
707*287e80b3SSadaf Ebrahimi static enum tracefs_dynevent_type
dynevent_info(struct tracefs_dynevent * dynevent,char ** system,char ** event,char ** prefix,char ** addr,char ** format)708*287e80b3SSadaf Ebrahimi dynevent_info(struct tracefs_dynevent *dynevent, char **system,
709*287e80b3SSadaf Ebrahimi char **event, char **prefix, char **addr, char **format)
710*287e80b3SSadaf Ebrahimi {
711*287e80b3SSadaf Ebrahimi char **lv[] = { system, event, prefix, addr, format };
712*287e80b3SSadaf Ebrahimi char **rv[] = { &dynevent->system, &dynevent->event, &dynevent->prefix,
713*287e80b3SSadaf Ebrahimi &dynevent->address, &dynevent->format };
714*287e80b3SSadaf Ebrahimi int i;
715*287e80b3SSadaf Ebrahimi
716*287e80b3SSadaf Ebrahimi for (i = 0; i < ARRAY_SIZE(lv); i++) {
717*287e80b3SSadaf Ebrahimi if (lv[i]) {
718*287e80b3SSadaf Ebrahimi if (*rv[i]) {
719*287e80b3SSadaf Ebrahimi *lv[i] = strdup(*rv[i]);
720*287e80b3SSadaf Ebrahimi if (!*lv[i])
721*287e80b3SSadaf Ebrahimi goto error;
722*287e80b3SSadaf Ebrahimi } else {
723*287e80b3SSadaf Ebrahimi *lv[i] = NULL;
724*287e80b3SSadaf Ebrahimi }
725*287e80b3SSadaf Ebrahimi }
726*287e80b3SSadaf Ebrahimi }
727*287e80b3SSadaf Ebrahimi
728*287e80b3SSadaf Ebrahimi return dynevent->type;
729*287e80b3SSadaf Ebrahimi
730*287e80b3SSadaf Ebrahimi error:
731*287e80b3SSadaf Ebrahimi for (i--; i >= 0; i--) {
732*287e80b3SSadaf Ebrahimi if (lv[i])
733*287e80b3SSadaf Ebrahimi free(*lv[i]);
734*287e80b3SSadaf Ebrahimi }
735*287e80b3SSadaf Ebrahimi
736*287e80b3SSadaf Ebrahimi return TRACEFS_DYNEVENT_UNKNOWN;
737*287e80b3SSadaf Ebrahimi }
738*287e80b3SSadaf Ebrahimi
739*287e80b3SSadaf Ebrahimi /**
740*287e80b3SSadaf Ebrahimi * tracefs_dynevent_info - return details of a dynamic event
741*287e80b3SSadaf Ebrahimi * @dynevent: A dynamic event context, describing given dynamic event.
742*287e80b3SSadaf Ebrahimi * @group: return, group in which the dynamic event is configured
743*287e80b3SSadaf Ebrahimi * @event: return, name of the dynamic event
744*287e80b3SSadaf Ebrahimi * @prefix: return, prefix string of the dynamic event
745*287e80b3SSadaf Ebrahimi * @addr: return, the function and offset (or address) of the dynamic event
746*287e80b3SSadaf Ebrahimi * @format: return, the format string of the dynamic event
747*287e80b3SSadaf Ebrahimi *
748*287e80b3SSadaf Ebrahimi * Returns the type of the dynamic event, or TRACEFS_DYNEVENT_UNKNOWN in case of an error.
749*287e80b3SSadaf Ebrahimi * Any of the @group, @event, @prefix, @addr and @format parameters are optional.
750*287e80b3SSadaf Ebrahimi * If a valid pointer is passed, in case of success - a string is allocated and returned.
751*287e80b3SSadaf Ebrahimi * These strings must be freed with free().
752*287e80b3SSadaf Ebrahimi */
753*287e80b3SSadaf Ebrahimi enum tracefs_dynevent_type
tracefs_dynevent_info(struct tracefs_dynevent * dynevent,char ** system,char ** event,char ** prefix,char ** addr,char ** format)754*287e80b3SSadaf Ebrahimi tracefs_dynevent_info(struct tracefs_dynevent *dynevent, char **system,
755*287e80b3SSadaf Ebrahimi char **event, char **prefix, char **addr, char **format)
756*287e80b3SSadaf Ebrahimi {
757*287e80b3SSadaf Ebrahimi if (!dynevent)
758*287e80b3SSadaf Ebrahimi return TRACEFS_DYNEVENT_UNKNOWN;
759*287e80b3SSadaf Ebrahimi
760*287e80b3SSadaf Ebrahimi return dynevent_info(dynevent, system, event, prefix, addr, format);
761*287e80b3SSadaf Ebrahimi }
762*287e80b3SSadaf Ebrahimi
763*287e80b3SSadaf Ebrahimi /**
764*287e80b3SSadaf Ebrahimi * tracefs_dynevent_get_event - return tep event representing the given dynamic event
765*287e80b3SSadaf Ebrahimi * @tep: a handle to the trace event parser context that holds the events
766*287e80b3SSadaf Ebrahimi * @dynevent: a dynamic event context, describing given dynamic event.
767*287e80b3SSadaf Ebrahimi *
768*287e80b3SSadaf Ebrahimi * Returns a pointer to a tep event describing the given dynamic event. The pointer
769*287e80b3SSadaf Ebrahimi * is managed by the @tep handle and must not be freed. In case of an error, or in case
770*287e80b3SSadaf Ebrahimi * the requested dynamic event is missing in the @tep handler - NULL is returned.
771*287e80b3SSadaf Ebrahimi */
772*287e80b3SSadaf Ebrahimi struct tep_event *
tracefs_dynevent_get_event(struct tep_handle * tep,struct tracefs_dynevent * dynevent)773*287e80b3SSadaf Ebrahimi tracefs_dynevent_get_event(struct tep_handle *tep, struct tracefs_dynevent *dynevent)
774*287e80b3SSadaf Ebrahimi {
775*287e80b3SSadaf Ebrahimi if (!tep || !dynevent || !dynevent->event)
776*287e80b3SSadaf Ebrahimi return NULL;
777*287e80b3SSadaf Ebrahimi
778*287e80b3SSadaf Ebrahimi return get_tep_event(tep, dynevent->system, dynevent->event);
779*287e80b3SSadaf Ebrahimi }
780