1// SPDX-License-Identifier: GPL-2.0 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5#include <bpf/libbpf.h> 6#include <util/llvm-utils.h> 7#include "llvm.h" 8#include "tests.h" 9#include "debug.h" 10 11#ifdef HAVE_LIBBPF_SUPPORT 12static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) 13{ 14 struct bpf_object *obj; 15 16 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); 17 if (libbpf_get_error(obj)) 18 return TEST_FAIL; 19 bpf_object__close(obj); 20 return TEST_OK; 21} 22#else 23static int test__bpf_parsing(void *obj_buf __maybe_unused, 24 size_t obj_buf_sz __maybe_unused) 25{ 26 pr_debug("Skip bpf parsing\n"); 27 return TEST_OK; 28} 29#endif 30 31static struct { 32 const char *source; 33 const char *desc; 34 bool should_load_fail; 35} bpf_source_table[__LLVM_TESTCASE_MAX] = { 36 [LLVM_TESTCASE_BASE] = { 37 .source = test_llvm__bpf_base_prog, 38 .desc = "Basic BPF llvm compile", 39 }, 40 [LLVM_TESTCASE_KBUILD] = { 41 .source = test_llvm__bpf_test_kbuild_prog, 42 .desc = "kbuild searching", 43 }, 44 [LLVM_TESTCASE_BPF_PROLOGUE] = { 45 .source = test_llvm__bpf_test_prologue_prog, 46 .desc = "Compile source for BPF prologue generation", 47 }, 48 [LLVM_TESTCASE_BPF_RELOCATION] = { 49 .source = test_llvm__bpf_test_relocation, 50 .desc = "Compile source for BPF relocation", 51 .should_load_fail = true, 52 }, 53}; 54 55int 56test_llvm__fetch_bpf_obj(void **p_obj_buf, 57 size_t *p_obj_buf_sz, 58 enum test_llvm__testcase idx, 59 bool force, 60 bool *should_load_fail) 61{ 62 const char *source; 63 const char *desc; 64 const char *tmpl_old, *clang_opt_old; 65 char *tmpl_new = NULL, *clang_opt_new = NULL; 66 int err, old_verbose, ret = TEST_FAIL; 67 68 if (idx >= __LLVM_TESTCASE_MAX) 69 return TEST_FAIL; 70 71 source = bpf_source_table[idx].source; 72 desc = bpf_source_table[idx].desc; 73 if (should_load_fail) 74 *should_load_fail = bpf_source_table[idx].should_load_fail; 75 76 /* 77 * Skip this test if user's .perfconfig doesn't set [llvm] section 78 * and clang is not found in $PATH, and this is not perf test -v 79 */ 80 if (!force && (verbose <= 0 && 81 !llvm_param.user_set_param && 82 llvm__search_clang())) { 83 pr_debug("No clang and no verbosive, skip this test\n"); 84 return TEST_SKIP; 85 } 86 87 /* 88 * llvm is verbosity when error. Suppress all error output if 89 * not 'perf test -v'. 90 */ 91 old_verbose = verbose; 92 if (verbose == 0) 93 verbose = -1; 94 95 *p_obj_buf = NULL; 96 *p_obj_buf_sz = 0; 97 98 if (!llvm_param.clang_bpf_cmd_template) 99 goto out; 100 101 if (!llvm_param.clang_opt) 102 llvm_param.clang_opt = strdup(""); 103 104 err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, 105 llvm_param.clang_bpf_cmd_template, 106 old_verbose ? "" : " 2>/dev/null"); 107 if (err < 0) 108 goto out; 109 err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); 110 if (err < 0) 111 goto out; 112 113 tmpl_old = llvm_param.clang_bpf_cmd_template; 114 llvm_param.clang_bpf_cmd_template = tmpl_new; 115 clang_opt_old = llvm_param.clang_opt; 116 llvm_param.clang_opt = clang_opt_new; 117 118 err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz); 119 120 llvm_param.clang_bpf_cmd_template = tmpl_old; 121 llvm_param.clang_opt = clang_opt_old; 122 123 verbose = old_verbose; 124 if (err) 125 goto out; 126 127 ret = TEST_OK; 128out: 129 free(tmpl_new); 130 free(clang_opt_new); 131 if (ret != TEST_OK) 132 pr_debug("Failed to compile test case: '%s'\n", desc); 133 return ret; 134} 135 136int test__llvm(struct test *test __maybe_unused, int subtest) 137{ 138 int ret; 139 void *obj_buf = NULL; 140 size_t obj_buf_sz = 0; 141 bool should_load_fail = false; 142 143 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) 144 return TEST_FAIL; 145 146 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 147 subtest, false, &should_load_fail); 148 149 if (ret == TEST_OK && !should_load_fail) { 150 ret = test__bpf_parsing(obj_buf, obj_buf_sz); 151 if (ret != TEST_OK) { 152 pr_debug("Failed to parse test case '%s'\n", 153 bpf_source_table[subtest].desc); 154 } 155 } 156 free(obj_buf); 157 158 return ret; 159} 160 161int test__llvm_subtest_get_nr(void) 162{ 163 return __LLVM_TESTCASE_MAX; 164} 165 166const char *test__llvm_subtest_get_desc(int subtest) 167{ 168 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) 169 return NULL; 170 171 return bpf_source_table[subtest].desc; 172} 173