Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * probe-file.c : operate ftrace k/uprobe events files
  3 *
  4 * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License as published by
  8 * the Free Software Foundation; either version 2 of the License, or
  9 * (at your option) any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 */
 17#include "util.h"
 18#include "event.h"
 19#include "strlist.h"
 20#include "debug.h"
 21#include "cache.h"
 22#include "color.h"
 23#include "symbol.h"
 24#include "thread.h"
 25#include <api/fs/tracing_path.h>
 26#include "probe-event.h"
 27#include "probe-file.h"
 28#include "session.h"
 29
 30#define MAX_CMDLEN 256
 31
 32static void print_open_warning(int err, bool uprobe)
 33{
 34	char sbuf[STRERR_BUFSIZE];
 35
 36	if (err == -ENOENT) {
 37		const char *config;
 38
 39		if (uprobe)
 40			config = "CONFIG_UPROBE_EVENTS";
 41		else
 42			config = "CONFIG_KPROBE_EVENTS";
 43
 44		pr_warning("%cprobe_events file does not exist"
 45			   " - please rebuild kernel with %s.\n",
 46			   uprobe ? 'u' : 'k', config);
 47	} else if (err == -ENOTSUP)
 48		pr_warning("Tracefs or debugfs is not mounted.\n");
 49	else
 50		pr_warning("Failed to open %cprobe_events: %s\n",
 51			   uprobe ? 'u' : 'k',
 52			   strerror_r(-err, sbuf, sizeof(sbuf)));
 53}
 54
 55static void print_both_open_warning(int kerr, int uerr)
 56{
 57	/* Both kprobes and uprobes are disabled, warn it. */
 58	if (kerr == -ENOTSUP && uerr == -ENOTSUP)
 59		pr_warning("Tracefs or debugfs is not mounted.\n");
 60	else if (kerr == -ENOENT && uerr == -ENOENT)
 61		pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
 62			   "or/and CONFIG_UPROBE_EVENTS.\n");
 63	else {
 64		char sbuf[STRERR_BUFSIZE];
 65		pr_warning("Failed to open kprobe events: %s.\n",
 66			   strerror_r(-kerr, sbuf, sizeof(sbuf)));
 67		pr_warning("Failed to open uprobe events: %s.\n",
 68			   strerror_r(-uerr, sbuf, sizeof(sbuf)));
 69	}
 70}
 71
 72static int open_probe_events(const char *trace_file, bool readwrite)
 73{
 74	char buf[PATH_MAX];
 75	const char *tracing_dir = "";
 76	int ret;
 77
 78	ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
 79			 tracing_path, tracing_dir, trace_file);
 80	if (ret >= 0) {
 81		pr_debug("Opening %s write=%d\n", buf, readwrite);
 82		if (readwrite && !probe_event_dry_run)
 83			ret = open(buf, O_RDWR | O_APPEND, 0);
 84		else
 85			ret = open(buf, O_RDONLY, 0);
 86
 87		if (ret < 0)
 88			ret = -errno;
 89	}
 90	return ret;
 91}
 92
 93static int open_kprobe_events(bool readwrite)
 94{
 95	return open_probe_events("kprobe_events", readwrite);
 96}
 97
 98static int open_uprobe_events(bool readwrite)
 99{
100	return open_probe_events("uprobe_events", readwrite);
101}
102
103int probe_file__open(int flag)
104{
105	int fd;
106
107	if (flag & PF_FL_UPROBE)
108		fd = open_uprobe_events(flag & PF_FL_RW);
109	else
110		fd = open_kprobe_events(flag & PF_FL_RW);
111	if (fd < 0)
112		print_open_warning(fd, flag & PF_FL_UPROBE);
113
114	return fd;
115}
116
117int probe_file__open_both(int *kfd, int *ufd, int flag)
118{
119	if (!kfd || !ufd)
120		return -EINVAL;
121
122	*kfd = open_kprobe_events(flag & PF_FL_RW);
123	*ufd = open_uprobe_events(flag & PF_FL_RW);
124	if (*kfd < 0 && *ufd < 0) {
125		print_both_open_warning(*kfd, *ufd);
126		return *kfd;
127	}
128
129	return 0;
130}
131
132/* Get raw string list of current kprobe_events  or uprobe_events */
133struct strlist *probe_file__get_rawlist(int fd)
134{
135	int ret, idx;
136	FILE *fp;
137	char buf[MAX_CMDLEN];
138	char *p;
139	struct strlist *sl;
140
141	if (fd < 0)
142		return NULL;
143
144	sl = strlist__new(NULL, NULL);
145
146	fp = fdopen(dup(fd), "r");
147	while (!feof(fp)) {
148		p = fgets(buf, MAX_CMDLEN, fp);
149		if (!p)
150			break;
151
152		idx = strlen(p) - 1;
153		if (p[idx] == '\n')
154			p[idx] = '\0';
155		ret = strlist__add(sl, buf);
156		if (ret < 0) {
157			pr_debug("strlist__add failed (%d)\n", ret);
158			strlist__delete(sl);
159			return NULL;
160		}
161	}
162	fclose(fp);
163
164	return sl;
165}
166
167static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
168{
169	char buf[128];
170	struct strlist *sl, *rawlist;
171	struct str_node *ent;
172	struct probe_trace_event tev;
173	int ret = 0;
174
175	memset(&tev, 0, sizeof(tev));
176	rawlist = probe_file__get_rawlist(fd);
177	if (!rawlist)
178		return NULL;
179	sl = strlist__new(NULL, NULL);
180	strlist__for_each(ent, rawlist) {
181		ret = parse_probe_trace_command(ent->s, &tev);
182		if (ret < 0)
183			break;
184		if (include_group) {
185			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
186					tev.event);
187			if (ret >= 0)
188				ret = strlist__add(sl, buf);
189		} else
190			ret = strlist__add(sl, tev.event);
191		clear_probe_trace_event(&tev);
192		if (ret < 0)
193			break;
194	}
195	strlist__delete(rawlist);
196
197	if (ret < 0) {
198		strlist__delete(sl);
199		return NULL;
200	}
201	return sl;
202}
203
204/* Get current perf-probe event names */
205struct strlist *probe_file__get_namelist(int fd)
206{
207	return __probe_file__get_namelist(fd, false);
208}
209
210int probe_file__add_event(int fd, struct probe_trace_event *tev)
211{
212	int ret = 0;
213	char *buf = synthesize_probe_trace_command(tev);
214	char sbuf[STRERR_BUFSIZE];
215
216	if (!buf) {
217		pr_debug("Failed to synthesize probe trace event.\n");
218		return -EINVAL;
219	}
220
221	pr_debug("Writing event: %s\n", buf);
222	if (!probe_event_dry_run) {
223		ret = write(fd, buf, strlen(buf));
224		if (ret <= 0) {
225			ret = -errno;
226			pr_warning("Failed to write event: %s\n",
227				   strerror_r(errno, sbuf, sizeof(sbuf)));
228		}
229	}
230	free(buf);
231
232	return ret;
233}
234
235static int __del_trace_probe_event(int fd, struct str_node *ent)
236{
237	char *p;
238	char buf[128];
239	int ret;
240
241	/* Convert from perf-probe event to trace-probe event */
242	ret = e_snprintf(buf, 128, "-:%s", ent->s);
243	if (ret < 0)
244		goto error;
245
246	p = strchr(buf + 2, ':');
247	if (!p) {
248		pr_debug("Internal error: %s should have ':' but not.\n",
249			 ent->s);
250		ret = -ENOTSUP;
251		goto error;
252	}
253	*p = '/';
254
255	pr_debug("Writing event: %s\n", buf);
256	ret = write(fd, buf, strlen(buf));
257	if (ret < 0) {
258		ret = -errno;
259		goto error;
260	}
261
262	return 0;
263error:
264	pr_warning("Failed to delete event: %s\n",
265		   strerror_r(-ret, buf, sizeof(buf)));
266	return ret;
267}
268
269int probe_file__get_events(int fd, struct strfilter *filter,
270			   struct strlist *plist)
271{
272	struct strlist *namelist;
273	struct str_node *ent;
274	const char *p;
275	int ret = -ENOENT;
276
277	if (!plist)
278		return -EINVAL;
279
280	namelist = __probe_file__get_namelist(fd, true);
281	if (!namelist)
282		return -ENOENT;
283
284	strlist__for_each(ent, namelist) {
285		p = strchr(ent->s, ':');
286		if ((p && strfilter__compare(filter, p + 1)) ||
287		    strfilter__compare(filter, ent->s)) {
288			strlist__add(plist, ent->s);
289			ret = 0;
290		}
291	}
292	strlist__delete(namelist);
293
294	return ret;
295}
296
297int probe_file__del_strlist(int fd, struct strlist *namelist)
298{
299	int ret = 0;
300	struct str_node *ent;
301
302	strlist__for_each(ent, namelist) {
303		ret = __del_trace_probe_event(fd, ent);
304		if (ret < 0)
305			break;
306	}
307	return ret;
308}
309
310int probe_file__del_events(int fd, struct strfilter *filter)
311{
312	struct strlist *namelist;
313	int ret;
314
315	namelist = strlist__new(NULL, NULL);
316	if (!namelist)
317		return -ENOMEM;
318
319	ret = probe_file__get_events(fd, filter, namelist);
320	if (ret < 0)
321		return ret;
322
323	ret = probe_file__del_strlist(fd, namelist);
324	strlist__delete(namelist);
325
326	return ret;
327}