After this patch, perf utilizes builtin cflags support to build BPF
script, no longer depend on external clang.

Test:

 $ type clang
 -bash: type: clang: not found
 $ cat ~/.perfconfig
 $ echo '#define LINUX_VERSION_CODE 0x040700' > ./test.c
 $ cat ./tools/perf/tests/bpf-script-example.c >> ./test.c
 $ ./perf record -v --dry-run -e ./test.c 2>&1 | grep builtin
 bpf: builtin compiling successful

Can't pass cflags so unable to include kernel headers now. Will be
fixed by following commits.

Signed-off-by: Wang Nan <wangn...@huawei.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: He Kuang <heku...@huawei.com>
Cc: Jiri Olsa <jo...@kernel.org>
---
 tools/perf/util/bpf-loader.c  | 15 +++++++++++----
 tools/perf/util/c++/clang-c.h | 26 ++++++++++++++++++++++++++
 tools/perf/util/c++/clang.cpp | 29 +++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 2b2c9b8..a5ddb8e 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -14,11 +14,11 @@
 #include "debug.h"
 #include "bpf-loader.h"
 #include "bpf-prologue.h"
-#include "llvm-utils.h"
 #include "probe-event.h"
 #include "probe-finder.h" // for MAX_PROBES
 #include "parse-events.h"
 #include "llvm-utils.h"
+#include "c++/clang-c.h"
 
 #define DEFINE_PRINT_FN(name, level) \
 static int libbpf_##name(const char *fmt, ...) \
@@ -86,9 +86,16 @@ struct bpf_object *bpf__prepare_load(const char *filename, 
bool source)
                void *obj_buf;
                size_t obj_buf_sz;
 
-               err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
-               if (err)
-                       return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
+               perf_clang__init();
+               err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz);
+               perf_clang__cleanup();
+               if (err) {
+                       pr_debug("bpf: builtin compiling failed: %d, try 
external compiler\n", err);
+                       err = llvm__compile_bpf(filename, &obj_buf, 
&obj_buf_sz);
+                       if (err)
+                               return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
+               } else
+                       pr_debug("bpf: builtin compiling successful\n");
                obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
                free(obj_buf);
        } else
diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
index 22b3936..0eadd79 100644
--- a/tools/perf/util/c++/clang-c.h
+++ b/tools/perf/util/c++/clang-c.h
@@ -1,16 +1,42 @@
 #ifndef PERF_UTIL_CLANG_C_H
 #define PERF_UTIL_CLANG_C_H
 
+#include <stddef.h>    /* for size_t */
+#include <util-cxx.h>  /* for __maybe_unused */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#ifdef HAVE_LIBCLANGLLVM_SUPPORT
 extern void perf_clang__init(void);
 extern void perf_clang__cleanup(void);
 
 extern int test__clang_to_IR(void);
 extern int test__clang_to_obj(void);
 
+extern int perf_clang__compile_bpf(const char *filename,
+                                  void **p_obj_buf,
+                                  size_t *p_obj_buf_sz);
+#else
+
+
+static inline void perf_clang__init(void) { }
+static inline void perf_clang__cleanup(void) { }
+
+static inline int test__clang_to_IR(void) { return -1; }
+static inline int test__clang_to_obj(void) { return -1;}
+
+static inline int
+perf_clang__compile_bpf(const char *filename __maybe_unused,
+                       void **p_obj_buf __maybe_unused,
+                       size_t *p_obj_buf_sz __maybe_unused)
+{
+       return -ENOTSUP;
+}
+
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
index 38dcc14..010b91e 100644
--- a/tools/perf/util/c++/clang.cpp
+++ b/tools/perf/util/c++/clang.cpp
@@ -163,4 +163,33 @@ void perf_clang__cleanup(void)
        perf::LLVMCtx.reset(nullptr);
        llvm::llvm_shutdown();
 }
+
+int perf_clang__compile_bpf(const char *filename,
+                           void **p_obj_buf,
+                           size_t *p_obj_buf_sz)
+{
+       using namespace perf;
+
+       if (!p_obj_buf || !p_obj_buf_sz)
+               return -EINVAL;
+
+       llvm::opt::ArgStringList CFlags;
+       auto M = getModuleFromSource(std::move(CFlags), filename);
+       if (!M)
+               return  -EINVAL;
+       auto O = getBPFObjectFromModule(&*M);
+       if (!O)
+               return -EINVAL;
+
+       size_t size = O->size_in_bytes();
+       void *buffer;
+
+       buffer = malloc(size);
+       if (!buffer)
+               return -ENOMEM;
+       memcpy(buffer, O->data(), size);
+       *p_obj_buf = buffer;
+       *p_obj_buf_sz = size;
+       return 0;
+}
 }
-- 
1.8.3.4

Reply via email to