diff options
Diffstat (limited to 'tools/perf/builtin-probe.c')
-rw-r--r-- | tools/perf/builtin-probe.c | 181 |
1 files changed, 111 insertions, 70 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 3370dabed15d..92b4c491f23d 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -52,6 +52,7 @@ const char *default_search_path[NR_SEARCH_PATH] = { | |||
52 | #define MAX_PATH_LEN 256 | 52 | #define MAX_PATH_LEN 256 |
53 | #define MAX_PROBES 128 | 53 | #define MAX_PROBES 128 |
54 | #define MAX_PROBE_ARGS 128 | 54 | #define MAX_PROBE_ARGS 128 |
55 | #define PERFPROBE_GROUP "perfprobe" | ||
55 | 56 | ||
56 | /* Session management structure */ | 57 | /* Session management structure */ |
57 | static struct { | 58 | static struct { |
@@ -60,20 +61,100 @@ static struct { | |||
60 | int need_dwarf; | 61 | int need_dwarf; |
61 | int nr_probe; | 62 | int nr_probe; |
62 | struct probe_point probes[MAX_PROBES]; | 63 | struct probe_point probes[MAX_PROBES]; |
63 | char *events[MAX_PROBES]; | ||
64 | } session; | 64 | } session; |
65 | 65 | ||
66 | #define semantic_error(msg ...) die("Semantic error :" msg) | 66 | #define semantic_error(msg ...) die("Semantic error :" msg) |
67 | 67 | ||
68 | /* Parse a probe point. Note that any error must die. */ | 68 | /* Parse probe point. Return 1 if return probe */ |
69 | static void parse_probepoint(const char *str) | 69 | static void parse_probe_point(char *arg, struct probe_point *pp) |
70 | { | ||
71 | char *ptr, *tmp; | ||
72 | char c, nc; | ||
73 | /* | ||
74 | * <Syntax> | ||
75 | * perf probe SRC:LN | ||
76 | * perf probe FUNC[+OFFS|%return][@SRC] | ||
77 | */ | ||
78 | |||
79 | ptr = strpbrk(arg, ":+@%"); | ||
80 | if (ptr) { | ||
81 | nc = *ptr; | ||
82 | *ptr++ = '\0'; | ||
83 | } | ||
84 | |||
85 | /* Check arg is function or file and copy it */ | ||
86 | if (strchr(arg, '.')) /* File */ | ||
87 | pp->file = strdup(arg); | ||
88 | else /* Function */ | ||
89 | pp->function = strdup(arg); | ||
90 | DIE_IF(pp->file == NULL && pp->function == NULL); | ||
91 | |||
92 | /* Parse other options */ | ||
93 | while (ptr) { | ||
94 | arg = ptr; | ||
95 | c = nc; | ||
96 | ptr = strpbrk(arg, ":+@%"); | ||
97 | if (ptr) { | ||
98 | nc = *ptr; | ||
99 | *ptr++ = '\0'; | ||
100 | } | ||
101 | switch (c) { | ||
102 | case ':': /* Line number */ | ||
103 | pp->line = strtoul(arg, &tmp, 0); | ||
104 | if (*tmp != '\0') | ||
105 | semantic_error("There is non-digit charactor" | ||
106 | " in line number."); | ||
107 | break; | ||
108 | case '+': /* Byte offset from a symbol */ | ||
109 | pp->offset = strtoul(arg, &tmp, 0); | ||
110 | if (*tmp != '\0') | ||
111 | semantic_error("There is non-digit charactor" | ||
112 | " in offset."); | ||
113 | break; | ||
114 | case '@': /* File name */ | ||
115 | if (pp->file) | ||
116 | semantic_error("SRC@SRC is not allowed."); | ||
117 | pp->file = strdup(arg); | ||
118 | DIE_IF(pp->file == NULL); | ||
119 | if (ptr) | ||
120 | semantic_error("@SRC must be the last " | ||
121 | "option."); | ||
122 | break; | ||
123 | case '%': /* Probe places */ | ||
124 | if (strcmp(arg, "return") == 0) { | ||
125 | pp->retprobe = 1; | ||
126 | } else /* Others not supported yet */ | ||
127 | semantic_error("%%%s is not supported.", arg); | ||
128 | break; | ||
129 | default: | ||
130 | DIE_IF("Program has a bug."); | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /* Exclusion check */ | ||
136 | if (pp->line && pp->function) | ||
137 | semantic_error("Function-relative line number is not" | ||
138 | " supported yet."); | ||
139 | if (!pp->line && pp->file && !pp->function) | ||
140 | semantic_error("File always requires line number."); | ||
141 | if (pp->offset && !pp->function) | ||
142 | semantic_error("Offset requires an entry function."); | ||
143 | if (pp->retprobe && !pp->function) | ||
144 | semantic_error("Return probe requires an entry function."); | ||
145 | if (pp->offset && pp->retprobe) | ||
146 | semantic_error("Offset can't be used with return probe."); | ||
147 | |||
148 | pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", | ||
149 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe); | ||
150 | } | ||
151 | |||
152 | /* Parse an event definition. Note that any error must die. */ | ||
153 | static void parse_probe_event(const char *str) | ||
70 | { | 154 | { |
71 | char *argv[MAX_PROBE_ARGS + 2]; /* Event + probe + args */ | 155 | char *argv[MAX_PROBE_ARGS + 2]; /* Event + probe + args */ |
72 | int argc, i; | 156 | int argc, i; |
73 | char *arg, *ptr; | ||
74 | struct probe_point *pp = &session.probes[session.nr_probe]; | 157 | struct probe_point *pp = &session.probes[session.nr_probe]; |
75 | char **event = &session.events[session.nr_probe]; | ||
76 | int retp = 0; | ||
77 | 158 | ||
78 | pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); | 159 | pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); |
79 | if (++session.nr_probe == MAX_PROBES) | 160 | if (++session.nr_probe == MAX_PROBES) |
@@ -103,70 +184,28 @@ static void parse_probepoint(const char *str) | |||
103 | pr_debug("argv[%d]=%s\n", argc, argv[argc - 1]); | 184 | pr_debug("argv[%d]=%s\n", argc, argv[argc - 1]); |
104 | } | 185 | } |
105 | } while (*str != '\0'); | 186 | } while (*str != '\0'); |
106 | if (argc < 2) | 187 | if (!argc) |
107 | semantic_error("Need event-name and probe-point at least."); | 188 | semantic_error("An empty argument."); |
108 | |||
109 | /* Parse the event name */ | ||
110 | if (argv[0][0] == 'r') | ||
111 | retp = 1; | ||
112 | else if (argv[0][0] != 'p') | ||
113 | semantic_error("You must specify 'p'(kprobe) or" | ||
114 | " 'r'(kretprobe) first."); | ||
115 | /* TODO: check event name */ | ||
116 | *event = argv[0]; | ||
117 | 189 | ||
118 | /* Parse probe point */ | 190 | /* Parse probe point */ |
119 | arg = argv[1]; | 191 | parse_probe_point(argv[0], pp); |
120 | if (arg[0] == '@') { | 192 | free(argv[0]); |
121 | /* Source Line */ | ||
122 | arg++; | ||
123 | ptr = strchr(arg, ':'); | ||
124 | if (!ptr || !isdigit(ptr[1])) | ||
125 | semantic_error("Line number is required."); | ||
126 | *ptr++ = '\0'; | ||
127 | if (strlen(arg) == 0) | ||
128 | semantic_error("No file name."); | ||
129 | pp->file = strdup(arg); | ||
130 | pp->line = atoi(ptr); | ||
131 | if (!pp->file || !pp->line) | ||
132 | semantic_error("Failed to parse line."); | ||
133 | pr_debug("file:%s line:%d\n", pp->file, pp->line); | ||
134 | } else { | ||
135 | /* Function name */ | ||
136 | ptr = strchr(arg, '+'); | ||
137 | if (ptr) { | ||
138 | if (!isdigit(ptr[1])) | ||
139 | semantic_error("Offset is required."); | ||
140 | *ptr++ = '\0'; | ||
141 | pp->offset = atoi(ptr); | ||
142 | } else | ||
143 | ptr = arg; | ||
144 | ptr = strchr(ptr, '@'); | ||
145 | if (ptr) { | ||
146 | *ptr++ = '\0'; | ||
147 | pp->file = strdup(ptr); | ||
148 | } | ||
149 | pp->function = strdup(arg); | ||
150 | pr_debug("symbol:%s file:%s offset:%d\n", | ||
151 | pp->function, pp->file, pp->offset); | ||
152 | } | ||
153 | free(argv[1]); | ||
154 | if (pp->file) | 193 | if (pp->file) |
155 | session.need_dwarf = 1; | 194 | session.need_dwarf = 1; |
156 | 195 | ||
157 | /* Copy arguments */ | 196 | /* Copy arguments */ |
158 | pp->nr_args = argc - 2; | 197 | pp->nr_args = argc - 1; |
159 | if (pp->nr_args > 0) { | 198 | if (pp->nr_args > 0) { |
160 | pp->args = (char **)malloc(sizeof(char *) * pp->nr_args); | 199 | pp->args = (char **)malloc(sizeof(char *) * pp->nr_args); |
161 | if (!pp->args) | 200 | if (!pp->args) |
162 | die("malloc"); | 201 | die("malloc"); |
163 | memcpy(pp->args, &argv[2], sizeof(char *) * pp->nr_args); | 202 | memcpy(pp->args, &argv[1], sizeof(char *) * pp->nr_args); |
164 | } | 203 | } |
165 | 204 | ||
166 | /* Ensure return probe has no C argument */ | 205 | /* Ensure return probe has no C argument */ |
167 | for (i = 0; i < pp->nr_args; i++) | 206 | for (i = 0; i < pp->nr_args; i++) |
168 | if (is_c_varname(pp->args[i])) { | 207 | if (is_c_varname(pp->args[i])) { |
169 | if (retp) | 208 | if (pp->retprobe) |
170 | semantic_error("You can't specify local" | 209 | semantic_error("You can't specify local" |
171 | " variable for kretprobe"); | 210 | " variable for kretprobe"); |
172 | session.need_dwarf = 1; | 211 | session.need_dwarf = 1; |
@@ -175,11 +214,11 @@ static void parse_probepoint(const char *str) | |||
175 | pr_debug("%d arguments\n", pp->nr_args); | 214 | pr_debug("%d arguments\n", pp->nr_args); |
176 | } | 215 | } |
177 | 216 | ||
178 | static int opt_add_probepoint(const struct option *opt __used, | 217 | static int opt_add_probe_event(const struct option *opt __used, |
179 | const char *str, int unset __used) | 218 | const char *str, int unset __used) |
180 | { | 219 | { |
181 | if (str) | 220 | if (str) |
182 | parse_probepoint(str); | 221 | parse_probe_event(str); |
183 | return 0; | 222 | return 0; |
184 | } | 223 | } |
185 | 224 | ||
@@ -229,17 +268,16 @@ static const struct option options[] = { | |||
229 | #endif | 268 | #endif |
230 | OPT_CALLBACK('a', "add", NULL, | 269 | OPT_CALLBACK('a', "add", NULL, |
231 | #ifdef NO_LIBDWARF | 270 | #ifdef NO_LIBDWARF |
232 | "p|r:[GRP/]NAME FUNC[+OFFS] [ARG ...]", | 271 | "FUNC[+OFFS|%return] [ARG ...]", |
233 | #else | 272 | #else |
234 | "p|r:[GRP/]NAME FUNC[+OFFS][@SRC]|@SRC:LINE [ARG ...]", | 273 | "FUNC[+OFFS|%return][@SRC]|SRC:LINE [ARG ...]", |
235 | #endif | 274 | #endif |
236 | "probe point definition, where\n" | 275 | "probe point definition, where\n" |
237 | "\t\tp:\tkprobe probe\n" | ||
238 | "\t\tr:\tkretprobe probe\n" | ||
239 | "\t\tGRP:\tGroup name (optional)\n" | 276 | "\t\tGRP:\tGroup name (optional)\n" |
240 | "\t\tNAME:\tEvent name\n" | 277 | "\t\tNAME:\tEvent name\n" |
241 | "\t\tFUNC:\tFunction name\n" | 278 | "\t\tFUNC:\tFunction name\n" |
242 | "\t\tOFFS:\tOffset from function entry (in byte)\n" | 279 | "\t\tOFFS:\tOffset from function entry (in byte)\n" |
280 | "\t\t%return:\tPut the probe at function return\n" | ||
243 | #ifdef NO_LIBDWARF | 281 | #ifdef NO_LIBDWARF |
244 | "\t\tARG:\tProbe argument (only \n" | 282 | "\t\tARG:\tProbe argument (only \n" |
245 | #else | 283 | #else |
@@ -248,7 +286,7 @@ static const struct option options[] = { | |||
248 | "\t\tARG:\tProbe argument (local variable name or\n" | 286 | "\t\tARG:\tProbe argument (local variable name or\n" |
249 | #endif | 287 | #endif |
250 | "\t\t\tkprobe-tracer argument format is supported.)\n", | 288 | "\t\t\tkprobe-tracer argument format is supported.)\n", |
251 | opt_add_probepoint), | 289 | opt_add_probe_event), |
252 | OPT_END() | 290 | OPT_END() |
253 | }; | 291 | }; |
254 | 292 | ||
@@ -266,7 +304,7 @@ static int write_new_event(int fd, const char *buf) | |||
266 | 304 | ||
267 | #define MAX_CMDLEN 256 | 305 | #define MAX_CMDLEN 256 |
268 | 306 | ||
269 | static int synthesize_probepoint(struct probe_point *pp) | 307 | static int synthesize_probe_event(struct probe_point *pp) |
270 | { | 308 | { |
271 | char *buf; | 309 | char *buf; |
272 | int i, len, ret; | 310 | int i, len, ret; |
@@ -316,12 +354,12 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
316 | /* Synthesize probes without dwarf */ | 354 | /* Synthesize probes without dwarf */ |
317 | for (j = 0; j < session.nr_probe; j++) { | 355 | for (j = 0; j < session.nr_probe; j++) { |
318 | #ifndef NO_LIBDWARF | 356 | #ifndef NO_LIBDWARF |
319 | if (session.events[j][0] != 'r') { | 357 | if (!session.probes[j].retprobe) { |
320 | session.need_dwarf = 1; | 358 | session.need_dwarf = 1; |
321 | continue; | 359 | continue; |
322 | } | 360 | } |
323 | #endif | 361 | #endif |
324 | ret = synthesize_probepoint(&session.probes[j]); | 362 | ret = synthesize_probe_event(&session.probes[j]); |
325 | if (ret == -E2BIG) | 363 | if (ret == -E2BIG) |
326 | semantic_error("probe point is too long."); | 364 | semantic_error("probe point is too long."); |
327 | else if (ret < 0) | 365 | else if (ret < 0) |
@@ -349,7 +387,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
349 | ret = find_probepoint(fd, pp); | 387 | ret = find_probepoint(fd, pp); |
350 | if (ret <= 0) | 388 | if (ret <= 0) |
351 | die("No probe point found.\n"); | 389 | die("No probe point found.\n"); |
352 | pr_debug("probe event %s found\n", session.events[j]); | ||
353 | } | 390 | } |
354 | close(fd); | 391 | close(fd); |
355 | 392 | ||
@@ -364,13 +401,17 @@ setup_probes: | |||
364 | for (j = 0; j < session.nr_probe; j++) { | 401 | for (j = 0; j < session.nr_probe; j++) { |
365 | pp = &session.probes[j]; | 402 | pp = &session.probes[j]; |
366 | if (pp->found == 1) { | 403 | if (pp->found == 1) { |
367 | snprintf(buf, MAX_CMDLEN, "%s %s\n", | 404 | snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x %s\n", |
368 | session.events[j], pp->probes[0]); | 405 | pp->retprobe ? 'r' : 'p', PERFPROBE_GROUP, |
406 | pp->function, pp->offset, pp->probes[0]); | ||
369 | write_new_event(fd, buf); | 407 | write_new_event(fd, buf); |
370 | } else | 408 | } else |
371 | for (i = 0; i < pp->found; i++) { | 409 | for (i = 0; i < pp->found; i++) { |
372 | snprintf(buf, MAX_CMDLEN, "%s%d %s\n", | 410 | snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x_%d %s\n", |
373 | session.events[j], i, pp->probes[i]); | 411 | pp->retprobe ? 'r' : 'p', |
412 | PERFPROBE_GROUP, | ||
413 | pp->function, pp->offset, i, | ||
414 | pp->probes[0]); | ||
374 | write_new_event(fd, buf); | 415 | write_new_event(fd, buf); |
375 | } | 416 | } |
376 | } | 417 | } |