1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
4*4882a593Smuzhiyun * Copyright (C) 2015, Huawei Inc.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <errno.h>
8*4882a593Smuzhiyun #include <limits.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <unistd.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/string.h>
14*4882a593Smuzhiyun #include <linux/zalloc.h>
15*4882a593Smuzhiyun #include "debug.h"
16*4882a593Smuzhiyun #include "llvm-utils.h"
17*4882a593Smuzhiyun #include "config.h"
18*4882a593Smuzhiyun #include "util.h"
19*4882a593Smuzhiyun #include <sys/wait.h>
20*4882a593Smuzhiyun #include <subcmd/exec-cmd.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
23*4882a593Smuzhiyun "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
24*4882a593Smuzhiyun "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
25*4882a593Smuzhiyun "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
26*4882a593Smuzhiyun "-Wno-unused-value -Wno-pointer-sign " \
27*4882a593Smuzhiyun "-working-directory $WORKING_DIR " \
28*4882a593Smuzhiyun "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun struct llvm_param llvm_param = {
31*4882a593Smuzhiyun .clang_path = "clang",
32*4882a593Smuzhiyun .llc_path = "llc",
33*4882a593Smuzhiyun .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
34*4882a593Smuzhiyun .clang_opt = NULL,
35*4882a593Smuzhiyun .opts = NULL,
36*4882a593Smuzhiyun .kbuild_dir = NULL,
37*4882a593Smuzhiyun .kbuild_opts = NULL,
38*4882a593Smuzhiyun .user_set_param = false,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
perf_llvm_config(const char * var,const char * value)41*4882a593Smuzhiyun int perf_llvm_config(const char *var, const char *value)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun if (!strstarts(var, "llvm."))
44*4882a593Smuzhiyun return 0;
45*4882a593Smuzhiyun var += sizeof("llvm.") - 1;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun if (!strcmp(var, "clang-path"))
48*4882a593Smuzhiyun llvm_param.clang_path = strdup(value);
49*4882a593Smuzhiyun else if (!strcmp(var, "clang-bpf-cmd-template"))
50*4882a593Smuzhiyun llvm_param.clang_bpf_cmd_template = strdup(value);
51*4882a593Smuzhiyun else if (!strcmp(var, "clang-opt"))
52*4882a593Smuzhiyun llvm_param.clang_opt = strdup(value);
53*4882a593Smuzhiyun else if (!strcmp(var, "kbuild-dir"))
54*4882a593Smuzhiyun llvm_param.kbuild_dir = strdup(value);
55*4882a593Smuzhiyun else if (!strcmp(var, "kbuild-opts"))
56*4882a593Smuzhiyun llvm_param.kbuild_opts = strdup(value);
57*4882a593Smuzhiyun else if (!strcmp(var, "dump-obj"))
58*4882a593Smuzhiyun llvm_param.dump_obj = !!perf_config_bool(var, value);
59*4882a593Smuzhiyun else if (!strcmp(var, "opts"))
60*4882a593Smuzhiyun llvm_param.opts = strdup(value);
61*4882a593Smuzhiyun else {
62*4882a593Smuzhiyun pr_debug("Invalid LLVM config option: %s\n", value);
63*4882a593Smuzhiyun return -1;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun llvm_param.user_set_param = true;
66*4882a593Smuzhiyun return 0;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static int
search_program(const char * def,const char * name,char * output)70*4882a593Smuzhiyun search_program(const char *def, const char *name,
71*4882a593Smuzhiyun char *output)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun char *env, *path, *tmp = NULL;
74*4882a593Smuzhiyun char buf[PATH_MAX];
75*4882a593Smuzhiyun int ret;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun output[0] = '\0';
78*4882a593Smuzhiyun if (def && def[0] != '\0') {
79*4882a593Smuzhiyun if (def[0] == '/') {
80*4882a593Smuzhiyun if (access(def, F_OK) == 0) {
81*4882a593Smuzhiyun strlcpy(output, def, PATH_MAX);
82*4882a593Smuzhiyun return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun } else if (def[0] != '\0')
85*4882a593Smuzhiyun name = def;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun env = getenv("PATH");
89*4882a593Smuzhiyun if (!env)
90*4882a593Smuzhiyun return -1;
91*4882a593Smuzhiyun env = strdup(env);
92*4882a593Smuzhiyun if (!env)
93*4882a593Smuzhiyun return -1;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun ret = -ENOENT;
96*4882a593Smuzhiyun path = strtok_r(env, ":", &tmp);
97*4882a593Smuzhiyun while (path) {
98*4882a593Smuzhiyun scnprintf(buf, sizeof(buf), "%s/%s", path, name);
99*4882a593Smuzhiyun if (access(buf, F_OK) == 0) {
100*4882a593Smuzhiyun strlcpy(output, buf, PATH_MAX);
101*4882a593Smuzhiyun ret = 0;
102*4882a593Smuzhiyun break;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun path = strtok_r(NULL, ":", &tmp);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun free(env);
108*4882a593Smuzhiyun return ret;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun #define READ_SIZE 4096
112*4882a593Smuzhiyun static int
read_from_pipe(const char * cmd,void ** p_buf,size_t * p_read_sz)113*4882a593Smuzhiyun read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun int err = 0;
116*4882a593Smuzhiyun void *buf = NULL;
117*4882a593Smuzhiyun FILE *file = NULL;
118*4882a593Smuzhiyun size_t read_sz = 0, buf_sz = 0;
119*4882a593Smuzhiyun char serr[STRERR_BUFSIZE];
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun file = popen(cmd, "r");
122*4882a593Smuzhiyun if (!file) {
123*4882a593Smuzhiyun pr_err("ERROR: unable to popen cmd: %s\n",
124*4882a593Smuzhiyun str_error_r(errno, serr, sizeof(serr)));
125*4882a593Smuzhiyun return -EINVAL;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun while (!feof(file) && !ferror(file)) {
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun * Make buf_sz always have obe byte extra space so we
131*4882a593Smuzhiyun * can put '\0' there.
132*4882a593Smuzhiyun */
133*4882a593Smuzhiyun if (buf_sz - read_sz < READ_SIZE + 1) {
134*4882a593Smuzhiyun void *new_buf;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun buf_sz = read_sz + READ_SIZE + 1;
137*4882a593Smuzhiyun new_buf = realloc(buf, buf_sz);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (!new_buf) {
140*4882a593Smuzhiyun pr_err("ERROR: failed to realloc memory\n");
141*4882a593Smuzhiyun err = -ENOMEM;
142*4882a593Smuzhiyun goto errout;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun buf = new_buf;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (buf_sz - read_sz < 1) {
151*4882a593Smuzhiyun pr_err("ERROR: internal error\n");
152*4882a593Smuzhiyun err = -EINVAL;
153*4882a593Smuzhiyun goto errout;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (ferror(file)) {
157*4882a593Smuzhiyun pr_err("ERROR: error occurred when reading from pipe: %s\n",
158*4882a593Smuzhiyun str_error_r(errno, serr, sizeof(serr)));
159*4882a593Smuzhiyun err = -EIO;
160*4882a593Smuzhiyun goto errout;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun err = WEXITSTATUS(pclose(file));
164*4882a593Smuzhiyun file = NULL;
165*4882a593Smuzhiyun if (err) {
166*4882a593Smuzhiyun err = -EINVAL;
167*4882a593Smuzhiyun goto errout;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /*
171*4882a593Smuzhiyun * If buf is string, give it terminal '\0' to make our life
172*4882a593Smuzhiyun * easier. If buf is not string, that '\0' is out of space
173*4882a593Smuzhiyun * indicated by read_sz so caller won't even notice it.
174*4882a593Smuzhiyun */
175*4882a593Smuzhiyun ((char *)buf)[read_sz] = '\0';
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (!p_buf)
178*4882a593Smuzhiyun free(buf);
179*4882a593Smuzhiyun else
180*4882a593Smuzhiyun *p_buf = buf;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (p_read_sz)
183*4882a593Smuzhiyun *p_read_sz = read_sz;
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun errout:
187*4882a593Smuzhiyun if (file)
188*4882a593Smuzhiyun pclose(file);
189*4882a593Smuzhiyun free(buf);
190*4882a593Smuzhiyun if (p_buf)
191*4882a593Smuzhiyun *p_buf = NULL;
192*4882a593Smuzhiyun if (p_read_sz)
193*4882a593Smuzhiyun *p_read_sz = 0;
194*4882a593Smuzhiyun return err;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun static inline void
force_set_env(const char * var,const char * value)198*4882a593Smuzhiyun force_set_env(const char *var, const char *value)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun if (value) {
201*4882a593Smuzhiyun setenv(var, value, 1);
202*4882a593Smuzhiyun pr_debug("set env: %s=%s\n", var, value);
203*4882a593Smuzhiyun } else {
204*4882a593Smuzhiyun unsetenv(var);
205*4882a593Smuzhiyun pr_debug("unset env: %s\n", var);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun static void
version_notice(void)210*4882a593Smuzhiyun version_notice(void)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun pr_err(
213*4882a593Smuzhiyun " \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
214*4882a593Smuzhiyun " \tYou may want to try git trunk:\n"
215*4882a593Smuzhiyun " \t\tgit clone http://llvm.org/git/llvm.git\n"
216*4882a593Smuzhiyun " \t\t and\n"
217*4882a593Smuzhiyun " \t\tgit clone http://llvm.org/git/clang.git\n\n"
218*4882a593Smuzhiyun " \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n"
219*4882a593Smuzhiyun " \tdebian/ubuntu:\n"
220*4882a593Smuzhiyun " \t\thttp://llvm.org/apt\n\n"
221*4882a593Smuzhiyun " \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n"
222*4882a593Smuzhiyun " \toption in [llvm] section of ~/.perfconfig to:\n\n"
223*4882a593Smuzhiyun " \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS \\\n"
224*4882a593Smuzhiyun " \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n"
225*4882a593Smuzhiyun " \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n"
226*4882a593Smuzhiyun " \t(Replace /path/to/llc with path to your llc)\n\n"
227*4882a593Smuzhiyun );
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
detect_kbuild_dir(char ** kbuild_dir)230*4882a593Smuzhiyun static int detect_kbuild_dir(char **kbuild_dir)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun const char *test_dir = llvm_param.kbuild_dir;
233*4882a593Smuzhiyun const char *prefix_dir = "";
234*4882a593Smuzhiyun const char *suffix_dir = "";
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /* _UTSNAME_LENGTH is 65 */
237*4882a593Smuzhiyun char release[128];
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun char *autoconf_path;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun int err;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (!test_dir) {
244*4882a593Smuzhiyun err = fetch_kernel_version(NULL, release,
245*4882a593Smuzhiyun sizeof(release));
246*4882a593Smuzhiyun if (err)
247*4882a593Smuzhiyun return -EINVAL;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun test_dir = release;
250*4882a593Smuzhiyun prefix_dir = "/lib/modules/";
251*4882a593Smuzhiyun suffix_dir = "/build";
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h",
255*4882a593Smuzhiyun prefix_dir, test_dir, suffix_dir);
256*4882a593Smuzhiyun if (err < 0)
257*4882a593Smuzhiyun return -ENOMEM;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (access(autoconf_path, R_OK) == 0) {
260*4882a593Smuzhiyun free(autoconf_path);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir,
263*4882a593Smuzhiyun suffix_dir);
264*4882a593Smuzhiyun if (err < 0)
265*4882a593Smuzhiyun return -ENOMEM;
266*4882a593Smuzhiyun return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun pr_debug("%s: Couldn't find \"%s\", missing kernel-devel package?.\n",
269*4882a593Smuzhiyun __func__, autoconf_path);
270*4882a593Smuzhiyun free(autoconf_path);
271*4882a593Smuzhiyun return -ENOENT;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun static const char *kinc_fetch_script =
275*4882a593Smuzhiyun "#!/usr/bin/env sh\n"
276*4882a593Smuzhiyun "if ! test -d \"$KBUILD_DIR\"\n"
277*4882a593Smuzhiyun "then\n"
278*4882a593Smuzhiyun " exit 1\n"
279*4882a593Smuzhiyun "fi\n"
280*4882a593Smuzhiyun "if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n"
281*4882a593Smuzhiyun "then\n"
282*4882a593Smuzhiyun " exit 1\n"
283*4882a593Smuzhiyun "fi\n"
284*4882a593Smuzhiyun "TMPDIR=`mktemp -d`\n"
285*4882a593Smuzhiyun "if test -z \"$TMPDIR\"\n"
286*4882a593Smuzhiyun "then\n"
287*4882a593Smuzhiyun " exit 1\n"
288*4882a593Smuzhiyun "fi\n"
289*4882a593Smuzhiyun "cat << EOF > $TMPDIR/Makefile\n"
290*4882a593Smuzhiyun "obj-y := dummy.o\n"
291*4882a593Smuzhiyun "\\$(obj)/%.o: \\$(src)/%.c\n"
292*4882a593Smuzhiyun "\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n"
293*4882a593Smuzhiyun "\t\\$(CC) -c -o \\$@ \\$<\n"
294*4882a593Smuzhiyun "EOF\n"
295*4882a593Smuzhiyun "touch $TMPDIR/dummy.c\n"
296*4882a593Smuzhiyun "make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n"
297*4882a593Smuzhiyun "RET=$?\n"
298*4882a593Smuzhiyun "rm -rf $TMPDIR\n"
299*4882a593Smuzhiyun "exit $RET\n";
300*4882a593Smuzhiyun
llvm__get_kbuild_opts(char ** kbuild_dir,char ** kbuild_include_opts)301*4882a593Smuzhiyun void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun static char *saved_kbuild_dir;
304*4882a593Smuzhiyun static char *saved_kbuild_include_opts;
305*4882a593Smuzhiyun int err;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (!kbuild_dir || !kbuild_include_opts)
308*4882a593Smuzhiyun return;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun *kbuild_dir = NULL;
311*4882a593Smuzhiyun *kbuild_include_opts = NULL;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (saved_kbuild_dir && saved_kbuild_include_opts &&
314*4882a593Smuzhiyun !IS_ERR(saved_kbuild_dir) && !IS_ERR(saved_kbuild_include_opts)) {
315*4882a593Smuzhiyun *kbuild_dir = strdup(saved_kbuild_dir);
316*4882a593Smuzhiyun *kbuild_include_opts = strdup(saved_kbuild_include_opts);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (*kbuild_dir && *kbuild_include_opts)
319*4882a593Smuzhiyun return;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun zfree(kbuild_dir);
322*4882a593Smuzhiyun zfree(kbuild_include_opts);
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun * Don't fall through: it may breaks saved_kbuild_dir and
325*4882a593Smuzhiyun * saved_kbuild_include_opts if detect them again when
326*4882a593Smuzhiyun * memory is low.
327*4882a593Smuzhiyun */
328*4882a593Smuzhiyun return;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
332*4882a593Smuzhiyun pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
333*4882a593Smuzhiyun pr_debug("Skip kbuild options detection.\n");
334*4882a593Smuzhiyun goto errout;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun err = detect_kbuild_dir(kbuild_dir);
338*4882a593Smuzhiyun if (err) {
339*4882a593Smuzhiyun pr_warning(
340*4882a593Smuzhiyun "WARNING:\tunable to get correct kernel building directory.\n"
341*4882a593Smuzhiyun "Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
342*4882a593Smuzhiyun " \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
343*4882a593Smuzhiyun " \tdetection.\n\n");
344*4882a593Smuzhiyun goto errout;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
348*4882a593Smuzhiyun force_set_env("KBUILD_DIR", *kbuild_dir);
349*4882a593Smuzhiyun force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts);
350*4882a593Smuzhiyun err = read_from_pipe(kinc_fetch_script,
351*4882a593Smuzhiyun (void **)kbuild_include_opts,
352*4882a593Smuzhiyun NULL);
353*4882a593Smuzhiyun if (err) {
354*4882a593Smuzhiyun pr_warning(
355*4882a593Smuzhiyun "WARNING:\tunable to get kernel include directories from '%s'\n"
356*4882a593Smuzhiyun "Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n"
357*4882a593Smuzhiyun " \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n"
358*4882a593Smuzhiyun " \toption in [llvm] to \"\" to suppress this detection.\n\n",
359*4882a593Smuzhiyun *kbuild_dir);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun zfree(kbuild_dir);
362*4882a593Smuzhiyun goto errout;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun pr_debug("include option is set to %s\n", *kbuild_include_opts);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun saved_kbuild_dir = strdup(*kbuild_dir);
368*4882a593Smuzhiyun saved_kbuild_include_opts = strdup(*kbuild_include_opts);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (!saved_kbuild_dir || !saved_kbuild_include_opts) {
371*4882a593Smuzhiyun zfree(&saved_kbuild_dir);
372*4882a593Smuzhiyun zfree(&saved_kbuild_include_opts);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun return;
375*4882a593Smuzhiyun errout:
376*4882a593Smuzhiyun saved_kbuild_dir = ERR_PTR(-EINVAL);
377*4882a593Smuzhiyun saved_kbuild_include_opts = ERR_PTR(-EINVAL);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
llvm__get_nr_cpus(void)380*4882a593Smuzhiyun int llvm__get_nr_cpus(void)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun static int nr_cpus_avail = 0;
383*4882a593Smuzhiyun char serr[STRERR_BUFSIZE];
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (nr_cpus_avail > 0)
386*4882a593Smuzhiyun return nr_cpus_avail;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
389*4882a593Smuzhiyun if (nr_cpus_avail <= 0) {
390*4882a593Smuzhiyun pr_err(
391*4882a593Smuzhiyun "WARNING:\tunable to get available CPUs in this system: %s\n"
392*4882a593Smuzhiyun " \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
393*4882a593Smuzhiyun nr_cpus_avail = 128;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun return nr_cpus_avail;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
llvm__dump_obj(const char * path,void * obj_buf,size_t size)398*4882a593Smuzhiyun void llvm__dump_obj(const char *path, void *obj_buf, size_t size)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun char *obj_path = strdup(path);
401*4882a593Smuzhiyun FILE *fp;
402*4882a593Smuzhiyun char *p;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (!obj_path) {
405*4882a593Smuzhiyun pr_warning("WARNING: Not enough memory, skip object dumping\n");
406*4882a593Smuzhiyun return;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun p = strrchr(obj_path, '.');
410*4882a593Smuzhiyun if (!p || (strcmp(p, ".c") != 0)) {
411*4882a593Smuzhiyun pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n",
412*4882a593Smuzhiyun obj_path);
413*4882a593Smuzhiyun goto out;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun p[1] = 'o';
417*4882a593Smuzhiyun fp = fopen(obj_path, "wb");
418*4882a593Smuzhiyun if (!fp) {
419*4882a593Smuzhiyun pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n",
420*4882a593Smuzhiyun obj_path, strerror(errno));
421*4882a593Smuzhiyun goto out;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun pr_debug("LLVM: dumping %s\n", obj_path);
425*4882a593Smuzhiyun if (fwrite(obj_buf, size, 1, fp) != 1)
426*4882a593Smuzhiyun pr_debug("WARNING: failed to write to file '%s': %s, skip object dumping\n", obj_path, strerror(errno));
427*4882a593Smuzhiyun fclose(fp);
428*4882a593Smuzhiyun out:
429*4882a593Smuzhiyun free(obj_path);
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
llvm__compile_bpf(const char * path,void ** p_obj_buf,size_t * p_obj_buf_sz)432*4882a593Smuzhiyun int llvm__compile_bpf(const char *path, void **p_obj_buf,
433*4882a593Smuzhiyun size_t *p_obj_buf_sz)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun size_t obj_buf_sz;
436*4882a593Smuzhiyun void *obj_buf = NULL;
437*4882a593Smuzhiyun int err, nr_cpus_avail;
438*4882a593Smuzhiyun unsigned int kernel_version;
439*4882a593Smuzhiyun char linux_version_code_str[64];
440*4882a593Smuzhiyun const char *clang_opt = llvm_param.clang_opt;
441*4882a593Smuzhiyun char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
442*4882a593Smuzhiyun char serr[STRERR_BUFSIZE];
443*4882a593Smuzhiyun char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
444*4882a593Smuzhiyun *perf_bpf_include_opts = NULL;
445*4882a593Smuzhiyun const char *template = llvm_param.clang_bpf_cmd_template;
446*4882a593Smuzhiyun char *pipe_template = NULL;
447*4882a593Smuzhiyun const char *opts = llvm_param.opts;
448*4882a593Smuzhiyun char *command_echo = NULL, *command_out;
449*4882a593Smuzhiyun char *perf_include_dir = system_path(PERF_INCLUDE_DIR);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (path[0] != '-' && realpath(path, abspath) == NULL) {
452*4882a593Smuzhiyun err = errno;
453*4882a593Smuzhiyun pr_err("ERROR: problems with path %s: %s\n",
454*4882a593Smuzhiyun path, str_error_r(err, serr, sizeof(serr)));
455*4882a593Smuzhiyun return -err;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (!template)
459*4882a593Smuzhiyun template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun err = search_program(llvm_param.clang_path,
462*4882a593Smuzhiyun "clang", clang_path);
463*4882a593Smuzhiyun if (err) {
464*4882a593Smuzhiyun pr_err(
465*4882a593Smuzhiyun "ERROR:\tunable to find clang.\n"
466*4882a593Smuzhiyun "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
467*4882a593Smuzhiyun " \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
468*4882a593Smuzhiyun version_notice();
469*4882a593Smuzhiyun return -ENOENT;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /*
473*4882a593Smuzhiyun * This is an optional work. Even it fail we can continue our
474*4882a593Smuzhiyun * work. Needn't to check error return.
475*4882a593Smuzhiyun */
476*4882a593Smuzhiyun llvm__get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun nr_cpus_avail = llvm__get_nr_cpus();
479*4882a593Smuzhiyun snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
480*4882a593Smuzhiyun nr_cpus_avail);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun if (fetch_kernel_version(&kernel_version, NULL, 0))
483*4882a593Smuzhiyun kernel_version = 0;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun snprintf(linux_version_code_str, sizeof(linux_version_code_str),
486*4882a593Smuzhiyun "0x%x", kernel_version);
487*4882a593Smuzhiyun if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
488*4882a593Smuzhiyun goto errout;
489*4882a593Smuzhiyun force_set_env("NR_CPUS", nr_cpus_avail_str);
490*4882a593Smuzhiyun force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
491*4882a593Smuzhiyun force_set_env("CLANG_EXEC", clang_path);
492*4882a593Smuzhiyun force_set_env("CLANG_OPTIONS", clang_opt);
493*4882a593Smuzhiyun force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
494*4882a593Smuzhiyun force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
495*4882a593Smuzhiyun force_set_env("WORKING_DIR", kbuild_dir ? : ".");
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (opts) {
498*4882a593Smuzhiyun err = search_program(llvm_param.llc_path, "llc", llc_path);
499*4882a593Smuzhiyun if (err) {
500*4882a593Smuzhiyun pr_err("ERROR:\tunable to find llc.\n"
501*4882a593Smuzhiyun "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
502*4882a593Smuzhiyun " \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n");
503*4882a593Smuzhiyun version_notice();
504*4882a593Smuzhiyun goto errout;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun err = -ENOMEM;
508*4882a593Smuzhiyun if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
509*4882a593Smuzhiyun template, llc_path, opts) < 0) {
510*4882a593Smuzhiyun pr_err("ERROR:\tnot enough memory to setup command line\n");
511*4882a593Smuzhiyun goto errout;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun template = pipe_template;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * Since we may reset clang's working dir, path of source file
520*4882a593Smuzhiyun * should be transferred into absolute path, except we want
521*4882a593Smuzhiyun * stdin to be source file (testing).
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun force_set_env("CLANG_SOURCE",
524*4882a593Smuzhiyun (path[0] == '-') ? path : abspath);
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun pr_debug("llvm compiling command template: %s\n", template);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun err = -ENOMEM;
529*4882a593Smuzhiyun if (asprintf(&command_echo, "echo -n \"%s\"", template) < 0)
530*4882a593Smuzhiyun goto errout;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun err = read_from_pipe(command_echo, (void **) &command_out, NULL);
533*4882a593Smuzhiyun if (err)
534*4882a593Smuzhiyun goto errout;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun pr_debug("llvm compiling command : %s\n", command_out);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
539*4882a593Smuzhiyun if (err) {
540*4882a593Smuzhiyun pr_err("ERROR:\tunable to compile %s\n", path);
541*4882a593Smuzhiyun pr_err("Hint:\tCheck error message shown above.\n");
542*4882a593Smuzhiyun pr_err("Hint:\tYou can also pre-compile it into .o using:\n");
543*4882a593Smuzhiyun pr_err(" \t\tclang -target bpf -O2 -c %s\n", path);
544*4882a593Smuzhiyun pr_err(" \twith proper -I and -D options.\n");
545*4882a593Smuzhiyun goto errout;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun free(command_echo);
549*4882a593Smuzhiyun free(command_out);
550*4882a593Smuzhiyun free(kbuild_dir);
551*4882a593Smuzhiyun free(kbuild_include_opts);
552*4882a593Smuzhiyun free(perf_bpf_include_opts);
553*4882a593Smuzhiyun free(perf_include_dir);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun if (!p_obj_buf)
556*4882a593Smuzhiyun free(obj_buf);
557*4882a593Smuzhiyun else
558*4882a593Smuzhiyun *p_obj_buf = obj_buf;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun if (p_obj_buf_sz)
561*4882a593Smuzhiyun *p_obj_buf_sz = obj_buf_sz;
562*4882a593Smuzhiyun return 0;
563*4882a593Smuzhiyun errout:
564*4882a593Smuzhiyun free(command_echo);
565*4882a593Smuzhiyun free(kbuild_dir);
566*4882a593Smuzhiyun free(kbuild_include_opts);
567*4882a593Smuzhiyun free(obj_buf);
568*4882a593Smuzhiyun free(perf_bpf_include_opts);
569*4882a593Smuzhiyun free(perf_include_dir);
570*4882a593Smuzhiyun free(pipe_template);
571*4882a593Smuzhiyun if (p_obj_buf)
572*4882a593Smuzhiyun *p_obj_buf = NULL;
573*4882a593Smuzhiyun if (p_obj_buf_sz)
574*4882a593Smuzhiyun *p_obj_buf_sz = 0;
575*4882a593Smuzhiyun return err;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
llvm__search_clang(void)578*4882a593Smuzhiyun int llvm__search_clang(void)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun char clang_path[PATH_MAX];
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun return search_program(llvm_param.clang_path, "clang", clang_path);
583*4882a593Smuzhiyun }
584