Files
FEX-Emu--FEX/unittests/FEXLinuxTests/tests/signal/SystemInstructions.64.cpp
T
2026-09-15 20:06:48 -07:00

100 lines
4.8 KiB
C++

#include "invalid_util.h"
#include <catch2/catch_test_macros.hpp>
#include <atomic>
#include <signal.h>
#include <sys/mman.h>
#include <stdint.h>
#include <stdio.h>
#include <cstdlib>
#ifndef REG_RIP
#define REG_RIP REG_EIP
#endif
enum trapno {
X86_TRAPNO_UD = 6,
X86_TRAPNO_GP = 13,
};
#define CONCAT(x, y) x##y
#define TestSymbols(num) \
extern "C" uint64_t CONCAT(TestBegin_, num); \
extern "C" uint64_t CONCAT(TestEnd_, num);
#define Test(num, asm, trapno, errno, si_code, signal) \
capturing_handler_skip = (unsigned long)&CONCAT(TestEnd_, num) - (unsigned long)&CONCAT(TestBegin_, num); \
const unsigned long EXPECTED_RIP = (unsigned long)&CONCAT(TestBegin_, num); \
const int EXPECTED_TRAPNO = trapno; \
const int EXPECTED_ERR = errno; \
const int EXPECTED_SI_CODE = si_code; \
const int EXPECTED_SIGNAL = signal; \
__asm volatile("TestBegin_" #num ":" asm ";" \
"TestEnd_" #num ":" :: \
: "memory");
#define TEST(num, name, asm, trapno, errno, _si_code, _signal) \
TestSymbols(num); \
TEST_CASE("Signals: " #name) { \
struct sigaction act {}; \
act.sa_sigaction = CapturingHandler; \
act.sa_flags = SA_SIGINFO; \
sigaction(SIGSEGV, &act, nullptr); \
sigaction(SIGTRAP, &act, nullptr); \
sigaction(SIGILL, &act, nullptr); \
\
Test(num, asm, trapno, errno, _si_code, _signal); \
\
REQUIRE(from_handler.has_value()); \
CHECK(from_handler->mctx.gregs[REG_RIP] == EXPECTED_RIP); \
CHECK(from_handler->mctx.gregs[REG_TRAPNO] == EXPECTED_TRAPNO); \
CHECK(from_handler->mctx.gregs[REG_ERR] == EXPECTED_ERR); \
CHECK(from_handler->si_code == EXPECTED_SI_CODE); \
CHECK(from_handler->signal == EXPECTED_SIGNAL); \
}
// Instructions that explicitly are supported but must only work in CPL-0
TEST(0, "rdmsr", "rdmsr", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(1, "outs", "outs dx, byte ptr [rsi]", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(2, "ins", "ins byte ptr [rdi], dx", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(3, "cli", "cli", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(4, "clts", "clts", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(5, "invlpg", "invlpg [rax]", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(6, "lmsw", "lmsw [rax]", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(7, "ltr", "ltr [rax]", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(8, "mov cr0", "mov cr0, rax", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(9, "mov cr8", "mov cr8, rax", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(10, "mov rax, cr0", "mov rax, cr0", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(11, "mov rax, cr8", "mov rax, cr8", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(12, "mov rax, dr0", "mov rax, dr0", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(13, "mov dr0, rax", "mov dr0, rax", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(14, "rdpmc", "rdpmc", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(15, "sti", "sti", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(16, "swapgs", "swapgs", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
#ifdef __clang__
TEST(17, "sysret", "sysret", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
#else
TEST(17, "sysret", "sysretd", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
#endif
TEST(18, "wrmsr", "wrmsr", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(19, "invd", "invd", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
TEST(20, "wbinvd", "wbinvd", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
// Instructions not implemented
TEST(21, "monitor", "monitor", X86_TRAPNO_UD, 0, 2, SIGILL);
TEST(22, "mwait", "mwait", X86_TRAPNO_UD, 0, 2, SIGILL);
TEST(23, "sysenter", "sysenter", X86_TRAPNO_UD, 0, 2, SIGILL);
#ifdef __clang__
TEST(24, "sysexit", "sysexit", X86_TRAPNO_UD, 0, 2, SIGILL);
#else
TEST(24, "sysexit", "sysexitd", X86_TRAPNO_UD, 0, 2, SIGILL);
#endif
TEST(25, "in eax, dx", "in eax, dx", X86_TRAPNO_GP, 0, 0x80, SIGSEGV);
// Differs between dr8 and dr0-7 variants.
// dr0-7: SIGSEGV
// dr8-15: SIGILL
// TEST(20, "mov rax, dr8", "mov rax, dr8", X86_TRAPNO_UD, 0, 2, SIGILL);