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