aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-11-16 07:10:13 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-18 15:51:04 -0500
commita08357d8dc7d3025d1094f727ad1f7e837766f93 (patch)
tree9a53b2c350d1fcc8f93512b29ddca4a21846d8d4 /tools/perf
parentbfc077b4cf106793b30bf942e426ee99f1f4ac44 (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.c120
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
34struct bpf_prog_priv { 37struct 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
38static bool libbpf_initialized; 43static 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
374static int
375preproc_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
421errout:
422 pr_debug("Internal error in preproc_gen_prologue\n");
423 return -BPF_LOADER_ERRNO__PROLOGUE;
424}
425
426static 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
368int bpf__probe(struct bpf_object *obj) 470int 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 }
403out: 517out:
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;