18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
48c2ecf20Sopenharmony_ci * Copyright (C) 2015, Huawei Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <limits.h>
98c2ecf20Sopenharmony_ci#include <stdio.h>
108c2ecf20Sopenharmony_ci#include <stdlib.h>
118c2ecf20Sopenharmony_ci#include <unistd.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/string.h>
148c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
158c2ecf20Sopenharmony_ci#include "debug.h"
168c2ecf20Sopenharmony_ci#include "llvm-utils.h"
178c2ecf20Sopenharmony_ci#include "config.h"
188c2ecf20Sopenharmony_ci#include "util.h"
198c2ecf20Sopenharmony_ci#include <sys/wait.h>
208c2ecf20Sopenharmony_ci#include <subcmd/exec-cmd.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define CLANG_BPF_CMD_DEFAULT_TEMPLATE				\
238c2ecf20Sopenharmony_ci		"$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
248c2ecf20Sopenharmony_ci		"-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE "	\
258c2ecf20Sopenharmony_ci		"$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
268c2ecf20Sopenharmony_ci		"-Wno-unused-value -Wno-pointer-sign "		\
278c2ecf20Sopenharmony_ci		"-working-directory $WORKING_DIR "		\
288c2ecf20Sopenharmony_ci		"-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct llvm_param llvm_param = {
318c2ecf20Sopenharmony_ci	.clang_path = "clang",
328c2ecf20Sopenharmony_ci	.llc_path = "llc",
338c2ecf20Sopenharmony_ci	.clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
348c2ecf20Sopenharmony_ci	.clang_opt = NULL,
358c2ecf20Sopenharmony_ci	.opts = NULL,
368c2ecf20Sopenharmony_ci	.kbuild_dir = NULL,
378c2ecf20Sopenharmony_ci	.kbuild_opts = NULL,
388c2ecf20Sopenharmony_ci	.user_set_param = false,
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciint perf_llvm_config(const char *var, const char *value)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	if (!strstarts(var, "llvm."))
448c2ecf20Sopenharmony_ci		return 0;
458c2ecf20Sopenharmony_ci	var += sizeof("llvm.") - 1;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (!strcmp(var, "clang-path"))
488c2ecf20Sopenharmony_ci		llvm_param.clang_path = strdup(value);
498c2ecf20Sopenharmony_ci	else if (!strcmp(var, "clang-bpf-cmd-template"))
508c2ecf20Sopenharmony_ci		llvm_param.clang_bpf_cmd_template = strdup(value);
518c2ecf20Sopenharmony_ci	else if (!strcmp(var, "clang-opt"))
528c2ecf20Sopenharmony_ci		llvm_param.clang_opt = strdup(value);
538c2ecf20Sopenharmony_ci	else if (!strcmp(var, "kbuild-dir"))
548c2ecf20Sopenharmony_ci		llvm_param.kbuild_dir = strdup(value);
558c2ecf20Sopenharmony_ci	else if (!strcmp(var, "kbuild-opts"))
568c2ecf20Sopenharmony_ci		llvm_param.kbuild_opts = strdup(value);
578c2ecf20Sopenharmony_ci	else if (!strcmp(var, "dump-obj"))
588c2ecf20Sopenharmony_ci		llvm_param.dump_obj = !!perf_config_bool(var, value);
598c2ecf20Sopenharmony_ci	else if (!strcmp(var, "opts"))
608c2ecf20Sopenharmony_ci		llvm_param.opts = strdup(value);
618c2ecf20Sopenharmony_ci	else {
628c2ecf20Sopenharmony_ci		pr_debug("Invalid LLVM config option: %s\n", value);
638c2ecf20Sopenharmony_ci		return -1;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci	llvm_param.user_set_param = true;
668c2ecf20Sopenharmony_ci	return 0;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int
708c2ecf20Sopenharmony_cisearch_program(const char *def, const char *name,
718c2ecf20Sopenharmony_ci	       char *output)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	char *env, *path, *tmp = NULL;
748c2ecf20Sopenharmony_ci	char buf[PATH_MAX];
758c2ecf20Sopenharmony_ci	int ret;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	output[0] = '\0';
788c2ecf20Sopenharmony_ci	if (def && def[0] != '\0') {
798c2ecf20Sopenharmony_ci		if (def[0] == '/') {
808c2ecf20Sopenharmony_ci			if (access(def, F_OK) == 0) {
818c2ecf20Sopenharmony_ci				strlcpy(output, def, PATH_MAX);
828c2ecf20Sopenharmony_ci				return 0;
838c2ecf20Sopenharmony_ci			}
848c2ecf20Sopenharmony_ci		} else if (def[0] != '\0')
858c2ecf20Sopenharmony_ci			name = def;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	env = getenv("PATH");
898c2ecf20Sopenharmony_ci	if (!env)
908c2ecf20Sopenharmony_ci		return -1;
918c2ecf20Sopenharmony_ci	env = strdup(env);
928c2ecf20Sopenharmony_ci	if (!env)
938c2ecf20Sopenharmony_ci		return -1;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = -ENOENT;
968c2ecf20Sopenharmony_ci	path = strtok_r(env, ":",  &tmp);
978c2ecf20Sopenharmony_ci	while (path) {
988c2ecf20Sopenharmony_ci		scnprintf(buf, sizeof(buf), "%s/%s", path, name);
998c2ecf20Sopenharmony_ci		if (access(buf, F_OK) == 0) {
1008c2ecf20Sopenharmony_ci			strlcpy(output, buf, PATH_MAX);
1018c2ecf20Sopenharmony_ci			ret = 0;
1028c2ecf20Sopenharmony_ci			break;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci		path = strtok_r(NULL, ":", &tmp);
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	free(env);
1088c2ecf20Sopenharmony_ci	return ret;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define READ_SIZE	4096
1128c2ecf20Sopenharmony_cistatic int
1138c2ecf20Sopenharmony_ciread_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	int err = 0;
1168c2ecf20Sopenharmony_ci	void *buf = NULL;
1178c2ecf20Sopenharmony_ci	FILE *file = NULL;
1188c2ecf20Sopenharmony_ci	size_t read_sz = 0, buf_sz = 0;
1198c2ecf20Sopenharmony_ci	char serr[STRERR_BUFSIZE];
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	file = popen(cmd, "r");
1228c2ecf20Sopenharmony_ci	if (!file) {
1238c2ecf20Sopenharmony_ci		pr_err("ERROR: unable to popen cmd: %s\n",
1248c2ecf20Sopenharmony_ci		       str_error_r(errno, serr, sizeof(serr)));
1258c2ecf20Sopenharmony_ci		return -EINVAL;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	while (!feof(file) && !ferror(file)) {
1298c2ecf20Sopenharmony_ci		/*
1308c2ecf20Sopenharmony_ci		 * Make buf_sz always have obe byte extra space so we
1318c2ecf20Sopenharmony_ci		 * can put '\0' there.
1328c2ecf20Sopenharmony_ci		 */
1338c2ecf20Sopenharmony_ci		if (buf_sz - read_sz < READ_SIZE + 1) {
1348c2ecf20Sopenharmony_ci			void *new_buf;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci			buf_sz = read_sz + READ_SIZE + 1;
1378c2ecf20Sopenharmony_ci			new_buf = realloc(buf, buf_sz);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci			if (!new_buf) {
1408c2ecf20Sopenharmony_ci				pr_err("ERROR: failed to realloc memory\n");
1418c2ecf20Sopenharmony_ci				err = -ENOMEM;
1428c2ecf20Sopenharmony_ci				goto errout;
1438c2ecf20Sopenharmony_ci			}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci			buf = new_buf;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (buf_sz - read_sz < 1) {
1518c2ecf20Sopenharmony_ci		pr_err("ERROR: internal error\n");
1528c2ecf20Sopenharmony_ci		err = -EINVAL;
1538c2ecf20Sopenharmony_ci		goto errout;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (ferror(file)) {
1578c2ecf20Sopenharmony_ci		pr_err("ERROR: error occurred when reading from pipe: %s\n",
1588c2ecf20Sopenharmony_ci		       str_error_r(errno, serr, sizeof(serr)));
1598c2ecf20Sopenharmony_ci		err = -EIO;
1608c2ecf20Sopenharmony_ci		goto errout;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	err = WEXITSTATUS(pclose(file));
1648c2ecf20Sopenharmony_ci	file = NULL;
1658c2ecf20Sopenharmony_ci	if (err) {
1668c2ecf20Sopenharmony_ci		err = -EINVAL;
1678c2ecf20Sopenharmony_ci		goto errout;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/*
1718c2ecf20Sopenharmony_ci	 * If buf is string, give it terminal '\0' to make our life
1728c2ecf20Sopenharmony_ci	 * easier. If buf is not string, that '\0' is out of space
1738c2ecf20Sopenharmony_ci	 * indicated by read_sz so caller won't even notice it.
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ci	((char *)buf)[read_sz] = '\0';
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (!p_buf)
1788c2ecf20Sopenharmony_ci		free(buf);
1798c2ecf20Sopenharmony_ci	else
1808c2ecf20Sopenharmony_ci		*p_buf = buf;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (p_read_sz)
1838c2ecf20Sopenharmony_ci		*p_read_sz = read_sz;
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cierrout:
1878c2ecf20Sopenharmony_ci	if (file)
1888c2ecf20Sopenharmony_ci		pclose(file);
1898c2ecf20Sopenharmony_ci	free(buf);
1908c2ecf20Sopenharmony_ci	if (p_buf)
1918c2ecf20Sopenharmony_ci		*p_buf = NULL;
1928c2ecf20Sopenharmony_ci	if (p_read_sz)
1938c2ecf20Sopenharmony_ci		*p_read_sz = 0;
1948c2ecf20Sopenharmony_ci	return err;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline void
1988c2ecf20Sopenharmony_ciforce_set_env(const char *var, const char *value)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	if (value) {
2018c2ecf20Sopenharmony_ci		setenv(var, value, 1);
2028c2ecf20Sopenharmony_ci		pr_debug("set env: %s=%s\n", var, value);
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		unsetenv(var);
2058c2ecf20Sopenharmony_ci		pr_debug("unset env: %s\n", var);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void
2108c2ecf20Sopenharmony_civersion_notice(void)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	pr_err(
2138c2ecf20Sopenharmony_ci"     \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
2148c2ecf20Sopenharmony_ci"     \tYou may want to try git trunk:\n"
2158c2ecf20Sopenharmony_ci"     \t\tgit clone http://llvm.org/git/llvm.git\n"
2168c2ecf20Sopenharmony_ci"     \t\t     and\n"
2178c2ecf20Sopenharmony_ci"     \t\tgit clone http://llvm.org/git/clang.git\n\n"
2188c2ecf20Sopenharmony_ci"     \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n"
2198c2ecf20Sopenharmony_ci"     \tdebian/ubuntu:\n"
2208c2ecf20Sopenharmony_ci"     \t\thttp://llvm.org/apt\n\n"
2218c2ecf20Sopenharmony_ci"     \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n"
2228c2ecf20Sopenharmony_ci"     \toption in [llvm] section of ~/.perfconfig to:\n\n"
2238c2ecf20Sopenharmony_ci"     \t  \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS \\\n"
2248c2ecf20Sopenharmony_ci"     \t     -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n"
2258c2ecf20Sopenharmony_ci"     \t     -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n"
2268c2ecf20Sopenharmony_ci"     \t(Replace /path/to/llc with path to your llc)\n\n"
2278c2ecf20Sopenharmony_ci);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int detect_kbuild_dir(char **kbuild_dir)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	const char *test_dir = llvm_param.kbuild_dir;
2338c2ecf20Sopenharmony_ci	const char *prefix_dir = "";
2348c2ecf20Sopenharmony_ci	const char *suffix_dir = "";
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* _UTSNAME_LENGTH is 65 */
2378c2ecf20Sopenharmony_ci	char release[128];
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	char *autoconf_path;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	int err;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (!test_dir) {
2448c2ecf20Sopenharmony_ci		err = fetch_kernel_version(NULL, release,
2458c2ecf20Sopenharmony_ci					   sizeof(release));
2468c2ecf20Sopenharmony_ci		if (err)
2478c2ecf20Sopenharmony_ci			return -EINVAL;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		test_dir = release;
2508c2ecf20Sopenharmony_ci		prefix_dir = "/lib/modules/";
2518c2ecf20Sopenharmony_ci		suffix_dir = "/build";
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h",
2558c2ecf20Sopenharmony_ci		       prefix_dir, test_dir, suffix_dir);
2568c2ecf20Sopenharmony_ci	if (err < 0)
2578c2ecf20Sopenharmony_ci		return -ENOMEM;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (access(autoconf_path, R_OK) == 0) {
2608c2ecf20Sopenharmony_ci		free(autoconf_path);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir,
2638c2ecf20Sopenharmony_ci			       suffix_dir);
2648c2ecf20Sopenharmony_ci		if (err < 0)
2658c2ecf20Sopenharmony_ci			return -ENOMEM;
2668c2ecf20Sopenharmony_ci		return 0;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	pr_debug("%s: Couldn't find \"%s\", missing kernel-devel package?.\n",
2698c2ecf20Sopenharmony_ci		 __func__, autoconf_path);
2708c2ecf20Sopenharmony_ci	free(autoconf_path);
2718c2ecf20Sopenharmony_ci	return -ENOENT;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic const char *kinc_fetch_script =
2758c2ecf20Sopenharmony_ci"#!/usr/bin/env sh\n"
2768c2ecf20Sopenharmony_ci"if ! test -d \"$KBUILD_DIR\"\n"
2778c2ecf20Sopenharmony_ci"then\n"
2788c2ecf20Sopenharmony_ci"	exit 1\n"
2798c2ecf20Sopenharmony_ci"fi\n"
2808c2ecf20Sopenharmony_ci"if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n"
2818c2ecf20Sopenharmony_ci"then\n"
2828c2ecf20Sopenharmony_ci"	exit 1\n"
2838c2ecf20Sopenharmony_ci"fi\n"
2848c2ecf20Sopenharmony_ci"TMPDIR=`mktemp -d`\n"
2858c2ecf20Sopenharmony_ci"if test -z \"$TMPDIR\"\n"
2868c2ecf20Sopenharmony_ci"then\n"
2878c2ecf20Sopenharmony_ci"    exit 1\n"
2888c2ecf20Sopenharmony_ci"fi\n"
2898c2ecf20Sopenharmony_ci"cat << EOF > $TMPDIR/Makefile\n"
2908c2ecf20Sopenharmony_ci"obj-y := dummy.o\n"
2918c2ecf20Sopenharmony_ci"\\$(obj)/%.o: \\$(src)/%.c\n"
2928c2ecf20Sopenharmony_ci"\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n"
2938c2ecf20Sopenharmony_ci"\t\\$(CC) -c -o \\$@ \\$<\n"
2948c2ecf20Sopenharmony_ci"EOF\n"
2958c2ecf20Sopenharmony_ci"touch $TMPDIR/dummy.c\n"
2968c2ecf20Sopenharmony_ci"make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n"
2978c2ecf20Sopenharmony_ci"RET=$?\n"
2988c2ecf20Sopenharmony_ci"rm -rf $TMPDIR\n"
2998c2ecf20Sopenharmony_ci"exit $RET\n";
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_civoid llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	static char *saved_kbuild_dir;
3048c2ecf20Sopenharmony_ci	static char *saved_kbuild_include_opts;
3058c2ecf20Sopenharmony_ci	int err;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!kbuild_dir || !kbuild_include_opts)
3088c2ecf20Sopenharmony_ci		return;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	*kbuild_dir = NULL;
3118c2ecf20Sopenharmony_ci	*kbuild_include_opts = NULL;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (saved_kbuild_dir && saved_kbuild_include_opts &&
3148c2ecf20Sopenharmony_ci	    !IS_ERR(saved_kbuild_dir) && !IS_ERR(saved_kbuild_include_opts)) {
3158c2ecf20Sopenharmony_ci		*kbuild_dir = strdup(saved_kbuild_dir);
3168c2ecf20Sopenharmony_ci		*kbuild_include_opts = strdup(saved_kbuild_include_opts);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		if (*kbuild_dir && *kbuild_include_opts)
3198c2ecf20Sopenharmony_ci			return;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		zfree(kbuild_dir);
3228c2ecf20Sopenharmony_ci		zfree(kbuild_include_opts);
3238c2ecf20Sopenharmony_ci		/*
3248c2ecf20Sopenharmony_ci		 * Don't fall through: it may breaks saved_kbuild_dir and
3258c2ecf20Sopenharmony_ci		 * saved_kbuild_include_opts if detect them again when
3268c2ecf20Sopenharmony_ci		 * memory is low.
3278c2ecf20Sopenharmony_ci		 */
3288c2ecf20Sopenharmony_ci		return;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
3328c2ecf20Sopenharmony_ci		pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
3338c2ecf20Sopenharmony_ci		pr_debug("Skip kbuild options detection.\n");
3348c2ecf20Sopenharmony_ci		goto errout;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	err = detect_kbuild_dir(kbuild_dir);
3388c2ecf20Sopenharmony_ci	if (err) {
3398c2ecf20Sopenharmony_ci		pr_warning(
3408c2ecf20Sopenharmony_ci"WARNING:\tunable to get correct kernel building directory.\n"
3418c2ecf20Sopenharmony_ci"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
3428c2ecf20Sopenharmony_ci"     \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
3438c2ecf20Sopenharmony_ci"     \tdetection.\n\n");
3448c2ecf20Sopenharmony_ci		goto errout;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
3488c2ecf20Sopenharmony_ci	force_set_env("KBUILD_DIR", *kbuild_dir);
3498c2ecf20Sopenharmony_ci	force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts);
3508c2ecf20Sopenharmony_ci	err = read_from_pipe(kinc_fetch_script,
3518c2ecf20Sopenharmony_ci			     (void **)kbuild_include_opts,
3528c2ecf20Sopenharmony_ci			     NULL);
3538c2ecf20Sopenharmony_ci	if (err) {
3548c2ecf20Sopenharmony_ci		pr_warning(
3558c2ecf20Sopenharmony_ci"WARNING:\tunable to get kernel include directories from '%s'\n"
3568c2ecf20Sopenharmony_ci"Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n"
3578c2ecf20Sopenharmony_ci"     \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n"
3588c2ecf20Sopenharmony_ci"     \toption in [llvm] to \"\" to suppress this detection.\n\n",
3598c2ecf20Sopenharmony_ci			*kbuild_dir);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		zfree(kbuild_dir);
3628c2ecf20Sopenharmony_ci		goto errout;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	pr_debug("include option is set to %s\n", *kbuild_include_opts);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	saved_kbuild_dir = strdup(*kbuild_dir);
3688c2ecf20Sopenharmony_ci	saved_kbuild_include_opts = strdup(*kbuild_include_opts);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (!saved_kbuild_dir || !saved_kbuild_include_opts) {
3718c2ecf20Sopenharmony_ci		zfree(&saved_kbuild_dir);
3728c2ecf20Sopenharmony_ci		zfree(&saved_kbuild_include_opts);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	return;
3758c2ecf20Sopenharmony_cierrout:
3768c2ecf20Sopenharmony_ci	saved_kbuild_dir = ERR_PTR(-EINVAL);
3778c2ecf20Sopenharmony_ci	saved_kbuild_include_opts = ERR_PTR(-EINVAL);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciint llvm__get_nr_cpus(void)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	static int nr_cpus_avail = 0;
3838c2ecf20Sopenharmony_ci	char serr[STRERR_BUFSIZE];
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (nr_cpus_avail > 0)
3868c2ecf20Sopenharmony_ci		return nr_cpus_avail;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
3898c2ecf20Sopenharmony_ci	if (nr_cpus_avail <= 0) {
3908c2ecf20Sopenharmony_ci		pr_err(
3918c2ecf20Sopenharmony_ci"WARNING:\tunable to get available CPUs in this system: %s\n"
3928c2ecf20Sopenharmony_ci"        \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
3938c2ecf20Sopenharmony_ci		nr_cpus_avail = 128;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci	return nr_cpus_avail;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_civoid llvm__dump_obj(const char *path, void *obj_buf, size_t size)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	char *obj_path = strdup(path);
4018c2ecf20Sopenharmony_ci	FILE *fp;
4028c2ecf20Sopenharmony_ci	char *p;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if (!obj_path) {
4058c2ecf20Sopenharmony_ci		pr_warning("WARNING: Not enough memory, skip object dumping\n");
4068c2ecf20Sopenharmony_ci		return;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	p = strrchr(obj_path, '.');
4108c2ecf20Sopenharmony_ci	if (!p || (strcmp(p, ".c") != 0)) {
4118c2ecf20Sopenharmony_ci		pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n",
4128c2ecf20Sopenharmony_ci			   obj_path);
4138c2ecf20Sopenharmony_ci		goto out;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	p[1] = 'o';
4178c2ecf20Sopenharmony_ci	fp = fopen(obj_path, "wb");
4188c2ecf20Sopenharmony_ci	if (!fp) {
4198c2ecf20Sopenharmony_ci		pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n",
4208c2ecf20Sopenharmony_ci			   obj_path, strerror(errno));
4218c2ecf20Sopenharmony_ci		goto out;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	pr_debug("LLVM: dumping %s\n", obj_path);
4258c2ecf20Sopenharmony_ci	if (fwrite(obj_buf, size, 1, fp) != 1)
4268c2ecf20Sopenharmony_ci		pr_debug("WARNING: failed to write to file '%s': %s, skip object dumping\n", obj_path, strerror(errno));
4278c2ecf20Sopenharmony_ci	fclose(fp);
4288c2ecf20Sopenharmony_ciout:
4298c2ecf20Sopenharmony_ci	free(obj_path);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciint llvm__compile_bpf(const char *path, void **p_obj_buf,
4338c2ecf20Sopenharmony_ci		      size_t *p_obj_buf_sz)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	size_t obj_buf_sz;
4368c2ecf20Sopenharmony_ci	void *obj_buf = NULL;
4378c2ecf20Sopenharmony_ci	int err, nr_cpus_avail;
4388c2ecf20Sopenharmony_ci	unsigned int kernel_version;
4398c2ecf20Sopenharmony_ci	char linux_version_code_str[64];
4408c2ecf20Sopenharmony_ci	const char *clang_opt = llvm_param.clang_opt;
4418c2ecf20Sopenharmony_ci	char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
4428c2ecf20Sopenharmony_ci	char serr[STRERR_BUFSIZE];
4438c2ecf20Sopenharmony_ci	char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
4448c2ecf20Sopenharmony_ci	     *perf_bpf_include_opts = NULL;
4458c2ecf20Sopenharmony_ci	const char *template = llvm_param.clang_bpf_cmd_template;
4468c2ecf20Sopenharmony_ci	char *pipe_template = NULL;
4478c2ecf20Sopenharmony_ci	const char *opts = llvm_param.opts;
4488c2ecf20Sopenharmony_ci	char *command_echo = NULL, *command_out;
4498c2ecf20Sopenharmony_ci	char *perf_include_dir = system_path(PERF_INCLUDE_DIR);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (path[0] != '-' && realpath(path, abspath) == NULL) {
4528c2ecf20Sopenharmony_ci		err = errno;
4538c2ecf20Sopenharmony_ci		pr_err("ERROR: problems with path %s: %s\n",
4548c2ecf20Sopenharmony_ci		       path, str_error_r(err, serr, sizeof(serr)));
4558c2ecf20Sopenharmony_ci		return -err;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (!template)
4598c2ecf20Sopenharmony_ci		template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	err = search_program(llvm_param.clang_path,
4628c2ecf20Sopenharmony_ci			     "clang", clang_path);
4638c2ecf20Sopenharmony_ci	if (err) {
4648c2ecf20Sopenharmony_ci		pr_err(
4658c2ecf20Sopenharmony_ci"ERROR:\tunable to find clang.\n"
4668c2ecf20Sopenharmony_ci"Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
4678c2ecf20Sopenharmony_ci"     \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
4688c2ecf20Sopenharmony_ci		version_notice();
4698c2ecf20Sopenharmony_ci		return -ENOENT;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/*
4738c2ecf20Sopenharmony_ci	 * This is an optional work. Even it fail we can continue our
4748c2ecf20Sopenharmony_ci	 * work. Needn't to check error return.
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci	llvm__get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	nr_cpus_avail = llvm__get_nr_cpus();
4798c2ecf20Sopenharmony_ci	snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
4808c2ecf20Sopenharmony_ci		 nr_cpus_avail);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if (fetch_kernel_version(&kernel_version, NULL, 0))
4838c2ecf20Sopenharmony_ci		kernel_version = 0;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	snprintf(linux_version_code_str, sizeof(linux_version_code_str),
4868c2ecf20Sopenharmony_ci		 "0x%x", kernel_version);
4878c2ecf20Sopenharmony_ci	if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
4888c2ecf20Sopenharmony_ci		goto errout;
4898c2ecf20Sopenharmony_ci	force_set_env("NR_CPUS", nr_cpus_avail_str);
4908c2ecf20Sopenharmony_ci	force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
4918c2ecf20Sopenharmony_ci	force_set_env("CLANG_EXEC", clang_path);
4928c2ecf20Sopenharmony_ci	force_set_env("CLANG_OPTIONS", clang_opt);
4938c2ecf20Sopenharmony_ci	force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
4948c2ecf20Sopenharmony_ci	force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
4958c2ecf20Sopenharmony_ci	force_set_env("WORKING_DIR", kbuild_dir ? : ".");
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (opts) {
4988c2ecf20Sopenharmony_ci		err = search_program(llvm_param.llc_path, "llc", llc_path);
4998c2ecf20Sopenharmony_ci		if (err) {
5008c2ecf20Sopenharmony_ci			pr_err("ERROR:\tunable to find llc.\n"
5018c2ecf20Sopenharmony_ci			       "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
5028c2ecf20Sopenharmony_ci			       "     \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n");
5038c2ecf20Sopenharmony_ci			version_notice();
5048c2ecf20Sopenharmony_ci			goto errout;
5058c2ecf20Sopenharmony_ci		}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		err = -ENOMEM;
5088c2ecf20Sopenharmony_ci		if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
5098c2ecf20Sopenharmony_ci			      template, llc_path, opts) < 0) {
5108c2ecf20Sopenharmony_ci			pr_err("ERROR:\tnot enough memory to setup command line\n");
5118c2ecf20Sopenharmony_ci			goto errout;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		template = pipe_template;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/*
5198c2ecf20Sopenharmony_ci	 * Since we may reset clang's working dir, path of source file
5208c2ecf20Sopenharmony_ci	 * should be transferred into absolute path, except we want
5218c2ecf20Sopenharmony_ci	 * stdin to be source file (testing).
5228c2ecf20Sopenharmony_ci	 */
5238c2ecf20Sopenharmony_ci	force_set_env("CLANG_SOURCE",
5248c2ecf20Sopenharmony_ci		      (path[0] == '-') ? path : abspath);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	pr_debug("llvm compiling command template: %s\n", template);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	/*
5298c2ecf20Sopenharmony_ci	 * Below, substitute control characters for values that can cause the
5308c2ecf20Sopenharmony_ci	 * echo to misbehave, then substitute the values back.
5318c2ecf20Sopenharmony_ci	 */
5328c2ecf20Sopenharmony_ci	err = -ENOMEM;
5338c2ecf20Sopenharmony_ci	if (asprintf(&command_echo, "echo -n \a%s\a", template) < 0)
5348c2ecf20Sopenharmony_ci		goto errout;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci#define SWAP_CHAR(a, b) do { if (*p == a) *p = b; } while (0)
5378c2ecf20Sopenharmony_ci	for (char *p = command_echo; *p; p++) {
5388c2ecf20Sopenharmony_ci		SWAP_CHAR('<', '\001');
5398c2ecf20Sopenharmony_ci		SWAP_CHAR('>', '\002');
5408c2ecf20Sopenharmony_ci		SWAP_CHAR('"', '\003');
5418c2ecf20Sopenharmony_ci		SWAP_CHAR('\'', '\004');
5428c2ecf20Sopenharmony_ci		SWAP_CHAR('|', '\005');
5438c2ecf20Sopenharmony_ci		SWAP_CHAR('&', '\006');
5448c2ecf20Sopenharmony_ci		SWAP_CHAR('\a', '"');
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci	err = read_from_pipe(command_echo, (void **) &command_out, NULL);
5478c2ecf20Sopenharmony_ci	if (err)
5488c2ecf20Sopenharmony_ci		goto errout;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	for (char *p = command_out; *p; p++) {
5518c2ecf20Sopenharmony_ci		SWAP_CHAR('\001', '<');
5528c2ecf20Sopenharmony_ci		SWAP_CHAR('\002', '>');
5538c2ecf20Sopenharmony_ci		SWAP_CHAR('\003', '"');
5548c2ecf20Sopenharmony_ci		SWAP_CHAR('\004', '\'');
5558c2ecf20Sopenharmony_ci		SWAP_CHAR('\005', '|');
5568c2ecf20Sopenharmony_ci		SWAP_CHAR('\006', '&');
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci#undef SWAP_CHAR
5598c2ecf20Sopenharmony_ci	pr_debug("llvm compiling command : %s\n", command_out);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
5628c2ecf20Sopenharmony_ci	if (err) {
5638c2ecf20Sopenharmony_ci		pr_err("ERROR:\tunable to compile %s\n", path);
5648c2ecf20Sopenharmony_ci		pr_err("Hint:\tCheck error message shown above.\n");
5658c2ecf20Sopenharmony_ci		pr_err("Hint:\tYou can also pre-compile it into .o using:\n");
5668c2ecf20Sopenharmony_ci		pr_err("     \t\tclang -target bpf -O2 -c %s\n", path);
5678c2ecf20Sopenharmony_ci		pr_err("     \twith proper -I and -D options.\n");
5688c2ecf20Sopenharmony_ci		goto errout;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	free(command_echo);
5728c2ecf20Sopenharmony_ci	free(command_out);
5738c2ecf20Sopenharmony_ci	free(kbuild_dir);
5748c2ecf20Sopenharmony_ci	free(kbuild_include_opts);
5758c2ecf20Sopenharmony_ci	free(perf_bpf_include_opts);
5768c2ecf20Sopenharmony_ci	free(perf_include_dir);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (!p_obj_buf)
5798c2ecf20Sopenharmony_ci		free(obj_buf);
5808c2ecf20Sopenharmony_ci	else
5818c2ecf20Sopenharmony_ci		*p_obj_buf = obj_buf;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (p_obj_buf_sz)
5848c2ecf20Sopenharmony_ci		*p_obj_buf_sz = obj_buf_sz;
5858c2ecf20Sopenharmony_ci	return 0;
5868c2ecf20Sopenharmony_cierrout:
5878c2ecf20Sopenharmony_ci	free(command_echo);
5888c2ecf20Sopenharmony_ci	free(kbuild_dir);
5898c2ecf20Sopenharmony_ci	free(kbuild_include_opts);
5908c2ecf20Sopenharmony_ci	free(obj_buf);
5918c2ecf20Sopenharmony_ci	free(perf_bpf_include_opts);
5928c2ecf20Sopenharmony_ci	free(perf_include_dir);
5938c2ecf20Sopenharmony_ci	free(pipe_template);
5948c2ecf20Sopenharmony_ci	if (p_obj_buf)
5958c2ecf20Sopenharmony_ci		*p_obj_buf = NULL;
5968c2ecf20Sopenharmony_ci	if (p_obj_buf_sz)
5978c2ecf20Sopenharmony_ci		*p_obj_buf_sz = 0;
5988c2ecf20Sopenharmony_ci	return err;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ciint llvm__search_clang(void)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	char clang_path[PATH_MAX];
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return search_program(llvm_param.clang_path, "clang", clang_path);
6068c2ecf20Sopenharmony_ci}
607