Introduce a new test for native calls to ensure their functionality. The process involves cross-compiling the test cases, building them as dynamically linked binaries, and running these binaries which necessitates the addition of the appropriate interpreter prefix.
Signed-off-by: Yeqi Fu <fufuyqqq...@gmail.com> --- tests/tcg/multiarch/Makefile.target | 32 ++++++ tests/tcg/multiarch/native/nativecall.c | 132 ++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tests/tcg/multiarch/native/nativecall.c diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 43bddeaf21..8bad8ac0d5 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -12,7 +12,9 @@ VPATH += $(MULTIARCH_SRC) MULTIARCH_SRCS = $(notdir $(wildcard $(MULTIARCH_SRC)/*.c)) ifeq ($(filter %-linux-user, $(TARGET)),$(TARGET)) VPATH += $(MULTIARCH_SRC)/linux +VPATH += $(MULTIARCH_SRC)/native MULTIARCH_SRCS += $(notdir $(wildcard $(MULTIARCH_SRC)/linux/*.c)) +MULTIARCH_SRCS += $(notdir $(wildcard $(MULTIARCH_SRC)/native/*.c)) endif MULTIARCH_TESTS = $(MULTIARCH_SRCS:.c=) @@ -138,5 +140,35 @@ run-plugin-semiconsole-with-%: TESTS += semihosting semiconsole endif +nativecall: LDFLAGS+=-ldl +nativecall: CFLAGS+=-D_GNU_SOURCE -fPIE +nativecall: nativecall.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(filter-out -static,$(LDFLAGS)) + +ifneq ($(LD_PREFIX),) +ifneq ($(LIBNATIVE),) +run-nativecall: nativecall + $(call run-test, $<, $(QEMU) -L $(LD_PREFIX) \ + --native-bypass $(LIBNATIVE) $<, "nativecall") + +run-plugin-nativecall-with-%: + $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ + -L $(LD_PREFIX) --native-bypass $(LIBNATIVE) \ + -plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \ + $(call strip-plugin,$<) 2> $<.err, \ + $< with $*) +else +run-nativecall: nativecall + $(call skip-test, $<, "no native library found") +run-plugin-nativecall-with-%: + $(call skip-test, $<, "no native library found") +endif +else +run-nativecall: nativecall + $(call skip-test, $<, "no elf interpreter prefix found") +run-plugin-nativecall-with-%: + $(call skip-test, $<, "no elf interpreter prefix found") +endif + # Update TESTS TESTS += $(MULTIARCH_TESTS) diff --git a/tests/tcg/multiarch/native/nativecall.c b/tests/tcg/multiarch/native/nativecall.c new file mode 100644 index 0000000000..de18718c61 --- /dev/null +++ b/tests/tcg/multiarch/native/nativecall.c @@ -0,0 +1,132 @@ +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +void compare_memory(const void *a, const void *b, size_t n) +{ + const unsigned char *p1 = a; + const unsigned char *p2 = b; + for (size_t i = 0; i < n; i++) { + assert(p1[i] == p2[i]); + } +} + +void test_memcpy(char *src) +{ + char dest[2000]; + memcpy(dest, src, 2000); + compare_memory(dest, src, 2000); +} + +void test_strncpy(char *src) +{ + char dest[2000]; + strncpy(dest, src, 2000); + compare_memory(dest, src, 2000); +} + +void test_strcpy(char *src) +{ + char dest[2000]; + strcpy(dest, src); + compare_memory(dest, src, 2000); +} + +void test_strcat() +{ + char src[30] = "Hello, "; + char dest[] = "world!"; + char str[] = "Hello, world!"; + strcat(src, dest); + compare_memory(src, str, 13); +} + +void test_memcmp(char *str1, char *str2, char *str3) +{ + int result1 = memcmp(str1, str2, 3); + int result2 = memcmp(str1, str3, 3); + int result3 = memcmp(str3, str1, 3); + assert(result1 == 0); + assert(result2 < 0); + assert(result3 > 0); +} + +void test_strncmp(char *str1, char *str2, char *str3) +{ + int result1 = strncmp(str1, str2, 3); + int result2 = strncmp(str1, str3, 3); + int result3 = strncmp(str3, str1, 3); + assert(result1 == 0); + assert(result2 < 0); + assert(result3 > 0); +} + +void test_strcmp(char *str1, char *str2, char *str3) +{ + int result1 = strcmp(str1, str2); + int result2 = strcmp(str1, str3); + int result3 = strcmp(str3, str1); + assert(result1 == 0); + assert(result2 < 0); + assert(result3 > 0); +} + +void test_memset(char *buffer) +{ + memset(buffer, 'A', 2000 - 1); + for (int i = 0; i < 2000 - 1; i++) { + assert(buffer[i] == 'A'); + } +} + +void test_libnative() +{ + Dl_info info; + void *memcpy_addr = (void *)memcpy; + if (dladdr(memcpy_addr, &info) != 0) { + assert(strstr(info.dli_fname, "libnative.so") != NULL); + } +} + +/* + * When executing execv, an error may occur stating that the shared library + * cannot be preloaded. + */ +void test_execv(const char *cmd) +{ + char *argv[4]; + argv[0] = (char *)"/bin/sh"; + argv[1] = (char *)"-c"; + argv[2] = (char *)cmd; + argv[3] = NULL; + execv("/bin/sh", argv); +} + +int main() +{ + char buf[2000]; + for (int i = 0; i < 2000 - 1; i++) { + buf[i] = 'A' + (i % 26); + } + buf[2000 - 1] = '\0'; + char str1[4] = "abc\0"; + char str2[4] = "abc\0"; + char str3[4] = "def\0"; + + test_memcpy(buf); + test_strncpy(buf); + test_strcpy(buf); + test_memcmp(str1, str2, str3); + test_strncmp(str1, str2, str3); + test_strcmp(str1, str2, str3); + test_strcat(); + test_memset(buf); + test_libnative(); + test_execv("echo 111"); + + return EXIT_SUCCESS; +} -- 2.34.1