[RFC PATCH v3 30/37] perf bpf: Add bpf-loader and open ELF object files

Wang Nan
2015-05-17T11:00:29Z

bpf_prepare_laod() is used to open each eBPF object files. The
returned handlers are stored into an array. A corresponding bpf_clear()
is introduced to free all resources.

For the propose of logging, 3 printing functions are defined using
DEFINE_PRINT_FN, which require a veprintf to process va_list args.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
tools/perf/builtin-bpf.c | 12 +++++++-
tools/perf/util/Build | 1 +
tools/perf/util/bpf-loader.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/bpf-loader.h | 13 +++++++++
tools/perf/util/debug.c | 5 ++++
tools/perf/util/debug.h | 1 +
6 files changed, 100 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/util/bpf-loader.c
create mode 100644 tools/perf/util/bpf-loader.h

diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
index b5c613f..e922921 100644
--- a/tools/perf/builtin-bpf.c
+++ b/tools/perf/builtin-bpf.c
@@ -12,6 +12,7 @@
#include "perf.h"
#include "debug.h"
#include "parse-options.h"
+#include "bpf-loader.h"

typedef int (*bpf_cmd_fn_t)(int argc, const char **argv, const char *prefix);

@@ -124,6 +125,7 @@ static int cmd_bpf_record(int argc, const char **argv,
OPT_END()
};
struct str_node *str_node;
+ int err;

argc = parse_options(argc, argv, options,
bpf_record_usage, PARSE_OPT_KEEP_DASHDASH);
@@ -144,8 +146,16 @@ static int cmd_bpf_record(int argc, const char **argv,
argc--;
argv++;

- strlist__for_each(str_node, param.object_file_names)
+ strlist__for_each(str_node, param.object_file_names) {
+ const char *fn = str_node->s;
+
pr_debug("loading %s\n", str_node->s);
+ if ((err = bpf_prepare_load(fn))) {
+ pr_err("bpf: failed to load object file %s\n",
+ fn);
+ return -1;
+ }
+ }

return start_bpf_record(argc, argv);
usage:
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 797490a..609f6d6 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -75,6 +75,7 @@ libperf-$(CONFIG_X86) += tsc.o
libperf-y += cloexec.o
libperf-y += thread-stack.o

+libperf-$(CONFIG_LIBELF) += bpf-loader.o
libperf-$(CONFIG_LIBELF) += symbol-elf.o
libperf-$(CONFIG_LIBELF) += probe-event.o

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
new file mode 100644
index 0000000..17cd2b6
--- /dev/null
+++ b/tools/perf/util/bpf-loader.c
@@ -0,0 +1,69 @@
+/*
+ * bpf-loader.c
+ *
+ * Load bpf files into kernel using libbpf; create kprobe events.
+ */
+
+#include <bpf/libbpf.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-loader.h"
+
+#define DEFINE_PRINT_FN(name, level) \
+static int libbpf_##name(const char *fmt, ...) \
+{ \
+ va_list args; \
+ int ret; \
+ \
+ va_start(args, fmt); \
+ ret = veprintf(level, verbose, pr_fmt(fmt), args);\
+ va_end(args); \
+ return ret; \
+}
+
+DEFINE_PRINT_FN(warning, 0)
+DEFINE_PRINT_FN(info, 0)
+DEFINE_PRINT_FN(debug, 1)
+
+static bool libbpf_inited = false;
+
+#define MAX_OBJECTS 128
+
+struct {
+ struct bpf_object *objects[MAX_OBJECTS];
+ size_t nr_objects;
+} params;
+
+int bpf_prepare_load(const char *filename)
+{
+ struct bpf_object *obj;
+
+ if (!libbpf_inited)
+ libbpf_set_print(libbpf_warning,
+ libbpf_info,
+ libbpf_debug);
+
+ pr_debug("bpf: loading %s\n", filename);
+ if (params.nr_objects + 1 > MAX_OBJECTS) {
+ pr_err("Too many objects to load. "
+ "Increase MAX_OBJECTS\n");
+ return -EMFILE;
+ }
+
+ obj = bpf_open_object(filename);
+ if (!obj) {
+ pr_err("bpf: failed to load %s\n", filename);
+ return -EINVAL;
+ }
+
+ params.objects[params.nr_objects++] = obj;
+ return 0;
+}
+
+void bpf_clear(void)
+{
+ size_t i;
+
+ for (i = 0; i < params.nr_objects; i++)
+ bpf_close_object(params.objects[i]);
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
new file mode 100644
index 0000000..74eebc3
--- /dev/null
+++ b/tools/perf/util/bpf-loader.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+#ifndef __BPF_LOADER_H
+#define __BPF_LOADER_H
+
+int bpf_prepare_load(const char *filename);
+
+void bpf_clear(void);
+#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 2da5581..86d9c73 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -36,6 +36,11 @@ static int _eprintf(int level, int var, const char *fmt, va_list args)
return ret;
}

+int veprintf(int level, int var, const char *fmt, va_list args)
+{
+ return _eprintf(level, var, fmt, args);
+}
+
int eprintf(int level, int var, const char *fmt, ...)
{
va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index caac2fd..8b9a088 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -50,6 +50,7 @@ void pr_stat(const char *fmt, ...);

int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
+int veprintf(int level, int var, const char *fmt, va_list args);

int perf_debug_option(const char *str);

--
1.8.3.4