diff --git a/tests/unittest.c b/tests/unittest.c index ec1d4d763..cedaf21d5 100644 --- a/tests/unittest.c +++ b/tests/unittest.c @@ -160,6 +160,44 @@ static int sort_tests(const void *tc1, const void *tc2) return strcmp(test1->name, test2->name); } +/* + * RISC-V GCC doesn't set uftrace_unit_test data in the uftrace.test section + * (#1833). So it should read the unittest binary to find the symbol table + * and fill the data manually. + * + * Note that the unit test functions are global functions start with "func_" + * prefix. Other (global) functions should not start with that. + */ +static void update_test_cases(struct uftrace_unit_test *tcases, int num, + struct uftrace_elf_data *elf) +{ + struct uftrace_elf_iter iter; + int i = 0; + + elf_for_each_shdr(elf, &iter) { + if (iter.shdr.sh_type != SHT_SYMTAB) + continue; + elf_for_each_symbol(elf, &iter) { + typeof(iter.sym) *sym = &iter.sym; + const char *name = elf_get_name(elf, &iter, sym->st_name); + if (elf_symbol_type(sym) != STT_FUNC || + elf_symbol_bind(sym) != STB_GLOBAL) + continue; + if (strncmp(name, TEST_FUNC_PREFIX_STR, strlen(TEST_FUNC_PREFIX_STR))) + continue; + tcases[i].func = (void *)sym->st_value + load_base; + tcases[i].name = strdup(name + strlen(TEST_FUNC_PREFIX_STR)); + i++; + } + /* + * It applied the base address already, make sure not to do it + * twice. + */ + load_base = 0; + break; + } +} + static int setup_unit_test(struct uftrace_unit_test **test_cases, size_t *test_num, char *filter) { char *exename; @@ -202,6 +240,14 @@ static int setup_unit_test(struct uftrace_unit_test **test_cases, size_t *test_n elf_get_secdata(&elf, &iter); elf_read_secdata(&elf, &iter, 0, tcases, sec_size); + /* check if test cases are set properly */ + for (i = 0, actual = 0; i < num; i++) { + if (tcases[i].func && tcases[i].name) + actual++; + } + if (actual != num) + update_test_cases(tcases, num, &elf); + /* relocate section symbols in case of PIE */ for (i = 0, actual = 0; i < num && (load_base || filter); i++) { struct uftrace_unit_test *tc = &tcases[i]; diff --git a/tests/unittest.h b/tests/unittest.h index d7932a1c3..0b9f2c524 100644 --- a/tests/unittest.h +++ b/tests/unittest.h @@ -110,27 +110,32 @@ struct uftrace_unit_test { int (*func)(void); }; +#define TEST_FUNC_PREFIX func_ +#define TEST_FUNC_PREFIX_STR stringify(TEST_FUNC_PREFIX) +#define TEST_FUNC_NAME(t) TEST_FUNC_PREFIX##t + #ifdef __clang__ #define TEST_CASE(t) \ - extern int func_##t(void); \ + extern int TEST_FUNC_NAME(t)(void); \ \ __attribute__((section(TEST_SECTION), used, no_sanitize("address"))) \ - const struct uftrace_unit_test test_##t = { \ + const struct uftrace_unit_test test_##t = { \ .name = stringify(t), \ - .func = func_##t, \ + .func = TEST_FUNC_NAME(t), }; \ \ - int func_##t(void) + int TEST_FUNC_NAME(t)(void) #else /* #ifdef __clang__ */ #define TEST_CASE(t) \ - extern int func_##t(void); \ + extern int TEST_FUNC_NAME(t)(void); \ \ - __attribute__((section(TEST_SECTION), used)) const struct uftrace_unit_test test_##t = { \ + __attribute__((section(TEST_SECTION), used)) \ + const struct uftrace_unit_test test_##t = { \ .name = stringify(t), \ - .func = func_##t, \ + .func = TEST_FUNC_NAME(t), \ }; \ \ - int func_##t(void) + int TEST_FUNC_NAME(t)(void) #endif /* #ifdef __clang__ */ #define TERM_COLOR_NORMAL ""