mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-12 12:00:44 +02:00
I had to change how blocks are represented to make it easier to parse This required a fairly substantial refactor that makes it so blocks are represented differently and we can walk them sequentially. This will make future analysis easier to deal with. Had to rewrite the passes and core's parsing of the IR afterwards. Moved RA in to a optimization pass to be shared between the JIT backends This works because x86-64 and AArch64 RA can be identical. Still doesn't support PHI nodes or spilling correctly, this is the first step in the process of getting there.
600 lines
19 KiB
C++
600 lines
19 KiB
C++
#include "Common/MathUtils.h"
|
|
|
|
#include "Interface/Context/Context.h"
|
|
#include "Interface/Core/InternalThreadState.h"
|
|
#include "Interface/HLE/Syscalls.h"
|
|
|
|
#include "LogManager.h"
|
|
|
|
#include <FEXCore/Core/X86Enums.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
|
|
constexpr uint64_t PAGE_SIZE = 4096;
|
|
|
|
namespace FEXCore {
|
|
#ifdef DEBUG_STRACE
|
|
void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret) {
|
|
switch (Args->Argument[0]) {
|
|
case SYSCALL_BRK: LogMan::Msg::D("brk(%p) = 0x%lx", Args->Argument[1], Ret); break;
|
|
case SYSCALL_ACCESS:
|
|
LogMan::Msg::D("access(\"%s\", %d) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_OPENAT:
|
|
LogMan::Msg::D("openat(%ld, \"%s\", %d) = %ld", Args->Argument[1], CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[2]), Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_STAT:
|
|
LogMan::Msg::D("stat(\"%s\", {...}) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Ret);
|
|
break;
|
|
case SYSCALL_FSTAT:
|
|
LogMan::Msg::D("fstat(%ld, {...}) = %ld", Args->Argument[1], Ret);
|
|
break;
|
|
case SYSCALL_MMAP:
|
|
LogMan::Msg::D("mmap(%p, %ld, %ld, %ld, %d, %p) = %p", Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], static_cast<int32_t>(Args->Argument[5]), Args->Argument[6], Ret);
|
|
break;
|
|
case SYSCALL_CLOSE:
|
|
LogMan::Msg::D("close(%ld) = %ld", Args->Argument[1], Ret);
|
|
break;
|
|
case SYSCALL_READ:
|
|
LogMan::Msg::D("read(%ld, {...}, %ld) = %ld", Args->Argument[1], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_ARCH_PRCTL:
|
|
LogMan::Msg::D("arch_prctl(%ld, %p) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_MPROTECT:
|
|
LogMan::Msg::D("mprotect(%p, %ld, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_MUNMAP:
|
|
LogMan::Msg::D("munmap(%p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_UNAME:
|
|
LogMan::Msg::D("uname ({...}) = %ld", Ret);
|
|
break;
|
|
case SYSCALL_UMASK:
|
|
LogMan::Msg::D("umask(0x%lx) = %ld", Args->Argument[1], Ret);
|
|
break;
|
|
case SYSCALL_CHDIR:
|
|
LogMan::Msg::D("chdir(\"%s\") = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Ret);
|
|
break;
|
|
case SYSCALL_EXIT:
|
|
LogMan::Msg::D("exit(0x%lx)", Args->Argument[1]);
|
|
break;
|
|
case SYSCALL_WRITE:
|
|
LogMan::Msg::D("write(%ld, %p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_WRITEV:
|
|
LogMan::Msg::D("writev(%ld, %p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_EXIT_GROUP:
|
|
LogMan::Msg::D("exit_group(0x%lx)", Args->Argument[1]);
|
|
break;
|
|
case SYSCALL_SET_TID_ADDRESS:
|
|
LogMan::Msg::D("set_tid_address(%p) = %ld", Args->Argument[1], Ret);
|
|
break;
|
|
case SYSCALL_SET_ROBUST_LIST:
|
|
LogMan::Msg::D("set_robust_list(%p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_RT_SIGACTION:
|
|
LogMan::Msg::D("rt_sigaction(%ld, %p, %p) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_RT_SIGPROCMASK:
|
|
LogMan::Msg::D("rt_sigprocmask(%ld, %p, %p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Ret);
|
|
break;
|
|
case SYSCALL_PRLIMIT64:
|
|
LogMan::Msg::D("prlimit64(%ld, %ld, %p, %p) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Ret);
|
|
break;
|
|
case SYSCALL_GETPID:
|
|
LogMan::Msg::D("getpid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_GETUID:
|
|
LogMan::Msg::D("getuid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_GETGID:
|
|
LogMan::Msg::D("getgid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_GETEUID:
|
|
LogMan::Msg::D("geteuid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_GETEGID:
|
|
LogMan::Msg::D("getegid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_GETTID:
|
|
LogMan::Msg::D("gettid() = %ld", Ret);
|
|
break;
|
|
case SYSCALL_TGKILL:
|
|
LogMan::Msg::D("tgkill(%ld, %ld) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_LSEEK:
|
|
LogMan::Msg::D("lseek(%ld, %ld, %ld = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_IOCTL:
|
|
LogMan::Msg::D("ioctl(%ld, %ld, %p) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
|
break;
|
|
case SYSCALL_TIME:
|
|
LogMan::Msg::D("time(%p) = %ld", Args->Argument[1], Ret);
|
|
break;
|
|
case SYSCALL_CLOCK_GETTIME:
|
|
LogMan::Msg::D("clock_gettime(%ld, %p) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
|
break;
|
|
case SYSCALL_READLINK:
|
|
LogMan::Msg::D("readlink(\"%s\") = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Ret);
|
|
break;
|
|
default: LogMan::Msg::D("Unknown strace: %d", Args->Argument[0]);
|
|
}
|
|
}
|
|
#endif
|
|
void SyscallHandler::DefaultProgramBreak(FEXCore::Core::InternalThreadState *Thread, uint64_t Addr) {
|
|
DataSpaceSize = 0;
|
|
DataSpace = Addr;
|
|
DefaultProgramBreakAddress = Addr;
|
|
|
|
// Just allocate 1GB of data memory past the default program break location at this point
|
|
CTX->MapRegion(Thread, Addr, 0x1000'0000, true);
|
|
}
|
|
|
|
uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Thread, FEXCore::HLE::SyscallArguments *Args) {
|
|
uint64_t Result = 0;
|
|
|
|
switch (Args->Argument[0]) {
|
|
case SYSCALL_UNAME: {
|
|
struct _utsname {
|
|
char sysname[65];
|
|
char nodename[65];
|
|
char release[65];
|
|
char version[65];
|
|
char machine[65];
|
|
};
|
|
_utsname *Local = CTX->MemoryMapper.GetPointer<_utsname*>(Args->Argument[1]);
|
|
strcpy(Local->sysname, "Linux");
|
|
strcpy(Local->nodename, "FEXCore");
|
|
strcpy(Local->release, "5.0.0");
|
|
strcpy(Local->version, "#1");
|
|
strcpy(Local->machine, "x86_64");
|
|
Result = 0;
|
|
break;
|
|
}
|
|
// Memory management
|
|
case SYSCALL_BRK: {
|
|
if (Args->Argument[1] == 0) { // Just wants to get the location of the program break atm
|
|
if (DataSpace == 0) {
|
|
// XXX: We need to setup our default BRK space first
|
|
DefaultProgramBreak(Thread, 0xe000'0000);
|
|
}
|
|
Result = DataSpace + DataSpaceSize;
|
|
}
|
|
else {
|
|
// Allocating out data space
|
|
uint64_t NewEnd = Args->Argument[1];
|
|
if (NewEnd < DataSpace) {
|
|
// Not allowed to move brk end below original start
|
|
// Set the size to zero
|
|
DataSpaceSize = 0;
|
|
}
|
|
else {
|
|
uint64_t NewSize = NewEnd - DataSpace;
|
|
DataSpaceSize = NewSize;
|
|
}
|
|
Result = DataSpace + DataSpaceSize;
|
|
}
|
|
break;
|
|
}
|
|
case SYSCALL_MMAP: {
|
|
int Flags = Args->Argument[4];
|
|
int GuestFD = static_cast<int32_t>(Args->Argument[5]);
|
|
int HostFD = -1;
|
|
|
|
if (GuestFD != -1) {
|
|
HostFD = FM.FindHostFD(GuestFD);
|
|
}
|
|
|
|
uint64_t Base = AlignDown(LastMMAP, PAGE_SIZE);
|
|
uint64_t Size = AlignUp(Args->Argument[2], PAGE_SIZE);
|
|
uint64_t FileSizeToUse = Args->Argument[2];
|
|
uint64_t Prot = Args->Argument[3];
|
|
|
|
#ifdef DEBUG_MMAP
|
|
// FileSizeToUse = Size;
|
|
#endif
|
|
Prot = PROT_READ | PROT_WRITE | PROT_EXEC;
|
|
|
|
if (Flags & MAP_FIXED) {
|
|
Base = Args->Argument[1];
|
|
void *HostPtr = CTX->MemoryMapper.GetPointerSizeCheck(Base, FileSizeToUse);
|
|
if (!HostPtr) {
|
|
HostPtr = CTX->MapRegion(Thread, Base, Size, true);
|
|
}
|
|
else {
|
|
LogMan::Msg::D("\tMapping Fixed pointer in already mapped space: 0x%lx -> %p", Base, HostPtr);
|
|
}
|
|
|
|
if (HostFD != -1) {
|
|
#ifdef DEBUG_MMAP
|
|
// We are a file. Screw you I'm going to just memcpy you in to place
|
|
void *FileMem = mmap(nullptr, FileSizeToUse, Prot, MAP_PRIVATE, HostFD, Args->Argument[6]);
|
|
if (FileMem == MAP_FAILED) {
|
|
LogMan::Msg::A("Couldn't map file to %p\n", HostPtr);
|
|
}
|
|
|
|
memcpy(HostPtr, FileMem, FileSizeToUse);
|
|
munmap(FileMem, Size);
|
|
#else
|
|
void *FileMem = mmap(HostPtr, FileSizeToUse, Prot, MAP_PRIVATE | MAP_FIXED, HostFD, Args->Argument[6]);
|
|
if (FileMem == MAP_FAILED) {
|
|
LogMan::Msg::A("Couldn't map file to %p\n", HostPtr);
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
LogMan::Throw::A(Args->Argument[6] == 0, "Don't understand a fixed offset mmap");
|
|
}
|
|
|
|
Result = Base;
|
|
}
|
|
else {
|
|
// XXX: MMAP should map memory regions for all threads
|
|
void *HostPtr = CTX->MemoryMapper.GetPointerSizeCheck(Base, FileSizeToUse);
|
|
if (!HostPtr) {
|
|
HostPtr = CTX->MapRegion(Thread, Base, Size, true);
|
|
}
|
|
else {
|
|
LogMan::Msg::D("\tMapping Fixed pointer in already mapped space: 0x%lx -> %p", Base, HostPtr);
|
|
}
|
|
|
|
if (HostFD != -1) {
|
|
#ifdef DEBUG_MMAP
|
|
// We are a file. Screw you I'm going to just memcpy you in to place
|
|
void *FileMem = mmap(nullptr, FileSizeToUse, Prot, MAP_PRIVATE, HostFD, Args->Argument[6]);
|
|
if (FileMem == MAP_FAILED) {
|
|
LogMan::Msg::A("Couldn't map file to %p\n", HostPtr);
|
|
}
|
|
|
|
memcpy(HostPtr, FileMem, FileSizeToUse);
|
|
munmap(FileMem, Size);
|
|
#else
|
|
void *FileMem = mmap(HostPtr, FileSizeToUse, Prot, MAP_PRIVATE | MAP_FIXED, HostFD, Args->Argument[6]);
|
|
if (FileMem == MAP_FAILED) {
|
|
LogMan::Msg::A("Couldn't map file to %p\n", HostPtr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LastMMAP += Size;
|
|
Result = Base;
|
|
}
|
|
break;
|
|
}
|
|
case SYSCALL_MPROTECT: {
|
|
void *HostPtr = CTX->MemoryMapper.GetPointer<void*>(Args->Argument[1]);
|
|
|
|
// Result = mprotect(HostPtr, Args->Argument[2], Args->Argument[3]);
|
|
break;
|
|
}
|
|
case SYSCALL_ARCH_PRCTL: {
|
|
switch (Args->Argument[1]) {
|
|
case 0x1001: // ARCH_SET_GS
|
|
Thread->State.State.gs = Args->Argument[2];
|
|
break;
|
|
case 0x1002: // ARCH_SET_FS
|
|
Thread->State.State.fs = Args->Argument[2];
|
|
break;
|
|
case 0x1003: // ARCH_GET_FS
|
|
*CTX->MemoryMapper.GetPointer<uint64_t*>(Args->Argument[2]) = Thread->State.State.fs;
|
|
break;
|
|
case 0x1004: // ARCH_GET_GS
|
|
*CTX->MemoryMapper.GetPointer<uint64_t*>(Args->Argument[2]) = Thread->State.State.gs;
|
|
break;
|
|
default:
|
|
LogMan::Msg::E("Unknown prctl: 0x%x", Args->Argument[1]);
|
|
CTX->ShouldStop = true;
|
|
break;
|
|
}
|
|
Result = 0;
|
|
break;
|
|
}
|
|
// Thread management
|
|
case SYSCALL_GETUID:
|
|
Result = Thread->State.ThreadManager.GetUID();
|
|
break;
|
|
case SYSCALL_GETGID:
|
|
Result = Thread->State.ThreadManager.GetGID();
|
|
break;
|
|
case SYSCALL_GETEUID:
|
|
Result = Thread->State.ThreadManager.GetEUID();
|
|
break;
|
|
case SYSCALL_GETEGID:
|
|
Result = Thread->State.ThreadManager.GetEGID();
|
|
break;
|
|
case SYSCALL_GETTID:
|
|
Result = Thread->State.ThreadManager.GetTID();
|
|
break;
|
|
case SYSCALL_GETPID:
|
|
Result = Thread->State.ThreadManager.GetPID();
|
|
break;
|
|
case SYSCALL_EXIT:
|
|
LogMan::Msg::D("Thread exit with: %zd\n", Args->Argument[1]);
|
|
Thread->State.RunningEvents.ShouldStop = true;
|
|
break;
|
|
case SYSCALL_WAIT4:
|
|
LogMan::Msg::I("wait4(%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
|
Args->Argument[1],
|
|
Args->Argument[2],
|
|
Args->Argument[3],
|
|
Args->Argument[4]);
|
|
break;
|
|
|
|
// Futexes
|
|
case SYSCALL_FUTEX: {
|
|
|
|
// 0 : uaddr
|
|
// 1 : op
|
|
// 2: val
|
|
// 3: utime
|
|
// 4: uaddr2
|
|
// 5: val3
|
|
LogMan::Msg::I("futex(%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
|
Args->Argument[1],
|
|
Args->Argument[2],
|
|
Args->Argument[3],
|
|
Args->Argument[4],
|
|
Args->Argument[5],
|
|
Args->Argument[6]);
|
|
|
|
uint8_t Command = Args->Argument[2] & 0xF;
|
|
Result = 0;
|
|
switch (Command) {
|
|
case 0: { // WAIT
|
|
LogMan::Throw::A(!Args->Argument[4], "Can't handle timed futexes");
|
|
Futex *futex = new Futex{}; // XXX: Definitely a memory leak. When should we free this?
|
|
futex->Addr = CTX->MemoryMapper.GetPointer<std::atomic<uint32_t>*>(Args->Argument[1]);
|
|
futex->Val = Args->Argument[3];
|
|
EmplaceFutex(Args->Argument[1], futex);
|
|
{
|
|
std::unique_lock<std::mutex> lk(futex->Mutex);
|
|
futex->cv.wait(lk, [futex] { return futex->Addr->load() != futex->Val; });
|
|
}
|
|
break;
|
|
}
|
|
case 1: { // WAKE
|
|
Futex *futex = GetFutex(Args->Argument[1]);
|
|
if (!futex) {
|
|
Result = 0;
|
|
break;
|
|
}
|
|
for (uint64_t i = 0; i < Args->Argument[3]; ++i)
|
|
futex->cv.notify_one();
|
|
break;
|
|
}
|
|
default:
|
|
LogMan::Msg::A("Unknown futex command");
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SYSCALL_CLONE: {
|
|
// 0: clone_flags
|
|
// 1: New SP
|
|
// 2: parent tidptr
|
|
// 3: child tidptr
|
|
// 4: TLS
|
|
LogMan::Msg::I("clone(%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
|
Args->Argument[0],
|
|
Args->Argument[1],
|
|
Args->Argument[2],
|
|
Args->Argument[3],
|
|
Args->Argument[4],
|
|
Args->Argument[5]);
|
|
uint32_t Flags = Args->Argument[1];
|
|
uint64_t NewSP = Args->Argument[2];
|
|
uint64_t ParentTID = Args->Argument[3];
|
|
uint64_t ChildTID = Args->Argument[4];
|
|
uint64_t NewTLS = Args->Argument[5];
|
|
#define FLAGPRINT(x, y) if (Flags & (y)) LogMan::Msg::I("\tFlag: " #x)
|
|
FLAGPRINT(CSIGNAL, 0x000000FF);
|
|
FLAGPRINT(CLONE_VM, 0x00000100);
|
|
FLAGPRINT(CLONE_FS, 0x00000200);
|
|
FLAGPRINT(CLONE_FILES, 0x00000400);
|
|
FLAGPRINT(CLONE_SIGHAND, 0x00000800);
|
|
FLAGPRINT(CLONE_PTRACE, 0x00002000);
|
|
FLAGPRINT(CLONE_VFORK, 0x00004000);
|
|
FLAGPRINT(CLONE_PARENT, 0x00008000);
|
|
FLAGPRINT(CLONE_THREAD, 0x00010000);
|
|
FLAGPRINT(CLONE_NEWNS, 0x00020000);
|
|
FLAGPRINT(CLONE_SYSVSEM, 0x00040000);
|
|
FLAGPRINT(CLONE_SETTLS, 0x00080000);
|
|
FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000);
|
|
FLAGPRINT(CLONE_CHILD_CLEARTID, 0x00200000);
|
|
FLAGPRINT(CLONE_DETACHED, 0x00400000);
|
|
FLAGPRINT(CLONE_UNTRACED, 0x00800000);
|
|
FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000);
|
|
FLAGPRINT(CLONE_NEWCGROUP, 0x02000000);
|
|
FLAGPRINT(CLONE_NEWUTS, 0x04000000);
|
|
FLAGPRINT(CLONE_NEWIPC, 0x08000000);
|
|
FLAGPRINT(CLONE_NEWUSER, 0x10000000);
|
|
FLAGPRINT(CLONE_NEWPID, 0x20000000);
|
|
FLAGPRINT(CLONE_NEWNET, 0x40000000);
|
|
FLAGPRINT(CLONE_IO, 0x80000000);
|
|
|
|
FEXCore::Core::CPUState NewThreadState{};
|
|
// Clone copies the parent thread's state
|
|
memcpy(&NewThreadState, &Thread->State.State, sizeof(FEXCore::Core::CPUState));
|
|
|
|
NewThreadState.gregs[FEXCore::X86State::REG_RAX] = 0;
|
|
NewThreadState.gregs[FEXCore::X86State::REG_RBX] = 0;
|
|
NewThreadState.gregs[FEXCore::X86State::REG_RBP] = 0;
|
|
NewThreadState.gregs[FEXCore::X86State::REG_RSP] = NewSP;
|
|
NewThreadState.fs = NewTLS;
|
|
|
|
// Set us to start just after the syscall instruction
|
|
NewThreadState.rip += 2;
|
|
|
|
auto NewThread = CTX->CreateThread(&NewThreadState, ParentTID, ChildTID);
|
|
CTX->CopyMemoryMapping(Thread, NewThread);
|
|
|
|
// Sets the child TID to pointer in ParentTID
|
|
if (Flags & CLONE_PARENT_SETTID) {
|
|
uint64_t *TIDPtr = CTX->MemoryMapper.GetPointer<uint64_t*>(ParentTID);
|
|
TIDPtr[0] = NewThread->State.ThreadManager.GetTID();
|
|
}
|
|
|
|
// Sets the child TID to the pointer in ChildTID
|
|
if (Flags & CLONE_CHILD_SETTID) {
|
|
uint64_t *TIDPtr = CTX->MemoryMapper.GetPointer<uint64_t*>(ChildTID);
|
|
TIDPtr[0] = NewThread->State.ThreadManager.GetTID();
|
|
}
|
|
|
|
// When the thread exits, clear the child thread ID at ChildTID
|
|
// Additionally wakeup a futex at that address
|
|
// Address /may/ be changed with SET_TID_ADDRESS syscall
|
|
if (Flags & CLONE_CHILD_CLEARTID) {
|
|
}
|
|
|
|
CTX->InitializeThread(NewThread);
|
|
|
|
// Actually start the thread
|
|
CTX->RunThread(NewThread);
|
|
|
|
// Return the new threads TID
|
|
Result = NewThread->State.ThreadManager.GetTID();
|
|
break;
|
|
}
|
|
// File management
|
|
case SYSCALL_READ:
|
|
Result = FM.Read(Args->Argument[1],
|
|
CTX->MemoryMapper.GetPointer(Args->Argument[2]),
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_WRITE:
|
|
Result = FM.Write(Args->Argument[1],
|
|
CTX->MemoryMapper.GetPointer(Args->Argument[2]),
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_OPEN:
|
|
Result = FM.Open(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]),
|
|
Args->Argument[2],
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_CLOSE:
|
|
Result = FM.Close(Args->Argument[1]);
|
|
break;
|
|
case SYSCALL_STAT:
|
|
Result = FM.Stat(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]),
|
|
CTX->MemoryMapper.GetPointer(Args->Argument[2]));
|
|
break;
|
|
case SYSCALL_FSTAT:
|
|
Result = FM.Fstat(Args->Argument[1],
|
|
CTX->MemoryMapper.GetPointer(Args->Argument[2]));
|
|
break;
|
|
case SYSCALL_LSEEK:
|
|
Result = FM.Lseek(Args->Argument[1],
|
|
Args->Argument[2],
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_WRITEV:
|
|
Result = FM.Writev(Args->Argument[1],
|
|
CTX->MemoryMapper.GetPointer(Args->Argument[2]),
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_ACCESS:
|
|
Result = FM.Access(
|
|
CTX->MemoryMapper.GetPointer<const char*>(Args->Argument[1]),
|
|
Args->Argument[2]);
|
|
break;
|
|
case SYSCALL_READLINK:
|
|
Result = FM.Readlink(
|
|
CTX->MemoryMapper.GetPointer<const char*>(Args->Argument[1]),
|
|
CTX->MemoryMapper.GetPointer<char*>(Args->Argument[2]),
|
|
Args->Argument[3]);
|
|
break;
|
|
case SYSCALL_OPENAT:
|
|
Result = FM.Openat(
|
|
Args->Argument[1],
|
|
CTX->MemoryMapper.GetPointer<const char*>(Args->Argument[2]),
|
|
Args->Argument[3],
|
|
Args->Argument[4]);
|
|
break;
|
|
case SYSCALL_IOCTL:
|
|
Result = FM.Ioctl(
|
|
Args->Argument[1],
|
|
Args->Argument[2],
|
|
CTX->MemoryMapper.GetPointer<void*>(Args->Argument[3]));
|
|
break;
|
|
|
|
case SYSCALL_TIME: {
|
|
time_t *ClockResult = CTX->MemoryMapper.GetPointer<time_t*>(Args->Argument[2]);
|
|
Result = time(ClockResult);
|
|
// XXX: Debug
|
|
// memset(ClockResult, 0, sizeof(time_t));
|
|
// Result = 0;
|
|
}
|
|
break;
|
|
case SYSCALL_CLOCK_GETTIME: {
|
|
timespec *ClockResult = CTX->MemoryMapper.GetPointer<timespec*>(Args->Argument[2]);
|
|
Result = clock_gettime(Args->Argument[1], ClockResult);
|
|
// XXX: Debug
|
|
// memset(ClockResult, 0, sizeof(timespec));
|
|
}
|
|
break;
|
|
case SYSCALL_NANOSLEEP: {
|
|
timespec const* req = CTX->MemoryMapper.GetPointer<timespec const*>(Args->Argument[1]);
|
|
timespec *rem = CTX->MemoryMapper.GetPointer<timespec*>(Args->Argument[2]);
|
|
Result = nanosleep(req, rem);
|
|
break;
|
|
}
|
|
case SYSCALL_SET_TID_ADDRESS: {
|
|
Thread->State.ThreadManager.child_tid = Args->Argument[1];
|
|
Result = Thread->State.ThreadManager.GetTID();
|
|
break;
|
|
}
|
|
case SYSCALL_SET_ROBUST_LIST: {
|
|
Thread->State.ThreadManager.robust_list_head = Args->Argument[1];
|
|
Result = 0;
|
|
break;
|
|
}
|
|
case SYSCALL_PRLIMIT64: {
|
|
LogMan::Throw::A(Args->Argument[3] == 0, "Guest trying to set limit for %d", Args->Argument[2]);
|
|
struct rlimit {
|
|
uint64_t rlim_cur;
|
|
uint64_t rlim_max;
|
|
};
|
|
switch (Args->Argument[2]) {
|
|
case 3: { // Stack limits
|
|
rlimit *old_limit = CTX->MemoryMapper.GetPointer<rlimit*>(Args->Argument[3]);
|
|
// Default size
|
|
old_limit->rlim_cur = 8 * 1024;
|
|
old_limit->rlim_max = ~0ULL;
|
|
break;
|
|
}
|
|
default: LogMan::Msg::A("Unknown PRLimit: %d", Args->Argument[2]);
|
|
}
|
|
Result = 0;
|
|
break;
|
|
}
|
|
case SYSCALL_UMASK:
|
|
// Just say that the mask has always matched what was passed in
|
|
Result = Args->Argument[1];
|
|
break;
|
|
case SYSCALL_CHDIR:
|
|
Result = chdir(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]));
|
|
break;
|
|
// Currently unhandled
|
|
// Return fake result
|
|
case SYSCALL_RT_SIGACTION:
|
|
case SYSCALL_RT_SIGPROCMASK:
|
|
case SYSCALL_EXIT_GROUP:
|
|
case SYSCALL_TGKILL:
|
|
case SYSCALL_MUNMAP:
|
|
Result = 0;
|
|
break;
|
|
default:
|
|
Result = -1;
|
|
LogMan::Msg::A("Unknown syscall: %d", Args->Argument[0]);
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_STRACE
|
|
Strace(Args, Result);
|
|
#endif
|
|
return Result;
|
|
}
|
|
}
|