diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 222 |
1 files changed, 156 insertions, 66 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d14a4585bcaf..29465d440043 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -62,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) return ret; } +/* Check the name is good for event/group */ +static bool check_event_name(const char *name) +{ + if (!isalpha(*name) && *name != '_') + return false; + while (*++name != '\0') { + if (!isalpha(*name) && !isdigit(*name) && *name != '_') + return false; + } + return true; +} + /* Parse probepoint definition. */ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) { @@ -69,10 +81,26 @@ 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."); + if (!check_event_name(arg)) + semantic_error("%s is bad for event name -it must " + "follow C symbol-naming rule.", arg); + pp->event = strdup(arg); + arg = tmp; + } + ptr = strpbrk(arg, ":+@%"); if (ptr) { nc = *ptr; @@ -150,10 +178,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 +195,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 +208,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 +232,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 +261,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 +290,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 +320,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 +350,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 +410,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 +428,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 +450,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 +459,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 +474,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 +511,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 +522,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 +540,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 +556,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 +595,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 +653,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); } |