diff options
Diffstat (limited to 'tools/perf/util/llvm-utils.c')
-rw-r--r-- | tools/perf/util/llvm-utils.c | 68 |
1 files changed, 59 insertions, 9 deletions
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 4952b429caa7..19262f98cd4e 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -14,19 +14,22 @@ #include "config.h" #include "util.h" #include <sys/wait.h> +#include <subcmd/exec-cmd.h> #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ - "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \ + "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \ "-Wno-unused-value -Wno-pointer-sign " \ "-working-directory $WORKING_DIR " \ - "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -" + "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE" struct llvm_param llvm_param = { .clang_path = "clang", + .llc_path = "llc", .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, .clang_opt = NULL, + .opts = NULL, .kbuild_dir = NULL, .kbuild_opts = NULL, .user_set_param = false, @@ -50,6 +53,8 @@ int perf_llvm_config(const char *var, const char *value) llvm_param.kbuild_opts = strdup(value); else if (!strcmp(var, "dump-obj")) llvm_param.dump_obj = !!perf_config_bool(var, value); + else if (!strcmp(var, "opts")) + llvm_param.opts = strdup(value); else { pr_debug("Invalid LLVM config option: %s\n", value); return -1; @@ -212,7 +217,7 @@ version_notice(void) " \t\thttp://llvm.org/apt\n\n" " \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n" " \toption in [llvm] section of ~/.perfconfig to:\n\n" -" \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS \\\n" +" \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS \\\n" " \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n" " \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n" " \t(Replace /path/to/llc with path to your llc)\n\n" @@ -265,16 +270,16 @@ static const char *kinc_fetch_script = "#!/usr/bin/env sh\n" "if ! test -d \"$KBUILD_DIR\"\n" "then\n" -" exit -1\n" +" exit 1\n" "fi\n" "if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n" "then\n" -" exit -1\n" +" exit 1\n" "fi\n" "TMPDIR=`mktemp -d`\n" "if test -z \"$TMPDIR\"\n" "then\n" -" exit -1\n" +" exit 1\n" "fi\n" "cat << EOF > $TMPDIR/Makefile\n" "obj-y := dummy.o\n" @@ -429,10 +434,15 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, unsigned int kernel_version; char linux_version_code_str[64]; const char *clang_opt = llvm_param.clang_opt; - char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; + char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64]; char serr[STRERR_BUFSIZE]; - char *kbuild_dir = NULL, *kbuild_include_opts = NULL; + char *kbuild_dir = NULL, *kbuild_include_opts = NULL, + *perf_bpf_include_opts = NULL; const char *template = llvm_param.clang_bpf_cmd_template; + char *pipe_template = NULL; + const char *opts = llvm_param.opts; + char *command_echo = NULL, *command_out; + char *perf_include_dir = system_path(PERF_INCLUDE_DIR); if (path[0] != '-' && realpath(path, abspath) == NULL) { err = errno; @@ -470,14 +480,36 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, snprintf(linux_version_code_str, sizeof(linux_version_code_str), "0x%x", kernel_version); - + if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0) + goto errout; force_set_env("NR_CPUS", nr_cpus_avail_str); force_set_env("LINUX_VERSION_CODE", linux_version_code_str); force_set_env("CLANG_EXEC", clang_path); force_set_env("CLANG_OPTIONS", clang_opt); force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); + force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts); force_set_env("WORKING_DIR", kbuild_dir ? : "."); + if (opts) { + err = search_program(llvm_param.llc_path, "llc", llc_path); + if (err) { + pr_err("ERROR:\tunable to find llc.\n" + "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n" + " \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n"); + version_notice(); + goto errout; + } + + if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -", + template, llc_path, opts) < 0) { + pr_err("ERROR:\tnot enough memory to setup command line\n"); + goto errout; + } + + template = pipe_template; + + } + /* * Since we may reset clang's working dir, path of source file * should be transferred into absolute path, except we want @@ -487,6 +519,16 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, (path[0] == '-') ? path : abspath); pr_debug("llvm compiling command template: %s\n", template); + + if (asprintf(&command_echo, "echo -n \"%s\"", template) < 0) + goto errout; + + err = read_from_pipe(command_echo, (void **) &command_out, NULL); + if (err) + goto errout; + + pr_debug("llvm compiling command : %s\n", command_out); + err = read_from_pipe(template, &obj_buf, &obj_buf_sz); if (err) { pr_err("ERROR:\tunable to compile %s\n", path); @@ -497,8 +539,12 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, goto errout; } + free(command_echo); + free(command_out); free(kbuild_dir); free(kbuild_include_opts); + free(perf_bpf_include_opts); + free(perf_include_dir); if (!p_obj_buf) free(obj_buf); @@ -509,9 +555,13 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, *p_obj_buf_sz = obj_buf_sz; return 0; errout: + free(command_echo); free(kbuild_dir); free(kbuild_include_opts); free(obj_buf); + free(perf_bpf_include_opts); + free(perf_include_dir); + free(pipe_template); if (p_obj_buf) *p_obj_buf = NULL; if (p_obj_buf_sz) |