perf probe: Move ftrace probe-event operations to probe-file.c
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Wed, 15 Jul 2015 09:14:07 +0000 (18:14 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 20 Jul 2015 20:49:49 +0000 (17:49 -0300)
Move ftrace probe-event operations to probe-file.c from probe-event.c.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20150715091407.8915.14316.stgit@localhost.localdomain
[ Fixed up strlist__new() calls wrt 4a77e2183fc0 ("perf strlist: Make dupstr be the...") ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/Build
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c [new file with mode: 0644]
tools/perf/util/probe-file.h [new file with mode: 0644]

index 601d114..8d1bdf8 100644 (file)
@@ -79,6 +79,7 @@ libperf-$(CONFIG_AUXTRACE) += auxtrace.o
 libperf-y += parse-branch-options.o
 
 libperf-$(CONFIG_LIBELF) += symbol-elf.o
+libperf-$(CONFIG_LIBELF) += probe-file.o
 libperf-$(CONFIG_LIBELF) += probe-event.o
 
 ifndef CONFIG_LIBELF
index 54a91d7..fe4941a 100644 (file)
@@ -45,6 +45,7 @@
 #include "trace-event.h"       /* For __maybe_unused */
 #include "probe-event.h"
 #include "probe-finder.h"
+#include "probe-file.h"
 #include "session.h"
 
 #define MAX_CMDLEN 256
@@ -55,11 +56,7 @@ struct probe_conf probe_conf;
 
 #define semantic_error(msg ...) pr_err("Semantic error :" msg)
 
-/* If there is no space to write, returns -E2BIG. */
-static int e_snprintf(char *str, size_t size, const char *format, ...)
-       __attribute__((format(printf, 3, 4)));
-
-static int e_snprintf(char *str, size_t size, const char *format, ...)
+int e_snprintf(char *str, size_t size, const char *format, ...)
 {
        int ret;
        va_list ap;
@@ -72,7 +69,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static void clear_probe_trace_event(struct probe_trace_event *tev);
 static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -1467,8 +1463,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
 }
 
 /* Parse probe_events event into struct probe_point */
-static int parse_probe_trace_command(const char *cmd,
-                                    struct probe_trace_event *tev)
+int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
 {
        struct probe_trace_point *tp = &tev->point;
        char pr;
@@ -1951,7 +1946,7 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
        memset(pev, 0, sizeof(*pev));
 }
 
-static void clear_probe_trace_event(struct probe_trace_event *tev)
+void clear_probe_trace_event(struct probe_trace_event *tev)
 {
        struct probe_trace_arg_ref *ref, *next;
        int i;
@@ -1976,119 +1971,6 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
        memset(tev, 0, sizeof(*tev));
 }
 
-static void print_open_warning(int err, bool is_kprobe)
-{
-       char sbuf[STRERR_BUFSIZE];
-
-       if (err == -ENOENT) {
-               const char *config;
-
-               if (!is_kprobe)
-                       config = "CONFIG_UPROBE_EVENTS";
-               else
-                       config = "CONFIG_KPROBE_EVENTS";
-
-               pr_warning("%cprobe_events file does not exist"
-                          " - please rebuild kernel with %s.\n",
-                          is_kprobe ? 'k' : 'u', config);
-       } else if (err == -ENOTSUP)
-               pr_warning("Tracefs or debugfs is not mounted.\n");
-       else
-               pr_warning("Failed to open %cprobe_events: %s\n",
-                          is_kprobe ? 'k' : 'u',
-                          strerror_r(-err, sbuf, sizeof(sbuf)));
-}
-
-static void print_both_open_warning(int kerr, int uerr)
-{
-       /* Both kprobes and uprobes are disabled, warn it. */
-       if (kerr == -ENOTSUP && uerr == -ENOTSUP)
-               pr_warning("Tracefs or debugfs is not mounted.\n");
-       else if (kerr == -ENOENT && uerr == -ENOENT)
-               pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
-                          "or/and CONFIG_UPROBE_EVENTS.\n");
-       else {
-               char sbuf[STRERR_BUFSIZE];
-               pr_warning("Failed to open kprobe events: %s.\n",
-                          strerror_r(-kerr, sbuf, sizeof(sbuf)));
-               pr_warning("Failed to open uprobe events: %s.\n",
-                          strerror_r(-uerr, sbuf, sizeof(sbuf)));
-       }
-}
-
-static int open_probe_events(const char *trace_file, bool readwrite)
-{
-       char buf[PATH_MAX];
-       const char *__debugfs;
-       const char *tracing_dir = "";
-       int ret;
-
-       __debugfs = tracefs_find_mountpoint();
-       if (__debugfs == NULL) {
-               tracing_dir = "tracing/";
-
-               __debugfs = debugfs_find_mountpoint();
-               if (__debugfs == NULL)
-                       return -ENOTSUP;
-       }
-
-       ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
-                        __debugfs, tracing_dir, trace_file);
-       if (ret >= 0) {
-               pr_debug("Opening %s write=%d\n", buf, readwrite);
-               if (readwrite && !probe_event_dry_run)
-                       ret = open(buf, O_RDWR | O_APPEND, 0);
-               else
-                       ret = open(buf, O_RDONLY, 0);
-
-               if (ret < 0)
-                       ret = -errno;
-       }
-       return ret;
-}
-
-static int open_kprobe_events(bool readwrite)
-{
-       return open_probe_events("kprobe_events", readwrite);
-}
-
-static int open_uprobe_events(bool readwrite)
-{
-       return open_probe_events("uprobe_events", readwrite);
-}
-
-/* Get raw string list of current kprobe_events  or uprobe_events */
-static struct strlist *get_probe_trace_command_rawlist(int fd)
-{
-       int ret, idx;
-       FILE *fp;
-       char buf[MAX_CMDLEN];
-       char *p;
-       struct strlist *sl;
-
-       sl = strlist__new(NULL, NULL);
-
-       fp = fdopen(dup(fd), "r");
-       while (!feof(fp)) {
-               p = fgets(buf, MAX_CMDLEN, fp);
-               if (!p)
-                       break;
-
-               idx = strlen(p) - 1;
-               if (p[idx] == '\n')
-                       p[idx] = '\0';
-               ret = strlist__add(sl, buf);
-               if (ret < 0) {
-                       pr_debug("strlist__add failed (%d)\n", ret);
-                       strlist__delete(sl);
-                       return NULL;
-               }
-       }
-       fclose(fp);
-
-       return sl;
-}
-
 struct kprobe_blacklist_node {
        struct list_head list;
        unsigned long start;
@@ -2284,7 +2166,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe,
        memset(&tev, 0, sizeof(tev));
        memset(&pev, 0, sizeof(pev));
 
-       rawlist = get_probe_trace_command_rawlist(fd);
+       rawlist = probe_file__get_rawlist(fd);
        if (!rawlist)
                return -ENOMEM;
 
@@ -2325,89 +2207,20 @@ int show_perf_probe_events(struct strfilter *filter)
        if (ret < 0)
                return ret;
 
-       kp_fd = open_kprobe_events(false);
-       if (kp_fd >= 0) {
-               ret = __show_perf_probe_events(kp_fd, true, filter);
-               close(kp_fd);
-               if (ret < 0)
-                       goto out;
-       }
-
-       up_fd = open_uprobe_events(false);
-       if (kp_fd < 0 && up_fd < 0) {
-               print_both_open_warning(kp_fd, up_fd);
-               ret = kp_fd;
-               goto out;
-       }
+       ret = probe_file__open_both(&kp_fd, &up_fd, 0);
+       if (ret < 0)
+               return ret;
 
-       if (up_fd >= 0) {
+       if (kp_fd >= 0)
+               ret = __show_perf_probe_events(kp_fd, true, filter);
+       if (up_fd >= 0 && ret >= 0)
                ret = __show_perf_probe_events(up_fd, false, filter);
+       if (kp_fd > 0)
+               close(kp_fd);
+       if (up_fd > 0)
                close(up_fd);
-       }
-out:
        exit_symbol_maps();
-       return ret;
-}
 
-/* Get current perf-probe event names */
-static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
-{
-       char buf[128];
-       struct strlist *sl, *rawlist;
-       struct str_node *ent;
-       struct probe_trace_event tev;
-       int ret = 0;
-
-       memset(&tev, 0, sizeof(tev));
-       rawlist = get_probe_trace_command_rawlist(fd);
-       if (!rawlist)
-               return NULL;
-       sl = strlist__new(NULL, NULL);
-       strlist__for_each(ent, rawlist) {
-               ret = parse_probe_trace_command(ent->s, &tev);
-               if (ret < 0)
-                       break;
-               if (include_group) {
-                       ret = e_snprintf(buf, 128, "%s:%s", tev.group,
-                                       tev.event);
-                       if (ret >= 0)
-                               ret = strlist__add(sl, buf);
-               } else
-                       ret = strlist__add(sl, tev.event);
-               clear_probe_trace_event(&tev);
-               if (ret < 0)
-                       break;
-       }
-       strlist__delete(rawlist);
-
-       if (ret < 0) {
-               strlist__delete(sl);
-               return NULL;
-       }
-       return sl;
-}
-
-static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
-{
-       int ret = 0;
-       char *buf = synthesize_probe_trace_command(tev);
-       char sbuf[STRERR_BUFSIZE];
-
-       if (!buf) {
-               pr_debug("Failed to synthesize probe trace event.\n");
-               return -EINVAL;
-       }
-
-       pr_debug("Writing event: %s\n", buf);
-       if (!probe_event_dry_run) {
-               ret = write(fd, buf, strlen(buf));
-               if (ret <= 0) {
-                       ret = -errno;
-                       pr_warning("Failed to write event: %s\n",
-                                  strerror_r(errno, sbuf, sizeof(sbuf)));
-               }
-       }
-       free(buf);
        return ret;
 }
 
@@ -2527,18 +2340,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        const char *event = NULL, *group = NULL;
        struct strlist *namelist;
 
-       if (pev->uprobes)
-               fd = open_uprobe_events(true);
-       else
-               fd = open_kprobe_events(true);
-
-       if (fd < 0) {
-               print_open_warning(fd, !pev->uprobes);
+       fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0));
+       if (fd < 0)
                return fd;
-       }
 
        /* Get current event names */
-       namelist = get_probe_trace_event_names(fd, false);
+       namelist = probe_file__get_namelist(fd);
        if (!namelist) {
                pr_debug("Failed to get current event list.\n");
                ret = -ENOMEM;
@@ -2559,7 +2366,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
                if (ret < 0)
                        break;
 
-               ret = write_probe_trace_event(fd, tev);
+               ret = probe_file__add_event(fd, tev);
                if (ret < 0)
                        break;
 
@@ -2854,68 +2661,9 @@ end:
        return ret;
 }
 
-static int __del_trace_probe_event(int fd, struct str_node *ent)
-{
-       char *p;
-       char buf[128];
-       int ret;
-
-       /* Convert from perf-probe event to trace-probe event */
-       ret = e_snprintf(buf, 128, "-:%s", ent->s);
-       if (ret < 0)
-               goto error;
-
-       p = strchr(buf + 2, ':');
-       if (!p) {
-               pr_debug("Internal error: %s should have ':' but not.\n",
-                        ent->s);
-               ret = -ENOTSUP;
-               goto error;
-       }
-       *p = '/';
-
-       pr_debug("Writing event: %s\n", buf);
-       ret = write(fd, buf, strlen(buf));
-       if (ret < 0) {
-               ret = -errno;
-               goto error;
-       }
-
-       pr_info("Removed event: %s\n", ent->s);
-       return 0;
-error:
-       pr_warning("Failed to delete event: %s\n",
-                  strerror_r(-ret, buf, sizeof(buf)));
-       return ret;
-}
-
-static int del_trace_probe_events(int fd, struct strfilter *filter,
-                                 struct strlist *namelist)
-{
-       struct str_node *ent;
-       const char *p;
-       int ret = -ENOENT;
-
-       if (!namelist)
-               return -ENOENT;
-
-       strlist__for_each(ent, namelist) {
-               p = strchr(ent->s, ':');
-               if ((p && strfilter__compare(filter, p + 1)) ||
-                   strfilter__compare(filter, ent->s)) {
-                       ret = __del_trace_probe_event(fd, ent);
-                       if (ret < 0)
-                               break;
-               }
-       }
-
-       return ret;
-}
-
 int del_perf_probe_events(struct strfilter *filter)
 {
        int ret, ret2, ufd = -1, kfd = -1;
-       struct strlist *namelist = NULL, *unamelist = NULL;
        char *str = strfilter__string(filter);
 
        if (!str)
@@ -2924,25 +2672,15 @@ int del_perf_probe_events(struct strfilter *filter)
        pr_debug("Delete filter: \'%s\'\n", str);
 
        /* Get current event names */
-       kfd = open_kprobe_events(true);
-       if (kfd >= 0)
-               namelist = get_probe_trace_event_names(kfd, true);
-
-       ufd = open_uprobe_events(true);
-       if (ufd >= 0)
-               unamelist = get_probe_trace_event_names(ufd, true);
-
-       if (kfd < 0 && ufd < 0) {
-               print_both_open_warning(kfd, ufd);
-               ret = kfd;
-               goto error;
-       }
+       ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
+       if (ret < 0)
+               goto out;
 
-       ret = del_trace_probe_events(kfd, filter, namelist);
+       ret = probe_file__del_events(kfd, filter);
        if (ret < 0 && ret != -ENOENT)
                goto error;
 
-       ret2 = del_trace_probe_events(ufd, filter, unamelist);
+       ret2 = probe_file__del_events(ufd, filter);
        if (ret2 < 0 && ret2 != -ENOENT) {
                ret = ret2;
                goto error;
@@ -2953,15 +2691,11 @@ int del_perf_probe_events(struct strfilter *filter)
        ret = 0;
 
 error:
-       if (kfd >= 0) {
-               strlist__delete(namelist);
+       if (kfd >= 0)
                close(kfd);
-       }
-
-       if (ufd >= 0) {
-               strlist__delete(unamelist);
+       if (ufd >= 0)
                close(ufd);
-       }
+out:
        free(str);
 
        return ret;
index 31db6ee..20f555d 100644 (file)
@@ -109,6 +109,8 @@ struct variable_list {
 /* Command string to events */
 extern int parse_perf_probe_command(const char *cmd,
                                    struct perf_probe_event *pev);
+extern int parse_probe_trace_command(const char *cmd,
+                                    struct probe_trace_event *tev);
 
 /* Events to command string */
 extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
@@ -121,6 +123,7 @@ extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
 
 /* Release event contents */
 extern void clear_perf_probe_event(struct perf_probe_event *pev);
+extern void clear_probe_trace_event(struct probe_trace_event *tev);
 
 /* Command string to line-range */
 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
@@ -144,6 +147,10 @@ bool arch__prefers_symtab(void);
 void arch__fix_tev_from_maps(struct perf_probe_event *pev,
                             struct probe_trace_event *tev, struct map *map);
 
+/* If there is no space to write, returns -E2BIG. */
+int e_snprintf(char *str, size_t size, const char *format, ...)
+       __attribute__((format(printf, 3, 4)));
+
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX        1024
 
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
new file mode 100644 (file)
index 0000000..bbb2437
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * probe-file.c : operate ftrace k/uprobe events files
+ *
+ * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "util.h"
+#include "event.h"
+#include "strlist.h"
+#include "debug.h"
+#include "cache.h"
+#include "color.h"
+#include "symbol.h"
+#include "thread.h"
+#include <api/fs/debugfs.h>
+#include <api/fs/tracefs.h>
+#include "probe-event.h"
+#include "probe-file.h"
+#include "session.h"
+
+#define MAX_CMDLEN 256
+
+static void print_open_warning(int err, bool uprobe)
+{
+       char sbuf[STRERR_BUFSIZE];
+
+       if (err == -ENOENT) {
+               const char *config;
+
+               if (uprobe)
+                       config = "CONFIG_UPROBE_EVENTS";
+               else
+                       config = "CONFIG_KPROBE_EVENTS";
+
+               pr_warning("%cprobe_events file does not exist"
+                          " - please rebuild kernel with %s.\n",
+                          uprobe ? 'u' : 'k', config);
+       } else if (err == -ENOTSUP)
+               pr_warning("Tracefs or debugfs is not mounted.\n");
+       else
+               pr_warning("Failed to open %cprobe_events: %s\n",
+                          uprobe ? 'u' : 'k',
+                          strerror_r(-err, sbuf, sizeof(sbuf)));
+}
+
+static void print_both_open_warning(int kerr, int uerr)
+{
+       /* Both kprobes and uprobes are disabled, warn it. */
+       if (kerr == -ENOTSUP && uerr == -ENOTSUP)
+               pr_warning("Tracefs or debugfs is not mounted.\n");
+       else if (kerr == -ENOENT && uerr == -ENOENT)
+               pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
+                          "or/and CONFIG_UPROBE_EVENTS.\n");
+       else {
+               char sbuf[STRERR_BUFSIZE];
+               pr_warning("Failed to open kprobe events: %s.\n",
+                          strerror_r(-kerr, sbuf, sizeof(sbuf)));
+               pr_warning("Failed to open uprobe events: %s.\n",
+                          strerror_r(-uerr, sbuf, sizeof(sbuf)));
+       }
+}
+
+static int open_probe_events(const char *trace_file, bool readwrite)
+{
+       char buf[PATH_MAX];
+       const char *__debugfs;
+       const char *tracing_dir = "";
+       int ret;
+
+       __debugfs = tracefs_find_mountpoint();
+       if (__debugfs == NULL) {
+               tracing_dir = "tracing/";
+
+               __debugfs = debugfs_find_mountpoint();
+               if (__debugfs == NULL)
+                       return -ENOTSUP;
+       }
+
+       ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
+                        __debugfs, tracing_dir, trace_file);
+       if (ret >= 0) {
+               pr_debug("Opening %s write=%d\n", buf, readwrite);
+               if (readwrite && !probe_event_dry_run)
+                       ret = open(buf, O_RDWR | O_APPEND, 0);
+               else
+                       ret = open(buf, O_RDONLY, 0);
+
+               if (ret < 0)
+                       ret = -errno;
+       }
+       return ret;
+}
+
+static int open_kprobe_events(bool readwrite)
+{
+       return open_probe_events("kprobe_events", readwrite);
+}
+
+static int open_uprobe_events(bool readwrite)
+{
+       return open_probe_events("uprobe_events", readwrite);
+}
+
+int probe_file__open(int flag)
+{
+       int fd;
+
+       if (flag & PF_FL_UPROBE)
+               fd = open_uprobe_events(flag & PF_FL_RW);
+       else
+               fd = open_kprobe_events(flag & PF_FL_RW);
+       if (fd < 0)
+               print_open_warning(fd, flag & PF_FL_UPROBE);
+
+       return fd;
+}
+
+int probe_file__open_both(int *kfd, int *ufd, int flag)
+{
+       if (!kfd || !ufd)
+               return -EINVAL;
+
+       *kfd = open_kprobe_events(flag & PF_FL_RW);
+       *ufd = open_uprobe_events(flag & PF_FL_RW);
+       if (*kfd < 0 && *ufd < 0) {
+               print_both_open_warning(*kfd, *ufd);
+               return *kfd;
+       }
+
+       return 0;
+}
+
+/* Get raw string list of current kprobe_events  or uprobe_events */
+struct strlist *probe_file__get_rawlist(int fd)
+{
+       int ret, idx;
+       FILE *fp;
+       char buf[MAX_CMDLEN];
+       char *p;
+       struct strlist *sl;
+
+       sl = strlist__new(NULL, NULL);
+
+       fp = fdopen(dup(fd), "r");
+       while (!feof(fp)) {
+               p = fgets(buf, MAX_CMDLEN, fp);
+               if (!p)
+                       break;
+
+               idx = strlen(p) - 1;
+               if (p[idx] == '\n')
+                       p[idx] = '\0';
+               ret = strlist__add(sl, buf);
+               if (ret < 0) {
+                       pr_debug("strlist__add failed (%d)\n", ret);
+                       strlist__delete(sl);
+                       return NULL;
+               }
+       }
+       fclose(fp);
+
+       return sl;
+}
+
+static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
+{
+       char buf[128];
+       struct strlist *sl, *rawlist;
+       struct str_node *ent;
+       struct probe_trace_event tev;
+       int ret = 0;
+
+       memset(&tev, 0, sizeof(tev));
+       rawlist = probe_file__get_rawlist(fd);
+       if (!rawlist)
+               return NULL;
+       sl = strlist__new(NULL, NULL);
+       strlist__for_each(ent, rawlist) {
+               ret = parse_probe_trace_command(ent->s, &tev);
+               if (ret < 0)
+                       break;
+               if (include_group) {
+                       ret = e_snprintf(buf, 128, "%s:%s", tev.group,
+                                       tev.event);
+                       if (ret >= 0)
+                               ret = strlist__add(sl, buf);
+               } else
+                       ret = strlist__add(sl, tev.event);
+               clear_probe_trace_event(&tev);
+               if (ret < 0)
+                       break;
+       }
+       strlist__delete(rawlist);
+
+       if (ret < 0) {
+               strlist__delete(sl);
+               return NULL;
+       }
+       return sl;
+}
+
+/* Get current perf-probe event names */
+struct strlist *probe_file__get_namelist(int fd)
+{
+       return __probe_file__get_namelist(fd, false);
+}
+
+int probe_file__add_event(int fd, struct probe_trace_event *tev)
+{
+       int ret = 0;
+       char *buf = synthesize_probe_trace_command(tev);
+       char sbuf[STRERR_BUFSIZE];
+
+       if (!buf) {
+               pr_debug("Failed to synthesize probe trace event.\n");
+               return -EINVAL;
+       }
+
+       pr_debug("Writing event: %s\n", buf);
+       if (!probe_event_dry_run) {
+               ret = write(fd, buf, strlen(buf));
+               if (ret <= 0) {
+                       ret = -errno;
+                       pr_warning("Failed to write event: %s\n",
+                                  strerror_r(errno, sbuf, sizeof(sbuf)));
+               }
+       }
+       free(buf);
+
+       return ret;
+}
+
+static int __del_trace_probe_event(int fd, struct str_node *ent)
+{
+       char *p;
+       char buf[128];
+       int ret;
+
+       /* Convert from perf-probe event to trace-probe event */
+       ret = e_snprintf(buf, 128, "-:%s", ent->s);
+       if (ret < 0)
+               goto error;
+
+       p = strchr(buf + 2, ':');
+       if (!p) {
+               pr_debug("Internal error: %s should have ':' but not.\n",
+                        ent->s);
+               ret = -ENOTSUP;
+               goto error;
+       }
+       *p = '/';
+
+       pr_debug("Writing event: %s\n", buf);
+       ret = write(fd, buf, strlen(buf));
+       if (ret < 0) {
+               ret = -errno;
+               goto error;
+       }
+
+       pr_info("Removed event: %s\n", ent->s);
+       return 0;
+error:
+       pr_warning("Failed to delete event: %s\n",
+                  strerror_r(-ret, buf, sizeof(buf)));
+       return ret;
+}
+
+int probe_file__del_events(int fd, struct strfilter *filter)
+{
+       struct strlist *namelist;
+       struct str_node *ent;
+       const char *p;
+       int ret = -ENOENT;
+
+       namelist = __probe_file__get_namelist(fd, true);
+       if (!namelist)
+               return -ENOENT;
+
+       strlist__for_each(ent, namelist) {
+               p = strchr(ent->s, ':');
+               if ((p && strfilter__compare(filter, p + 1)) ||
+                   strfilter__compare(filter, ent->s)) {
+                       ret = __del_trace_probe_event(fd, ent);
+                       if (ret < 0)
+                               break;
+               }
+       }
+       strlist__delete(namelist);
+
+       return ret;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
new file mode 100644 (file)
index 0000000..ada94a2
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __PROBE_FILE_H
+#define __PROBE_FILE_H
+
+#include "strlist.h"
+#include "strfilter.h"
+#include "probe-event.h"
+
+#define PF_FL_UPROBE   1
+#define PF_FL_RW       2
+
+int probe_file__open(int flag);
+int probe_file__open_both(int *kfd, int *ufd, int flag);
+struct strlist *probe_file__get_namelist(int fd);
+struct strlist *probe_file__get_rawlist(int fd);
+int probe_file__add_event(int fd, struct probe_trace_event *tev);
+int probe_file__del_events(int fd, struct strfilter *filter);
+
+#endif