]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - tools/perf/util/probe-event.c
Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6
[mv-sheeva.git] / tools / perf / util / probe-event.c
index d14a4585bcafb53fd8a9f664ff50e32e8ca9f95b..2ca62154f79b8c49c9973ea732449fd9893c29df 100644 (file)
@@ -69,10 +69,23 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
        char c, nc = 0;
        /*
         * <Syntax>
-        * perf probe SRC:LN
-        * perf probe FUNC[+OFFS|%return][@SRC]
+        * perf probe [EVENT=]SRC:LN
+        * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
+        *
+        * TODO:Group name support
         */
 
+       ptr = strchr(arg, '=');
+       if (ptr) {      /* Event name */
+               *ptr = '\0';
+               tmp = ptr + 1;
+               ptr = strchr(arg, ':');
+               if (ptr)        /* Group name is not supported yet. */
+                       semantic_error("Group name is not supported yet.");
+               pp->event = strdup(arg);
+               arg = tmp;
+       }
+
        ptr = strpbrk(arg, ":+@%");
        if (ptr) {
                nc = *ptr;
@@ -150,10 +163,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 }
 
 /* Parse perf-probe event definition */
-int parse_perf_probe_event(const char *str, struct probe_point *pp)
+void parse_perf_probe_event(const char *str, struct probe_point *pp,
+                           bool *need_dwarf)
 {
        char **argv;
-       int argc, i, need_dwarf = 0;
+       int argc, i;
+
+       *need_dwarf = false;
 
        argv = argv_split(str, &argc);
        if (!argv)
@@ -164,7 +180,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
        /* Parse probe point */
        parse_perf_probe_probepoint(argv[0], pp);
        if (pp->file || pp->line)
-               need_dwarf = 1;
+               *need_dwarf = true;
 
        /* Copy arguments and ensure return probe has no C argument */
        pp->nr_args = argc - 1;
@@ -177,17 +193,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
                        if (pp->retprobe)
                                semantic_error("You can't specify local"
                                                " variable for kretprobe");
-                       need_dwarf = 1;
+                       *need_dwarf = true;
                }
        }
 
        argv_free(argv);
-       return need_dwarf;
 }
 
 /* Parse kprobe_events event into struct probe_point */
-void parse_trace_kprobe_event(const char *str, char **group, char **event,
-                             struct probe_point *pp)
+void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
 {
        char pr;
        char *p;
@@ -203,18 +217,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
 
        /* Scan event and group name. */
        ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
-                    &pr, (float *)(void *)group, (float *)(void *)event);
+                    &pr, (float *)(void *)&pp->group,
+                    (float *)(void *)&pp->event);
        if (ret != 3)
                semantic_error("Failed to parse event name: %s", argv[0]);
-       pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
-
-       if (!pp)
-               goto end;
+       pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
 
        pp->retprobe = (pr == 'r');
 
        /* Scan function name and offset */
-       ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
+       ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
+                    &pp->offset);
        if (ret == 1)
                pp->offset = 0;
 
@@ -233,15 +246,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
                        die("Failed to copy argument.");
        }
 
-end:
        argv_free(argv);
 }
 
-int synthesize_perf_probe_event(struct probe_point *pp)
+/* Synthesize only probe point (not argument) */
+int synthesize_perf_probe_point(struct probe_point *pp)
 {
        char *buf;
        char offs[64] = "", line[64] = "";
-       int i, len, ret;
+       int ret;
 
        pp->probes[0] = buf = zalloc(MAX_CMDLEN);
        if (!buf)
@@ -262,10 +275,24 @@ int synthesize_perf_probe_event(struct probe_point *pp)
                                 offs, pp->retprobe ? "%return" : "", line);
        else
                ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
-       if (ret <= 0)
-               goto error;
-       len = ret;
+       if (ret <= 0) {
+error:
+               free(pp->probes[0]);
+               pp->probes[0] = NULL;
+       }
+       return ret;
+}
 
+int synthesize_perf_probe_event(struct probe_point *pp)
+{
+       char *buf;
+       int i, len, ret;
+
+       len = synthesize_perf_probe_point(pp);
+       if (len < 0)
+               return 0;
+
+       buf = pp->probes[0];
        for (i = 0; i < pp->nr_args; i++) {
                ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
                                 pp->args[i]);
@@ -278,6 +305,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
        return pp->found;
 error:
        free(pp->probes[0]);
+       pp->probes[0] = NULL;
 
        return ret;
 }
@@ -307,6 +335,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
        return pp->found;
 error:
        free(pp->probes[0]);
+       pp->probes[0] = NULL;
 
        return ret;
 }
@@ -366,6 +395,10 @@ static void clear_probe_point(struct probe_point *pp)
 {
        int i;
 
+       if (pp->event)
+               free(pp->event);
+       if (pp->group)
+               free(pp->group);
        if (pp->function)
                free(pp->function);
        if (pp->file)
@@ -380,13 +413,15 @@ static void clear_probe_point(struct probe_point *pp)
 }
 
 /* Show an event */
-static void show_perf_probe_event(const char *group, const char *event,
-                                 const char *place, struct probe_point *pp)
+static void show_perf_probe_event(const char *event, const char *place,
+                                 struct probe_point *pp)
 {
-       int i;
+       int i, ret;
        char buf[128];
 
-       e_snprintf(buf, 128, "%s:%s", group, event);
+       ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
+       if (ret < 0)
+               die("Failed to copy event: %s", strerror(-ret));
        printf("  %-40s (on %s", buf, place);
 
        if (pp->nr_args > 0) {
@@ -400,9 +435,7 @@ static void show_perf_probe_event(const char *group, const char *event,
 /* List up current perf-probe events */
 void show_perf_probe_events(void)
 {
-       unsigned int i;
-       int fd, nr;
-       char *group, *event;
+       int fd;
        struct probe_point pp;
        struct strlist *rawlist;
        struct str_node *ent;
@@ -411,18 +444,12 @@ void show_perf_probe_events(void)
        rawlist = get_trace_kprobe_event_rawlist(fd);
        close(fd);
 
-       for (i = 0; i < strlist__nr_entries(rawlist); i++) {
-               ent = strlist__entry(rawlist, i);
-               parse_trace_kprobe_event(ent->s, &group, &event, &pp);
+       strlist__for_each(ent, rawlist) {
+               parse_trace_kprobe_event(ent->s, &pp);
                /* Synthesize only event probe point */
-               nr = pp.nr_args;
-               pp.nr_args = 0;
-               synthesize_perf_probe_event(&pp);
-               pp.nr_args = nr;
+               synthesize_perf_probe_point(&pp);
                /* Show an event */
-               show_perf_probe_event(group, event, pp.probes[0], &pp);
-               free(group);
-               free(event);
+               show_perf_probe_event(pp.event, pp.probes[0], &pp);
                clear_probe_point(&pp);
        }
 
@@ -432,26 +459,25 @@ void show_perf_probe_events(void)
 /* Get current perf-probe event names */
 static struct strlist *get_perf_event_names(int fd, bool include_group)
 {
-       unsigned int i;
-       char *group, *event;
        char buf[128];
        struct strlist *sl, *rawlist;
        struct str_node *ent;
+       struct probe_point pp;
 
+       memset(&pp, 0, sizeof(pp));
        rawlist = get_trace_kprobe_event_rawlist(fd);
 
        sl = strlist__new(true, NULL);
-       for (i = 0; i < strlist__nr_entries(rawlist); i++) {
-               ent = strlist__entry(rawlist, i);
-               parse_trace_kprobe_event(ent->s, &group, &event, NULL);
+       strlist__for_each(ent, rawlist) {
+               parse_trace_kprobe_event(ent->s, &pp);
                if (include_group) {
-                       if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
+                       if (e_snprintf(buf, 128, "%s:%s", pp.group,
+                                      pp.event) < 0)
                                die("Failed to copy group:event name.");
                        strlist__add(sl, buf);
                } else
-                       strlist__add(sl, event);
-               free(group);
-               free(event);
+                       strlist__add(sl, pp.event);
+               clear_probe_point(&pp);
        }
 
        strlist__delete(rawlist);
@@ -470,7 +496,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
-                              struct strlist *namelist)
+                              struct strlist *namelist, bool allow_suffix)
 {
        int i, ret;
 
@@ -481,6 +507,12 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
        if (!strlist__has_entry(namelist, buf))
                return;
 
+       if (!allow_suffix) {
+               pr_warning("Error: event \"%s\" already exists. "
+                          "(Use -f to force duplicates.)\n", base);
+               die("Can't add new event.");
+       }
+
        /* Try to add suffix */
        for (i = 1; i < MAX_EVENT_INDEX; i++) {
                ret = e_snprintf(buf, len, "%s_%d", base, i);
@@ -493,13 +525,15 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
                die("Too many events are on the same function.");
 }
 
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
+void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
+                            bool force_add)
 {
        int i, j, fd;
        struct probe_point *pp;
        char buf[MAX_CMDLEN];
        char event[64];
        struct strlist *namelist;
+       bool allow_suffix;
 
        fd = open_kprobe_events(O_RDWR, O_APPEND);
        /* Get current event names */
@@ -507,21 +541,35 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
 
        for (j = 0; j < nr_probes; j++) {
                pp = probes + j;
+               if (!pp->event)
+                       pp->event = strdup(pp->function);
+               if (!pp->group)
+                       pp->group = strdup(PERFPROBE_GROUP);
+               DIE_IF(!pp->event || !pp->group);
+               /* If force_add is true, suffix search is allowed */
+               allow_suffix = force_add;
                for (i = 0; i < pp->found; i++) {
                        /* Get an unused new event name */
-                       get_new_event_name(event, 64, pp->function, namelist);
+                       get_new_event_name(event, 64, pp->event, namelist,
+                                          allow_suffix);
                        snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
                                 pp->retprobe ? 'r' : 'p',
-                                PERFPROBE_GROUP, event,
+                                pp->group, event,
                                 pp->probes[i]);
                        write_trace_kprobe_event(fd, buf);
                        printf("Added new event:\n");
                        /* Get the first parameter (probe-point) */
                        sscanf(pp->probes[i], "%s", buf);
-                       show_perf_probe_event(PERFPROBE_GROUP, event,
-                                             buf, pp);
+                       show_perf_probe_event(event, buf, pp);
                        /* Add added event name to namelist */
                        strlist__add(namelist, event);
+                       /*
+                        * Probes after the first probe which comes from same
+                        * user input are always allowed to add suffix, because
+                        * there might be several addresses corresponding to
+                        * one code line.
+                        */
+                       allow_suffix = true;
                }
        }
        /* Show how to use the event. */
@@ -532,29 +580,55 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
        close(fd);
 }
 
+static void __del_trace_kprobe_event(int fd, struct str_node *ent)
+{
+       char *p;
+       char buf[128];
+
+       /* Convert from perf-probe event to trace-kprobe event */
+       if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
+               die("Failed to copy event.");
+       p = strchr(buf + 2, ':');
+       if (!p)
+               die("Internal error: %s should have ':' but not.", ent->s);
+       *p = '/';
+
+       write_trace_kprobe_event(fd, buf);
+       printf("Remove event: %s\n", ent->s);
+}
+
 static void del_trace_kprobe_event(int fd, const char *group,
                                   const char *event, struct strlist *namelist)
 {
        char buf[128];
+       struct str_node *ent, *n;
+       int found = 0;
 
        if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
                die("Failed to copy event.");
-       if (!strlist__has_entry(namelist, buf)) {
-               pr_warning("Warning: event \"%s\" is not found.\n", buf);
-               return;
-       }
-       /* Convert from perf-probe event to trace-kprobe event */
-       if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
-               die("Failed to copy event.");
 
-       write_trace_kprobe_event(fd, buf);
-       printf("Remove event: %s:%s\n", group, event);
+       if (strpbrk(buf, "*?")) { /* Glob-exp */
+               strlist__for_each_safe(ent, n, namelist)
+                       if (strglobmatch(ent->s, buf)) {
+                               found++;
+                               __del_trace_kprobe_event(fd, ent);
+                               strlist__remove(namelist, ent);
+                       }
+       } else {
+               ent = strlist__find(namelist, buf);
+               if (ent) {
+                       found++;
+                       __del_trace_kprobe_event(fd, ent);
+                       strlist__remove(namelist, ent);
+               }
+       }
+       if (found == 0)
+               pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
 }
 
 void del_trace_kprobe_events(struct strlist *dellist)
 {
        int fd;
-       unsigned int i;
        const char *group, *event;
        char *p, *str;
        struct str_node *ent;
@@ -564,20 +638,21 @@ void del_trace_kprobe_events(struct strlist *dellist)
        /* Get current event names */
        namelist = get_perf_event_names(fd, true);
 
-       for (i = 0; i < strlist__nr_entries(dellist); i++) {
-               ent = strlist__entry(dellist, i);
+       strlist__for_each(ent, dellist) {
                str = strdup(ent->s);
                if (!str)
                        die("Failed to copy event.");
+               pr_debug("Parsing: %s\n", str);
                p = strchr(str, ':');
                if (p) {
                        group = str;
                        *p = '\0';
                        event = p + 1;
                } else {
-                       group = PERFPROBE_GROUP;
+                       group = "*";
                        event = str;
                }
+               pr_debug("Group: %s, Event: %s\n", group, event);
                del_trace_kprobe_event(fd, group, event, namelist);
                free(str);
        }