blob: b7f83ba42f5dcc92659a991e1e2831d693c42435 [file] [edit]
//===-- Hermetic integration test for ucontext routines -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// This is a hermetic integration test for getcontext and setcontext.
// We use a hermetic test here because the heavier unit test infrastructure
// (like GTest) interferes with context switching, stack frame management,
// and floating-point state restoration, causing spurious failures.
#include "test/IntegrationTest/test.h"
#include "include/llvm-libc-types/ucontext_t.h"
#include "src/ucontext/getcontext.h"
#include "src/ucontext/setcontext.h"
void basic_stub_test() {
ucontext_t ctx;
static volatile int jumped = 0;
int ret = LIBC_NAMESPACE::getcontext(&ctx);
ASSERT_EQ(ret, 0);
if (!jumped) {
jumped = 1;
LIBC_NAMESPACE::setcontext(&ctx);
ASSERT_TRUE(false); // Should not happen
}
ASSERT_TRUE(true);
}
void register_preservation_test() {
ucontext_t ctx;
static volatile int jumped = 0;
long checked_r12, checked_r13, checked_r14, checked_r15;
{
register long r12_val asm("r12") = 0x1212121212121212;
register long r13_val asm("r13") = 0x1313131313131313;
register long r14_val asm("r14") = 0x1414141414141414;
register long r15_val asm("r15") = 0x1515151515151515;
register void *rdi_val asm("rdi") = &ctx;
asm volatile("call *%[getcontext_ptr]"
: "+r"(rdi_val), "+r"(r12_val), "+r"(r13_val), "+r"(r14_val),
"+r"(r15_val)
: [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
: "memory", "rax", "rcx", "rdx", "rsi");
checked_r12 = r12_val;
checked_r13 = r13_val;
checked_r14 = r14_val;
checked_r15 = r15_val;
}
if (!jumped) {
jumped = 1;
// Modify registers to ensure they are restored from context
asm volatile("movq $0, %%r12\n\t"
"movq $0, %%r13\n\t"
"movq $0, %%r14\n\t"
"movq $0, %%r15\n\t" ::
: "r12", "r13", "r14", "r15");
register const ucontext_t *rdi_set asm("rdi") = &ctx;
asm volatile("call *%[setcontext_ptr]" ::"r"(rdi_set),
[setcontext_ptr] "r"((void *)LIBC_NAMESPACE::setcontext)
: "memory");
ASSERT_TRUE(false); // Should not reach here
}
ASSERT_EQ(checked_r12, (long)0x1212121212121212);
ASSERT_EQ(checked_r13, (long)0x1313131313131313);
ASSERT_EQ(checked_r14, (long)0x1414141414141414);
ASSERT_EQ(checked_r15, (long)0x1515151515151515);
}
void test_rbx_rdx() {
ucontext_t ctx;
static volatile int jumped = 0;
long checked_rbx, checked_rdx;
{
register long rbx_val asm("rbx") = 0xBBBBBBBBBBBBBBBB;
register long rdx_val asm("rdx") = 0xDDDDDDDDDDDDDDDD;
register void *rdi_val asm("rdi") = &ctx;
asm volatile("call *%[getcontext_ptr]"
: "+r"(rdi_val), "+r"(rbx_val), "+r"(rdx_val)
: [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
: "memory", "rax", "rcx", "rsi");
checked_rbx = rbx_val;
checked_rdx = rdx_val;
}
if (!jumped) {
jumped = 1;
asm volatile("movq $0, %%rbx\n\t"
"movq $0, %%rdx\n\t" ::
: "rbx", "rdx");
register const ucontext_t *rdi_set asm("rdi") = &ctx;
asm volatile("call *%[setcontext_ptr]" ::"r"(rdi_set),
[setcontext_ptr] "r"((void *)LIBC_NAMESPACE::setcontext)
: "memory");
ASSERT_TRUE(false);
}
ASSERT_EQ(checked_rbx, (long)0xBBBBBBBBBBBBBBBB);
ASSERT_EQ(checked_rdx, (long)0xDDDDDDDDDDDDDDDD);
}
void test_r8_r11() {
ucontext_t ctx;
static volatile int jumped = 0;
long checked_r8, checked_r9, checked_r10, checked_r11;
{
register long r8_val asm("r8") = 0x0808080808080808;
register long r9_val asm("r9") = 0x0909090909090909;
register long r10_val asm("r10") = 0x1010101010101010;
register long r11_val asm("r11") = 0x1111111111111111;
register void *rdi_val asm("rdi") = &ctx;
asm volatile("call *%[getcontext_ptr]"
: "+r"(rdi_val), "+r"(r8_val), "+r"(r9_val), "+r"(r10_val),
"+r"(r11_val)
: [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
: "memory", "rax", "rcx", "rdx", "rsi");
checked_r8 = r8_val;
checked_r9 = r9_val;
checked_r10 = r10_val;
checked_r11 = r11_val;
}
if (!jumped) {
jumped = 1;
asm volatile("movq $0, %%r8\n\t"
"movq $0, %%r9\n\t"
"movq $0, %%r10\n\t"
"movq $0, %%r11\n\t" ::
: "r8", "r9", "r10", "r11");
register const ucontext_t *rdi_set asm("rdi") = &ctx;
asm volatile("call *%[setcontext_ptr]" ::"r"(rdi_set),
[setcontext_ptr] "r"((void *)LIBC_NAMESPACE::setcontext)
: "memory");
ASSERT_TRUE(false);
}
ASSERT_EQ(checked_r8, (long)0x0808080808080808);
ASSERT_EQ(checked_r9, (long)0x0909090909090909);
ASSERT_EQ(checked_r10, (long)0x1010101010101010);
ASSERT_EQ(checked_r11, (long)0x1111111111111111);
}
TEST_MAIN() {
basic_stub_test();
register_preservation_test();
test_rbx_rdx();
test_r8_r11();
return 0;
}