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