mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 09:00:17 +02:00
unittests: Adds a test to check for partial decode
Known failure so added to the known failure list.
This commit is contained in:
4 files changed
+111
-38
No files matched your search
@@ -23,3 +23,6 @@ sigtest_sigmask.64
|
||||
# Disabled since FEX's FaultSafeMemcpy is intentionally stub-implemented
|
||||
syscalls_efault.32
|
||||
syscalls_efault.64
|
||||
|
||||
# partial instruction decode is known to fail
|
||||
noexec_protect.64
|
||||
@@ -31,6 +31,7 @@ foreach(TEST ${TESTS})
|
||||
|
||||
add_executable(${TEST_NAME}.${BITNESS} ${TEST})
|
||||
target_link_libraries(${TEST_NAME}.${BITNESS} PRIVATE Catch2::Catch2WithMain)
|
||||
target_include_directories(${TEST_NAME}.${BITNESS} PRIVATE include/)
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(pthread_cancel.${BITNESS} PRIVATE pthread)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
class SimpleX86Emit final {
|
||||
public:
|
||||
enum Reg {
|
||||
RAX = 0,
|
||||
RCX = 1,
|
||||
RDX = 2,
|
||||
RBX = 3,
|
||||
RSP = 4,
|
||||
RBP = 5,
|
||||
RSI = 6,
|
||||
RDI = 7,
|
||||
// r8 and higher not implemented.
|
||||
};
|
||||
SimpleX86Emit(void* Ptr, std::size_t size)
|
||||
: Ptr {static_cast<uint8_t*>(Ptr)}
|
||||
, EndPtr {static_cast<uint8_t*>(Ptr) + size} {}
|
||||
|
||||
void ret() {
|
||||
db<uint8_t>(0xc3);
|
||||
}
|
||||
|
||||
void mov(Reg reg, uint32_t val) {
|
||||
db<uint8_t>(0xB8 + reg);
|
||||
db(val);
|
||||
}
|
||||
|
||||
void dd(uint32_t val) {
|
||||
db(val);
|
||||
}
|
||||
|
||||
bool HadError() const {
|
||||
return _HadError;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* Ptr;
|
||||
uint8_t* EndPtr;
|
||||
bool _HadError {};
|
||||
|
||||
template<typename T>
|
||||
void db(T v) {
|
||||
static_assert(sizeof(uint32_t) == 4);
|
||||
std::size_t i {};
|
||||
for (i = 0; i < sizeof(T) && Ptr != EndPtr; ++i) {
|
||||
*Ptr = v >> (i * 8);
|
||||
++Ptr;
|
||||
}
|
||||
|
||||
_HadError = i != sizeof(T);
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "simple_x86.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <signal.h>
|
||||
@@ -7,6 +8,7 @@
|
||||
#include <csetjmp>
|
||||
|
||||
bool Caught = false;
|
||||
uint64_t CaughtAddr {};
|
||||
static jmp_buf LongJump {};
|
||||
|
||||
static void SIGSEGV_Handler(int signal, siginfo_t* siginfo, void* context) {
|
||||
@@ -16,47 +18,13 @@ static void SIGSEGV_Handler(int signal, siginfo_t* siginfo, void* context) {
|
||||
|
||||
// Page fault
|
||||
REQUIRE(_context->uc_mcontext.gregs[REG_TRAPNO] == 14);
|
||||
|
||||
CaughtAddr = reinterpret_cast<uint64_t>(siginfo->si_addr);
|
||||
|
||||
Caught = true;
|
||||
longjmp(LongJump, 1);
|
||||
}
|
||||
|
||||
class SimpleX86Emit final {
|
||||
public:
|
||||
enum Reg {
|
||||
RAX = 0,
|
||||
RCX = 1,
|
||||
RDX = 2,
|
||||
RBX = 3,
|
||||
RSP = 4,
|
||||
RBP = 5,
|
||||
RSI = 6,
|
||||
RDI = 7,
|
||||
// r8 and higher not implemented.
|
||||
};
|
||||
SimpleX86Emit(void* Ptr)
|
||||
: Ptr {static_cast<uint8_t*>(Ptr)} {}
|
||||
|
||||
void ret() {
|
||||
db<uint8_t>(0xc3);
|
||||
}
|
||||
|
||||
void mov(Reg reg, uint32_t val) {
|
||||
db<uint8_t>(0xB8 + reg);
|
||||
db(val);
|
||||
}
|
||||
private:
|
||||
uint8_t* Ptr;
|
||||
|
||||
template<typename T>
|
||||
void db(T v) {
|
||||
static_assert(sizeof(uint32_t) == 4);
|
||||
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||
*Ptr = v >> (i * 8);
|
||||
++Ptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Signals: Test No-Exec") {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = SIGSEGV_Handler;
|
||||
@@ -69,7 +37,7 @@ TEST_CASE("Signals: Test No-Exec") {
|
||||
void* Ptr = mmap(nullptr, PageSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
REQUIRE(Ptr != MAP_FAILED);
|
||||
|
||||
SimpleX86Emit emit(Ptr);
|
||||
SimpleX86Emit emit(Ptr, PageSize);
|
||||
emit.mov(SimpleX86Emit::Reg::RAX, 1);
|
||||
emit.ret();
|
||||
|
||||
@@ -99,3 +67,50 @@ TEST_CASE("Signals: Test No-Exec") {
|
||||
REQUIRE(Caught == true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Signals: Partial decode") {
|
||||
struct sigaction act {};
|
||||
act.sa_sigaction = SIGSEGV_Handler;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
|
||||
sigaction(SIGSEGV, &act, nullptr);
|
||||
auto PageSize = sysconf(_SC_PAGESIZE);
|
||||
PageSize = PageSize > 0 ? PageSize : 0x1000;
|
||||
|
||||
void* Ptr = mmap(nullptr, PageSize * 2, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
REQUIRE(Ptr != MAP_FAILED);
|
||||
|
||||
SimpleX86Emit emit(static_cast<uint8_t*>(Ptr) + PageSize - 1, PageSize + 1);
|
||||
|
||||
// MOV <uint32_t> hits the end of the page, writing only the opcode.
|
||||
emit.mov(SimpleX86Emit::Reg::RAX, 0x42424242);
|
||||
emit.ret();
|
||||
|
||||
// Protect second page
|
||||
REQUIRE(mprotect(static_cast<uint8_t*>(Ptr) + PageSize, PageSize, PROT_NONE) == 0);
|
||||
|
||||
using func_ptr = uint32_t (*)();
|
||||
func_ptr func = reinterpret_cast<func_ptr>(static_cast<uint8_t*>(Ptr) + PageSize - 1);
|
||||
Caught = false;
|
||||
if (setjmp(LongJump) == 0) {
|
||||
REQUIRE(func() != 0x42424242);
|
||||
} else {
|
||||
REQUIRE(Caught == true);
|
||||
CHECK(CaughtAddr == (reinterpret_cast<uint64_t>(Ptr) + PageSize));
|
||||
}
|
||||
|
||||
Caught = false;
|
||||
CaughtAddr = 0;
|
||||
|
||||
// Protect second page
|
||||
REQUIRE(mprotect(static_cast<uint8_t*>(Ptr) + PageSize, PageSize, PROT_READ | PROT_WRITE | PROT_EXEC) == 0);
|
||||
|
||||
if (setjmp(LongJump) == 0) {
|
||||
CHECK(func() == 0x42424242);
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
|
||||
CHECK(Caught == false);
|
||||
CHECK(CaughtAddr == 0);
|
||||
}
|
||||
Reference in new issue
Block a user