diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-11-16 07:10:13 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-11-18 15:51:04 -0500 |
commit | a08357d8dc7d3025d1094f727ad1f7e837766f93 (patch) | |
tree | 9a53b2c350d1fcc8f93512b29ddca4a21846d8d4 /tools/perf | |
parent | bfc077b4cf106793b30bf942e426ee99f1f4ac44 (diff) |
perf bpf: Generate prologue for BPF programs
This patch generates a prologue for each 'struct probe_trace_event' for
fetching arguments for BPF programs.
After bpf__probe(), iterate over each program to check whether prologues are
required. If none of the 'struct perf_probe_event' programs will attach to have
at least one argument, simply skip preprocessor hooking. For those who a
prologue is required, call bpf__gen_prologue() and paste the original
instruction after the prologue.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1447675815-166222-12-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/bpf-loader.c | 120 |
1 files changed, 119 insertions, 1 deletions
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index bd14be438cda..190a1c7f0649 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -5,12 +5,15 @@ | |||
5 | * Copyright (C) 2015 Huawei Inc. | 5 | * Copyright (C) 2015 Huawei Inc. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/bpf.h> | ||
8 | #include <bpf/libbpf.h> | 9 | #include <bpf/libbpf.h> |
9 | #include <linux/err.h> | 10 | #include <linux/err.h> |
10 | #include <linux/string.h> | 11 | #include <linux/string.h> |
11 | #include "perf.h" | 12 | #include "perf.h" |
12 | #include "debug.h" | 13 | #include "debug.h" |
13 | #include "bpf-loader.h" | 14 | #include "bpf-loader.h" |
15 | #include "bpf-prologue.h" | ||
16 | #include "llvm-utils.h" | ||
14 | #include "probe-event.h" | 17 | #include "probe-event.h" |
15 | #include "probe-finder.h" // for MAX_PROBES | 18 | #include "probe-finder.h" // for MAX_PROBES |
16 | #include "llvm-utils.h" | 19 | #include "llvm-utils.h" |
@@ -33,6 +36,8 @@ DEFINE_PRINT_FN(debug, 1) | |||
33 | 36 | ||
34 | struct bpf_prog_priv { | 37 | struct bpf_prog_priv { |
35 | struct perf_probe_event pev; | 38 | struct perf_probe_event pev; |
39 | bool need_prologue; | ||
40 | struct bpf_insn *insns_buf; | ||
36 | }; | 41 | }; |
37 | 42 | ||
38 | static bool libbpf_initialized; | 43 | static bool libbpf_initialized; |
@@ -107,6 +112,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, | |||
107 | struct bpf_prog_priv *priv = _priv; | 112 | struct bpf_prog_priv *priv = _priv; |
108 | 113 | ||
109 | cleanup_perf_probe_events(&priv->pev, 1); | 114 | cleanup_perf_probe_events(&priv->pev, 1); |
115 | zfree(&priv->insns_buf); | ||
110 | free(priv); | 116 | free(priv); |
111 | } | 117 | } |
112 | 118 | ||
@@ -365,6 +371,102 @@ static int bpf__prepare_probe(void) | |||
365 | return err; | 371 | return err; |
366 | } | 372 | } |
367 | 373 | ||
374 | static int | ||
375 | preproc_gen_prologue(struct bpf_program *prog, int n, | ||
376 | struct bpf_insn *orig_insns, int orig_insns_cnt, | ||
377 | struct bpf_prog_prep_result *res) | ||
378 | { | ||
379 | struct probe_trace_event *tev; | ||
380 | struct perf_probe_event *pev; | ||
381 | struct bpf_prog_priv *priv; | ||
382 | struct bpf_insn *buf; | ||
383 | size_t prologue_cnt = 0; | ||
384 | int err; | ||
385 | |||
386 | err = bpf_program__get_private(prog, (void **)&priv); | ||
387 | if (err || !priv) | ||
388 | goto errout; | ||
389 | |||
390 | pev = &priv->pev; | ||
391 | |||
392 | if (n < 0 || n >= pev->ntevs) | ||
393 | goto errout; | ||
394 | |||
395 | tev = &pev->tevs[n]; | ||
396 | |||
397 | buf = priv->insns_buf; | ||
398 | err = bpf__gen_prologue(tev->args, tev->nargs, | ||
399 | buf, &prologue_cnt, | ||
400 | BPF_MAXINSNS - orig_insns_cnt); | ||
401 | if (err) { | ||
402 | const char *title; | ||
403 | |||
404 | title = bpf_program__title(prog, false); | ||
405 | if (!title) | ||
406 | title = "[unknown]"; | ||
407 | |||
408 | pr_debug("Failed to generate prologue for program %s\n", | ||
409 | title); | ||
410 | return err; | ||
411 | } | ||
412 | |||
413 | memcpy(&buf[prologue_cnt], orig_insns, | ||
414 | sizeof(struct bpf_insn) * orig_insns_cnt); | ||
415 | |||
416 | res->new_insn_ptr = buf; | ||
417 | res->new_insn_cnt = prologue_cnt + orig_insns_cnt; | ||
418 | res->pfd = NULL; | ||
419 | return 0; | ||
420 | |||
421 | errout: | ||
422 | pr_debug("Internal error in preproc_gen_prologue\n"); | ||
423 | return -BPF_LOADER_ERRNO__PROLOGUE; | ||
424 | } | ||
425 | |||
426 | static int hook_load_preprocessor(struct bpf_program *prog) | ||
427 | { | ||
428 | struct perf_probe_event *pev; | ||
429 | struct bpf_prog_priv *priv; | ||
430 | bool need_prologue = false; | ||
431 | int err, i; | ||
432 | |||
433 | err = bpf_program__get_private(prog, (void **)&priv); | ||
434 | if (err || !priv) { | ||
435 | pr_debug("Internal error when hook preprocessor\n"); | ||
436 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
437 | } | ||
438 | |||
439 | pev = &priv->pev; | ||
440 | for (i = 0; i < pev->ntevs; i++) { | ||
441 | struct probe_trace_event *tev = &pev->tevs[i]; | ||
442 | |||
443 | if (tev->nargs > 0) { | ||
444 | need_prologue = true; | ||
445 | break; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Since all tevs don't have argument, we don't need generate | ||
451 | * prologue. | ||
452 | */ | ||
453 | if (!need_prologue) { | ||
454 | priv->need_prologue = false; | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | priv->need_prologue = true; | ||
459 | priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS); | ||
460 | if (!priv->insns_buf) { | ||
461 | pr_debug("No enough memory: alloc insns_buf failed\n"); | ||
462 | return -ENOMEM; | ||
463 | } | ||
464 | |||
465 | err = bpf_program__set_prep(prog, pev->ntevs, | ||
466 | preproc_gen_prologue); | ||
467 | return err; | ||
468 | } | ||
469 | |||
368 | int bpf__probe(struct bpf_object *obj) | 470 | int bpf__probe(struct bpf_object *obj) |
369 | { | 471 | { |
370 | int err = 0; | 472 | int err = 0; |
@@ -399,6 +501,18 @@ int bpf__probe(struct bpf_object *obj) | |||
399 | pr_debug("bpf_probe: failed to apply perf probe events"); | 501 | pr_debug("bpf_probe: failed to apply perf probe events"); |
400 | goto out; | 502 | goto out; |
401 | } | 503 | } |
504 | |||
505 | /* | ||
506 | * After probing, let's consider prologue, which | ||
507 | * adds program fetcher to BPF programs. | ||
508 | * | ||
509 | * hook_load_preprocessorr() hooks pre-processor | ||
510 | * to bpf_program, let it generate prologue | ||
511 | * dynamically during loading. | ||
512 | */ | ||
513 | err = hook_load_preprocessor(prog); | ||
514 | if (err) | ||
515 | goto out; | ||
402 | } | 516 | } |
403 | out: | 517 | out: |
404 | return err < 0 ? err : 0; | 518 | return err < 0 ? err : 0; |
@@ -482,7 +596,11 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
482 | for (i = 0; i < pev->ntevs; i++) { | 596 | for (i = 0; i < pev->ntevs; i++) { |
483 | tev = &pev->tevs[i]; | 597 | tev = &pev->tevs[i]; |
484 | 598 | ||
485 | fd = bpf_program__fd(prog); | 599 | if (priv->need_prologue) |
600 | fd = bpf_program__nth_fd(prog, i); | ||
601 | else | ||
602 | fd = bpf_program__fd(prog); | ||
603 | |||
486 | if (fd < 0) { | 604 | if (fd < 0) { |
487 | pr_debug("bpf: failed to get file descriptor\n"); | 605 | pr_debug("bpf: failed to get file descriptor\n"); |
488 | return fd; | 606 | return fd; |