From: Wang Nan <wangnan0@huawei.com>
To: <acme@kernel.org>, <ast@plumgrid.com>,
<brendan.d.gregg@gmail.com>, <daniel@iogearbox.net>,
<namhyung@kernel.org>, <masami.hiramatsu.pt@hitachi.com>,
<paulus@samba.org>, <a.p.zijlstra@chello.nl>, <mingo@redhat.com>,
<jolsa@kernel.org>, <dsahern@gmail.com>
Cc: <linux-kernel@vger.kernel.org>, <lizefan@huawei.com>,
<hekuang@huawei.com>, <xiakaixu@huawei.com>, <pi3orama@163.com>
Subject: [RFC PATCH v8 24/49] perf tools: Call clang to compile C source to object code
Date: Wed, 24 Jun 2015 12:31:28 +0000 [thread overview]
Message-ID: <1435149113-51142-25-git-send-email-wangnan0@huawei.com> (raw)
In-Reply-To: <1435149113-51142-1-git-send-email-wangnan0@huawei.com>
This is the core patch for supporting eBPF on-the-fly compiling, does
the following work:
1. Search clang compiler using search_program().
2. Run command template defined in llvm-bpf-cmd-template option in
[llvm] config section using read_from_pipe(). Patch of clang and
source code path is injected into shell command using environment
variable using force_set_env().
Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
tools/perf/util/llvm-utils.c | 222 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/llvm-utils.h | 3 +
2 files changed, 225 insertions(+)
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 7dc1f1e..c01decd 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -43,3 +43,225 @@ int perf_llvm_config(const char *var, const char *value)
return -1;
return 0;
}
+
+static int
+search_program(const char *def, const char *name,
+ char *output)
+{
+ char *env, *path, *tmp;
+ char buf[PATH_MAX];
+ int ret;
+
+ output[0] = '\0';
+ if (def && def[0] != '\0') {
+ if (def[0] == '/') {
+ if (access(def, F_OK) == 0) {
+ strlcpy(output, def, PATH_MAX);
+ return 0;
+ }
+ } else if (def[0] != '\0')
+ name = def;
+ }
+
+ env = getenv("PATH");
+ if (!env)
+ return -1;
+ env = strdup(env);
+ if (!env)
+ return -1;
+
+ ret = -ENOENT;
+ path = strtok_r(env, ":", &tmp);
+ while (path) {
+ scnprintf(buf, sizeof(buf), "%s/%s", path, name);
+ if (access(buf, F_OK) == 0) {
+ strlcpy(output, buf, PATH_MAX);
+ ret = 0;
+ break;
+ }
+ path = strtok_r(NULL, ":", &tmp);
+ }
+
+ free(env);
+ return ret;
+}
+
+#define READ_SIZE 4096
+static int
+read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
+{
+ int err = 0;
+ void *buf = NULL;
+ FILE *file = NULL;
+ size_t read_sz = 0, buf_sz = 0;
+
+ file = popen(cmd, "r");
+ if (!file) {
+ pr_err("ERROR: unable to popen cmd: %s\n",
+ strerror(errno));
+ return -EINVAL;
+ }
+
+ while (!feof(file) && !ferror(file)) {
+ /*
+ * Make buf_sz always have obe byte extra space so we
+ * can put '\0' there.
+ */
+ if (buf_sz - read_sz < READ_SIZE + 1) {
+ void *new_buf;
+
+ buf_sz = read_sz + READ_SIZE + 1;
+ new_buf = realloc(buf, buf_sz);
+
+ if (!new_buf) {
+ pr_err("ERROR: failed to realloc memory\n");
+ err = -ENOMEM;
+ goto errout;
+ }
+
+ buf = new_buf;
+ }
+ read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
+ }
+
+ if (buf_sz - read_sz < 1) {
+ pr_err("ERROR: internal error\n");
+ err = -EINVAL;
+ goto errout;
+ }
+
+ if (ferror(file)) {
+ pr_err("ERROR: error occured when reading from pipe: %s\n",
+ strerror(errno));
+ err = -EIO;
+ goto errout;
+ }
+
+ err = WEXITSTATUS(pclose(file));
+ file = NULL;
+ if (err) {
+ err = -EINVAL;
+ goto errout;
+ }
+
+ /*
+ * If buf is string, give it terminal '\0' to make our life
+ * easier. If buf is not string, that '\0' is out of space
+ * indicated by read_sz so caller won't even notice it.
+ */
+ ((char *)buf)[read_sz] = '\0';
+
+ if (!p_buf)
+ free(buf);
+ else
+ *p_buf = buf;
+
+ if (p_read_sz)
+ *p_read_sz = read_sz;
+ return 0;
+
+errout:
+ if (file)
+ pclose(file);
+ free(buf);
+ if (p_buf)
+ *p_buf = NULL;
+ if (p_read_sz)
+ *p_read_sz = 0;
+ return err;
+}
+
+static inline void
+force_set_env(const char *var, const char *value)
+{
+ if (value) {
+ setenv(var, value, 1);
+ pr_debug("set env: %s=%s\n", var, value);
+ } else {
+ unsetenv(var);
+ pr_debug("unset env: %s\n", var);
+ }
+}
+
+static void
+version_notice(void)
+{
+ pr_err(
+" \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
+" \tYou may want to try git trunk:\n"
+" \t\tgit clone http://llvm.org/git/llvm.git\n"
+" \t\t and\n"
+" \t\tgit clone http://llvm.org/git/clang.git\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 -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"
+);
+}
+
+int llvm__compile_bpf(const char *path, void **p_obj_buf,
+ size_t *p_obj_buf_sz)
+{
+ int err;
+ char clang_path[PATH_MAX];
+ const char *clang_opt = llvm_param.clang_opt;
+ const char *template = llvm_param.clang_bpf_cmd_template;
+ void *obj_buf = NULL;
+ size_t obj_buf_sz;
+
+ if (!template)
+ template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
+
+ err = search_program(llvm_param.clang_path,
+ "clang", clang_path);
+ if (err) {
+ pr_err(
+"ERROR:\tunable to find clang.\n"
+"Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
+" \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
+ version_notice();
+ return -ENOENT;
+ }
+
+ force_set_env("CLANG_EXEC", clang_path);
+ force_set_env("CLANG_OPTIONS", clang_opt);
+ force_set_env("KERNEL_INC_OPTIONS", NULL);
+ force_set_env("WORKING_DIR", ".");
+
+ /*
+ * Since we may reset clang's working dir, path of source file
+ * should be transfered into absolute path, except we want
+ * stdin to be source file (testing).
+ */
+ force_set_env("CLANG_SOURCE",
+ (path[0] == '-') ? path :
+ make_nonrelative_path(path));
+
+ pr_debug("llvm compiling command template: %s\n", template);
+ err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
+ if (err) {
+ pr_err("ERROR:\tunable to compile %s\n", path);
+ pr_err("Hint:\tCheck error message shown above.\n");
+ version_notice();
+ pr_err("Hint:\tYou can also pre-compile it into .o\n");
+ goto errout;
+ }
+
+ if (!p_obj_buf)
+ free(obj_buf);
+ else
+ *p_obj_buf = obj_buf;
+
+ if (p_obj_buf_sz)
+ *p_obj_buf_sz = obj_buf_sz;
+ return 0;
+errout:
+ free(obj_buf);
+ if (p_obj_buf)
+ *p_obj_buf = NULL;
+ if (p_obj_buf_sz)
+ *p_obj_buf_sz = 0;
+ return err;
+}
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 504b799..d23adbc 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -33,4 +33,7 @@ struct llvm_param {
extern struct llvm_param llvm_param;
extern int perf_llvm_config(const char *var, const char *value);
+
+extern int llvm__compile_bpf(const char *path, void **p_obj_buf,
+ size_t *p_obj_buf_sz);
#endif
--
1.8.3.4
next prev parent reply other threads:[~2015-06-24 12:43 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-24 12:31 [RFC PATCH v8 00/49] perf tools: filtering events using eBPF programs Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 01/49] tools build: Add feature check for eBPF API Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 02/49] bpf tools: Introduce 'bpf' library to tools Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 03/49] bpf tools: Allow caller to set printing function Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 04/49] bpf tools: Open eBPF object file and do basic validation Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 05/49] bpf tools: Read eBPF object from buffer Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 06/49] bpf tools: Check endianess and make libbpf fail early Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 07/49] bpf tools: Iterate over ELF sections to collect information Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 08/49] bpf tools: Collect version and license from ELF sections Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 09/49] bpf tools: Collect map definitions from 'maps' section Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 10/49] bpf tools: Collect symbol table from SHT_SYMTAB section Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 11/49] bpf tools: Collect eBPF programs from their own sections Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 12/49] bpf tools: Collect relocation sections from SHT_REL sections Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 13/49] bpf tools: Record map accessing instructions for each program Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 14/49] bpf tools: Add bpf.c/h for common bpf operations Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 15/49] bpf tools: Create eBPF maps defined in an object file Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 16/49] bpf tools: Relocate eBPF programs Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 17/49] bpf tools: Introduce bpf_load_program() to bpf.c Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 18/49] bpf tools: Load eBPF programs in object files into kernel Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 19/49] bpf tools: Introduce accessors for struct bpf_program Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 20/49] bpf tools: Introduce accessors for struct bpf_object Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 21/49] bpf tools: Link all bpf objects onto a list Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 22/49] perf tools: Make perf depend on libbpf Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 23/49] perf tools: Introduce llvm config options Wang Nan
2015-06-24 12:31 ` Wang Nan [this message]
2015-06-24 12:31 ` [RFC PATCH v8 25/49] perf tests: Add LLVM test for eBPF on-the-fly compiling Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 26/49] perf tools: Auto detecting kernel build directory Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 27/49] perf tools: Auto detecting kernel include options Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 28/49] perf record: Enable passing bpf object file to --event Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 29/49] perf record: Compile scriptlets if pass '.c' " Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 30/49] perf tools: Parse probe points of eBPF programs during preparation Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 31/49] perf probe: Attach trace_probe_event with perf_probe_event Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 32/49] perf record: Probe at kprobe points Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 33/49] perf record: Load all eBPF object into kernel Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 34/49] perf tools: Add bpf_fd field to evsel and config it Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 35/49] perf tools: Attach eBPF program to perf event Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 36/49] perf tools: Suppress probing messages when probing by BPF loading Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 37/49] perf record: Add clang options for compiling BPF scripts Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 38/49] bpf tools: Load instructions buffer using load_program() Wang Nan
2015-06-26 8:28 ` Alexei Starovoitov
2015-06-26 11:00 ` Wangnan (F)
2015-06-24 12:31 ` [RFC PATCH v8 39/49] bpf tools: Load a program with different instance using preprocessor Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 40/49] perf tools: Fix probe-event.h include Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 41/49] perf probe: Reset tev->args and tev->nargs when failure Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 42/49] perf tools: Move linux/filter.h to tools/include Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 43/49] perf tools: Iterater over tev instead of pev in bpf__for_each_program Wang Nan
2015-06-26 8:29 ` Alexei Starovoitov
2015-06-24 12:31 ` [RFC PATCH v8 44/49] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 45/49] perf tools: Introduce arch_get_reg_info() for x86 Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 46/49] perf tools: Add prologue for BPF programs for fetching arguments Wang Nan
2015-06-26 4:23 ` Wangnan (F)
2015-06-26 8:32 ` Alexei Starovoitov
2015-06-24 12:31 ` [RFC PATCH v8 47/49] perf tools: Generate prologue for BPF programs Wang Nan
2015-06-26 8:40 ` Alexei Starovoitov
2015-06-24 12:31 ` [RFC PATCH v8 48/49] perf tools: Use same BPF program if arguments are identical Wang Nan
2015-06-24 12:31 ` [RFC PATCH v8 49/49] perf record: Support custom vmlinux path Wang Nan
2015-06-26 8:37 ` [RFC PATCH v8 00/49] perf tools: filtering events using eBPF programs Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1435149113-51142-25-git-send-email-wangnan0@huawei.com \
--to=wangnan0@huawei.com \
--cc=a.p.zijlstra@chello.nl \
--cc=acme@kernel.org \
--cc=ast@plumgrid.com \
--cc=brendan.d.gregg@gmail.com \
--cc=daniel@iogearbox.net \
--cc=dsahern@gmail.com \
--cc=hekuang@huawei.com \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lizefan@huawei.com \
--cc=masami.hiramatsu.pt@hitachi.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=paulus@samba.org \
--cc=pi3orama@163.com \
--cc=xiakaixu@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®