aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/util/probe-event.c231
-rw-r--r--tools/perf/util/probe-event.h5
3 files changed, 230 insertions, 18 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index bf20df2e816d..b5d15cf25471 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -62,6 +62,8 @@ static struct {
62 struct probe_point probes[MAX_PROBES]; 62 struct probe_point probes[MAX_PROBES];
63} session; 63} session;
64 64
65static bool listing;
66
65/* Parse an event definition. Note that any error must die. */ 67/* Parse an event definition. Note that any error must die. */
66static void parse_probe_event(const char *str) 68static void parse_probe_event(const char *str)
67{ 69{
@@ -119,6 +121,7 @@ static int open_default_vmlinux(void)
119static const char * const probe_usage[] = { 121static const char * const probe_usage[] = {
120 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 122 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
121 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 123 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
124 "perf probe --list",
122 NULL 125 NULL
123}; 126};
124 127
@@ -129,6 +132,7 @@ static const struct option options[] = {
129 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 132 OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
130 "vmlinux/module pathname"), 133 "vmlinux/module pathname"),
131#endif 134#endif
135 OPT_BOOLEAN('l', "list", &listing, "list up current probes"),
132 OPT_CALLBACK('a', "add", NULL, 136 OPT_CALLBACK('a', "add", NULL,
133#ifdef NO_LIBDWARF 137#ifdef NO_LIBDWARF
134 "FUNC[+OFFS|%return] [ARG ...]", 138 "FUNC[+OFFS|%return] [ARG ...]",
@@ -164,9 +168,15 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
164 for (i = 0; i < argc; i++) 168 for (i = 0; i < argc; i++)
165 parse_probe_event(argv[i]); 169 parse_probe_event(argv[i]);
166 170
167 if (session.nr_probe == 0) 171 if ((session.nr_probe == 0 && !listing) ||
172 (session.nr_probe != 0 && listing))
168 usage_with_options(probe_usage, options); 173 usage_with_options(probe_usage, options);
169 174
175 if (listing) {
176 show_perf_probe_events();
177 return 0;
178 }
179
170 if (session.need_dwarf) 180 if (session.need_dwarf)
171#ifdef NO_LIBDWARF 181#ifdef NO_LIBDWARF
172 die("Debuginfo-analysis is not supported"); 182 die("Debuginfo-analysis is not supported");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e3a683ab976f..7f4f288c642e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -29,10 +29,13 @@
29#include <unistd.h> 29#include <unistd.h>
30#include <stdlib.h> 30#include <stdlib.h>
31#include <string.h> 31#include <string.h>
32#include <stdarg.h>
33#include <limits.h>
32 34
33#undef _GNU_SOURCE 35#undef _GNU_SOURCE
34#include "event.h" 36#include "event.h"
35#include "string.h" 37#include "string.h"
38#include "strlist.h"
36#include "debug.h" 39#include "debug.h"
37#include "parse-events.h" /* For debugfs_path */ 40#include "parse-events.h" /* For debugfs_path */
38#include "probe-event.h" 41#include "probe-event.h"
@@ -43,6 +46,19 @@
43 46
44#define semantic_error(msg ...) die("Semantic error :" msg) 47#define semantic_error(msg ...) die("Semantic error :" msg)
45 48
49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...)
51{
52 int ret;
53 va_list ap;
54 va_start(ap, format);
55 ret = vsnprintf(str, size, format, ap);
56 va_end(ap);
57 if (ret >= (int)size)
58 ret = -E2BIG;
59 return ret;
60}
61
46/* Parse probepoint definition. */ 62/* Parse probepoint definition. */
47static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 63static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
48{ 64{
@@ -166,6 +182,103 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
166 return need_dwarf; 182 return need_dwarf;
167} 183}
168 184
185/* Parse kprobe_events event into struct probe_point */
186void parse_trace_kprobe_event(const char *str, char **group, char **event,
187 struct probe_point *pp)
188{
189 char pr;
190 char *p;
191 int ret, i, argc;
192 char **argv;
193
194 pr_debug("Parsing kprobe_events: %s\n", str);
195 argv = argv_split(str, &argc);
196 if (!argv)
197 die("argv_split failed.");
198 if (argc < 2)
199 semantic_error("Too less arguments.");
200
201 /* Scan event and group name. */
202 ret = sscanf(argv[0], "%c:%m[^/ \t]/%m[^ \t]",
203 &pr, group, event);
204 if (ret != 3)
205 semantic_error("Failed to parse event name: %s", argv[0]);
206 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
207
208 if (!pp)
209 goto end;
210
211 pp->retprobe = (pr == 'r');
212
213 /* Scan function name and offset */
214 ret = sscanf(argv[1], "%m[^+]+%d", &pp->function, &pp->offset);
215 if (ret == 1)
216 pp->offset = 0;
217
218 /* kprobe_events doesn't have this information */
219 pp->line = 0;
220 pp->file = NULL;
221
222 pp->nr_args = argc - 2;
223 pp->args = zalloc(sizeof(char *) * pp->nr_args);
224 for (i = 0; i < pp->nr_args; i++) {
225 p = strchr(argv[i + 2], '=');
226 if (p) /* We don't need which register is assigned. */
227 *p = '\0';
228 pp->args[i] = strdup(argv[i + 2]);
229 if (!pp->args[i])
230 die("Failed to copy argument.");
231 }
232
233end:
234 argv_free(argv);
235}
236
237int synthesize_perf_probe_event(struct probe_point *pp)
238{
239 char *buf;
240 char offs[64] = "", line[64] = "";
241 int i, len, ret;
242
243 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
244 if (!buf)
245 die("Failed to allocate memory by zalloc.");
246 if (pp->offset) {
247 ret = e_snprintf(offs, 64, "+%d", pp->offset);
248 if (ret <= 0)
249 goto error;
250 }
251 if (pp->line) {
252 ret = e_snprintf(line, 64, ":%d", pp->line);
253 if (ret <= 0)
254 goto error;
255 }
256
257 if (pp->function)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line);
260 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line);
262 if (ret <= 0)
263 goto error;
264 len = ret;
265
266 for (i = 0; i < pp->nr_args; i++) {
267 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
268 pp->args[i]);
269 if (ret <= 0)
270 goto error;
271 len += ret;
272 }
273 pp->found = 1;
274
275 return pp->found;
276error:
277 free(pp->probes[0]);
278
279 return ret;
280}
281
169int synthesize_trace_kprobe_event(struct probe_point *pp) 282int synthesize_trace_kprobe_event(struct probe_point *pp)
170{ 283{
171 char *buf; 284 char *buf;
@@ -174,15 +287,15 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
174 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 287 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
175 if (!buf) 288 if (!buf)
176 die("Failed to allocate memory by zalloc."); 289 die("Failed to allocate memory by zalloc.");
177 ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 290 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
178 if (ret <= 0 || ret >= MAX_CMDLEN) 291 if (ret <= 0)
179 goto error; 292 goto error;
180 len = ret; 293 len = ret;
181 294
182 for (i = 0; i < pp->nr_args; i++) { 295 for (i = 0; i < pp->nr_args; i++) {
183 ret = snprintf(&buf[len], MAX_CMDLEN - len, " %s", 296 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
184 pp->args[i]); 297 pp->args[i]);
185 if (ret <= 0 || ret >= MAX_CMDLEN - len) 298 if (ret <= 0)
186 goto error; 299 goto error;
187 len += ret; 300 len += ret;
188 } 301 }
@@ -191,12 +304,105 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
191 return pp->found; 304 return pp->found;
192error: 305error:
193 free(pp->probes[0]); 306 free(pp->probes[0]);
194 if (ret > 0)
195 ret = -E2BIG;
196 307
197 return ret; 308 return ret;
198} 309}
199 310
311static int open_kprobe_events(int flags, int mode)
312{
313 char buf[PATH_MAX];
314 int ret;
315
316 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
317 if (ret < 0)
318 die("Failed to make kprobe_events path.");
319
320 ret = open(buf, flags, mode);
321 if (ret < 0) {
322 if (errno == ENOENT)
323 die("kprobe_events file does not exist -"
324 " please rebuild with CONFIG_KPROBE_TRACER.");
325 else
326 die("Could not open kprobe_events file: %s",
327 strerror(errno));
328 }
329 return ret;
330}
331
332/* Get raw string list of current kprobe_events */
333static struct strlist *get_trace_kprobe_event_rawlist(int fd)
334{
335 int ret, idx;
336 FILE *fp;
337 char buf[MAX_CMDLEN];
338 char *p;
339 struct strlist *sl;
340
341 sl = strlist__new(true, NULL);
342
343 fp = fdopen(dup(fd), "r");
344 while (!feof(fp)) {
345 p = fgets(buf, MAX_CMDLEN, fp);
346 if (!p)
347 break;
348
349 idx = strlen(p) - 1;
350 if (p[idx] == '\n')
351 p[idx] = '\0';
352 ret = strlist__add(sl, buf);
353 if (ret < 0)
354 die("strlist__add failed: %s", strerror(-ret));
355 }
356 fclose(fp);
357
358 return sl;
359}
360
361/* Free and zero clear probe_point */
362static void clear_probe_point(struct probe_point *pp)
363{
364 int i;
365
366 if (pp->function)
367 free(pp->function);
368 if (pp->file)
369 free(pp->file);
370 for (i = 0; i < pp->nr_args; i++)
371 free(pp->args[i]);
372 if (pp->args)
373 free(pp->args);
374 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp));
377}
378
379/* List up current perf-probe events */
380void show_perf_probe_events(void)
381{
382 unsigned int i;
383 int fd;
384 char *group, *event;
385 struct probe_point pp;
386 struct strlist *rawlist;
387 struct str_node *ent;
388
389 fd = open_kprobe_events(O_RDONLY, 0);
390 rawlist = get_trace_kprobe_event_rawlist(fd);
391 close(fd);
392
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
394 ent = strlist__entry(rawlist, i);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
396 synthesize_perf_probe_event(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]);
398 free(group);
399 free(event);
400 clear_probe_point(&pp);
401 }
402
403 strlist__delete(rawlist);
404}
405
200static int write_trace_kprobe_event(int fd, const char *buf) 406static int write_trace_kprobe_event(int fd, const char *buf)
201{ 407{
202 int ret; 408 int ret;
@@ -216,16 +422,7 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
216 struct probe_point *pp; 422 struct probe_point *pp;
217 char buf[MAX_CMDLEN]; 423 char buf[MAX_CMDLEN];
218 424
219 snprintf(buf, MAX_CMDLEN, "%s/../kprobe_events", debugfs_path); 425 fd = open_kprobe_events(O_WRONLY, O_APPEND);
220 fd = open(buf, O_WRONLY, O_APPEND);
221 if (fd < 0) {
222 if (errno == ENOENT)
223 die("kprobe_events file does not exist -"
224 " please rebuild with CONFIG_KPROBE_TRACER.");
225 else
226 die("Could not open kprobe_events file: %s",
227 strerror(errno));
228 }
229 426
230 for (j = 0; j < nr_probes; j++) { 427 for (j = 0; j < nr_probes; j++) {
231 pp = probes + j; 428 pp = probes + j;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 0089c455ecac..88db7d1a9472 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,9 +2,14 @@
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include "probe-finder.h" 4#include "probe-finder.h"
5#include "strlist.h"
5 6
6extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 7extern int parse_perf_probe_event(const char *str, struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group,
10 char **event, struct probe_point *pp);
7extern int synthesize_trace_kprobe_event(struct probe_point *pp); 11extern int synthesize_trace_kprobe_event(struct probe_point *pp);
8extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
13extern void show_perf_probe_events(void);
9 14
10#endif /*_PROBE_EVENT_H */ 15#endif /*_PROBE_EVENT_H */