mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-23 10:00:47 +02:00
clone: Validate flags, cleanup
This commit is contained in:
1 parent
8a5813e4d0
commit
2ccaea7d66
3 files changed
+95
-102
No files matched your search
@@ -131,9 +131,6 @@ namespace FEXCore::Context {
|
||||
void CopyMemoryMapping(FEXCore::Core::InternalThreadState *ParentThread, FEXCore::Core::InternalThreadState *ChildThread);
|
||||
void RunThread(FEXCore::Core::InternalThreadState *Thread);
|
||||
|
||||
void HandleForkChildSide(uint64_t prevTID);
|
||||
uint64_t GetPIDHack();
|
||||
|
||||
protected:
|
||||
void ClearCodeCache(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
|
||||
|
||||
+1
-30
@@ -497,34 +497,6 @@ namespace FEXCore::Context {
|
||||
}
|
||||
}
|
||||
|
||||
static int indent = 0;
|
||||
|
||||
void Context::HandleForkChildSide(uint64_t PrevTID) {
|
||||
// Whoa okay, we have forked. Time to clean up
|
||||
|
||||
// Every thread that thinks it exists right now? Not real. Delete them
|
||||
for(auto iter = Threads.begin(); iter != Threads.end(); ++iter) {
|
||||
// Walk the thread list and delete every thread that isn't this one
|
||||
auto Thread = *iter;
|
||||
LogMan::Msg::D("[Child] Deleted a thread");
|
||||
//Thread->ExecutionThread.detach();
|
||||
//delete Thread;
|
||||
//Threads.erase(iter);
|
||||
}
|
||||
indent = 1;
|
||||
}
|
||||
|
||||
uint64_t Context::GetPIDHack() {
|
||||
std::lock_guard<std::mutex> lk(ThreadCreationMutex);
|
||||
for (auto &Thread : Threads) {
|
||||
if (Thread->State.ThreadManager.parent_tid == 0) {
|
||||
return Thread->State.ThreadManager.GetTID();
|
||||
}
|
||||
}
|
||||
|
||||
return ~0ULL;
|
||||
}
|
||||
|
||||
uintptr_t Context::CompileBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||
void *CodePtr {nullptr};
|
||||
uint8_t const *GuestCode{};
|
||||
@@ -772,8 +744,7 @@ namespace FEXCore::Context {
|
||||
|
||||
if (CoreDebugLevel >= 1) {
|
||||
char const *Name = LocalLoader->FindSymbolNameInRange(GuestRIP);
|
||||
std::string Index[2] = {"", "\t"};
|
||||
LogMan::Msg::D("%s[%d] >>>>RIP: 0x%lx(0x%lx): '%s'", Index[indent].c_str(), ::gettid(), GuestRIP, GuestRIP - MemoryBase, Name ? Name : "<Unknown>");
|
||||
LogMan::Msg::D("[%d:%d] >>>>RIP: 0x%lx(0x%lx): '%s'", ::getpid(), ::gettid(), GuestRIP, GuestRIP - MemoryBase, Name ? Name : "<Unknown>");
|
||||
}
|
||||
|
||||
if (!Thread->CPUBackend->NeedsOpDispatch()) {
|
||||
|
||||
+94
-69
@@ -71,63 +71,69 @@ namespace FEXCore::HLE {
|
||||
return NewThread;
|
||||
}
|
||||
|
||||
uint64_t DoFork(FEXCore::Core::InternalThreadState *Thread, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) {
|
||||
LogMan::Msg::E("FORKING!");
|
||||
uint64_t PrevTID = Thread->State.ThreadManager.TID;
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
uint64_t ForkGuest(FEXCore::Core::InternalThreadState *Thread, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) {
|
||||
pid_t Result = fork();
|
||||
|
||||
if (Result == 0) {
|
||||
// Child
|
||||
// uhhh...
|
||||
Thread->CTX->HandleForkChildSide(PrevTID);
|
||||
// update the internal TID
|
||||
Thread->State.ThreadManager.TID = ::gettid();
|
||||
}
|
||||
else {
|
||||
|
||||
// only a single thread running so no need to remove anything from the thread array
|
||||
|
||||
// Handle child setup now
|
||||
if (stack != nullptr) {
|
||||
// use specified stack
|
||||
LogMan::Msg::D("@@@@@@@ Fork uses custom stack");
|
||||
Thread->State.State.gregs[X86State::REG_RSP] = reinterpret_cast<uint64_t>(stack);
|
||||
} else {
|
||||
// In the case of fork and nullptr stack then the child uses the same stack space as the parent
|
||||
// Same virtual address, different addressspace
|
||||
LogMan::Msg::D("@@@@@@@ Fork uses parent stack");
|
||||
}
|
||||
|
||||
if (flags & CLONE_SETTLS) {
|
||||
Thread->State.State.fs = reinterpret_cast<uint64_t>(tls);
|
||||
}
|
||||
|
||||
// Sets the child TID to the pointer in ChildTID
|
||||
if (flags & CLONE_CHILD_SETTID) {
|
||||
Thread->State.ThreadManager.set_child_tid = child_tid;
|
||||
*child_tid = Thread->State.ThreadManager.TID;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
Thread->State.ThreadManager.clear_child_tid = child_tid;
|
||||
}
|
||||
|
||||
// the rest of the context remains as is, this thread will keep executing
|
||||
return 0;
|
||||
} else {
|
||||
if (Result != -1) {
|
||||
if (flags & CLONE_PARENT_SETTID) {
|
||||
*parent_tid = Result;
|
||||
}
|
||||
}
|
||||
// Parent
|
||||
return pid;
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
// Handle child setup now
|
||||
if (stack == nullptr) {
|
||||
// In the case of fork and nullptr stack then the child uses the same stack space as the parent
|
||||
// Same virtual address, different addressspace
|
||||
LogMan::Msg::D("@@@@@@@ Had to setup custom stack");
|
||||
stack = (void*)Thread->State.State.gregs[X86State::REG_RSP];
|
||||
}
|
||||
|
||||
LogMan::Msg::D("Time to spin up fork thread with Stack: 0x%lx\n", stack);
|
||||
auto NewThread = CreateNewThread(Thread, flags, stack, 0, child_tid, tls);
|
||||
|
||||
NewThread->State.State.gregs[FEXCore::X86State::REG_RAX] = 0;
|
||||
// Return the new threads TID
|
||||
uint64_t Result = NewThread->State.ThreadManager.GetTID();
|
||||
LogMan::Msg::D("Child [%d] starting at: 0x%lx. Parent was at 0x%lx", Result, NewThread->State.State.rip, Thread->State.State.rip);
|
||||
|
||||
// Actually start the thread
|
||||
Thread->CTX->RunThread(NewThread);
|
||||
|
||||
// This thread needs to die now
|
||||
// New thread becomes the new thread
|
||||
Thread->State.ThreadManager.parent_tid = ~0ULL;
|
||||
Thread->State.RunningEvents.ShouldStop = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AnyFlagsSet(uint64_t Flags, uint64_t Mask) {
|
||||
return (Flags & Mask) != 0;
|
||||
}
|
||||
|
||||
bool AllFlagsSet(uint64_t Flags, uint64_t Mask) {
|
||||
return (Flags & Mask) == Mask;
|
||||
}
|
||||
|
||||
void RegisterThread() {
|
||||
REGISTER_SYSCALL_IMPL(getpid, [](FEXCore::Core::InternalThreadState *Thread) -> uint64_t {
|
||||
#if 1
|
||||
uint64_t Result = Thread->CTX->GetPIDHack();
|
||||
if (Result == ~0ULL) {
|
||||
Result = ::getpid();
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
return Result;
|
||||
|
||||
#else
|
||||
uint64_t Result = ::getpid();
|
||||
SYSCALL_ERRNO();
|
||||
#endif
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(clone, [](FEXCore::Core::InternalThreadState *Thread, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) -> uint64_t {
|
||||
@@ -157,34 +163,53 @@ namespace FEXCore::HLE {
|
||||
FLAGPRINT(CLONE_NEWNET, 0x40000000);
|
||||
FLAGPRINT(CLONE_IO, 0x80000000);
|
||||
|
||||
if (!(flags & CLONE_VM)) {
|
||||
LogMan::Msg::D("Parent [%d] Leaving syscall at rip: 0x%lx", Thread->State.ThreadManager.GetTID(), Thread->State.State.rip);
|
||||
return DoFork(Thread, flags, stack, parent_tid, child_tid, tls);
|
||||
if (AnyFlagsSet(flags, CLONE_UNTRACED | CLONE_PTRACE)) {
|
||||
ERROR_AND_DIE("clone: Ptrace* not supported");
|
||||
}
|
||||
|
||||
auto NewThread = CreateNewThread(Thread, flags, stack, parent_tid, child_tid, tls);
|
||||
|
||||
// Return the new threads TID
|
||||
uint64_t Result = NewThread->State.ThreadManager.GetTID();
|
||||
LogMan::Msg::D("Child [%d] starting at: 0x%lx. Parent was at 0x%lx", Result, NewThread->State.State.rip, Thread->State.State.rip);
|
||||
|
||||
// Actually start the thread
|
||||
Thread->CTX->RunThread(NewThread);
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
|
||||
NewThread->ExecutionThread.join();
|
||||
if (AnyFlagsSet(flags, CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)) {
|
||||
ERROR_AND_DIE("clone: Namespaces are not supported");
|
||||
}
|
||||
|
||||
if (!(flags & CLONE_VM)) {
|
||||
// This thread needs to die now
|
||||
// New thread becomes the new thread
|
||||
NewThread->ExecutionThread.join();
|
||||
Thread->State.ThreadManager.parent_tid = ~0ULL;
|
||||
Thread->State.RunningEvents.ShouldStop = true;
|
||||
}
|
||||
if (!(flags & CLONE_THREAD)) {
|
||||
if (AnyFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM)) {
|
||||
ERROR_AND_DIE("clone: Unsuported flags w/o CLONE_THREAD (Shared Resources), %X", flags);
|
||||
}
|
||||
|
||||
SYSCALL_ERRNO();
|
||||
if (flags & CLONE_VFORK) {
|
||||
ERROR_AND_DIE("clone: Unsupported CLONE_VFORK w/o CLONE_THREAD");
|
||||
}
|
||||
|
||||
// CLONE_PARENT is ignored (Implied by CLONE_THREAD)
|
||||
|
||||
if (Thread->CTX->GetThreadCount() != 1) {
|
||||
ERROR_AND_DIE("clone: Fork only supported on single threaded applications");
|
||||
} else {
|
||||
LogMan::Msg::D("clone: Forking process");
|
||||
}
|
||||
|
||||
return ForkGuest(Thread, flags, stack, parent_tid, child_tid, tls);
|
||||
} else {
|
||||
|
||||
if (!AllFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) {
|
||||
ERROR_AND_DIE("clone: CLONE_THREAD: Unsuported flags w/ CLONE_THREAD (Shared Resources), %X", flags);
|
||||
}
|
||||
|
||||
auto NewThread = CreateNewThread(Thread, flags, stack, parent_tid, child_tid, tls);
|
||||
|
||||
// Return the new threads TID
|
||||
uint64_t Result = NewThread->State.ThreadManager.GetTID();
|
||||
LogMan::Msg::D("Child [%d] starting at: 0x%lx. Parent was at 0x%lx", Result, NewThread->State.State.rip, Thread->State.State.rip);
|
||||
|
||||
// Actually start the thread
|
||||
Thread->CTX->RunThread(NewThread);
|
||||
|
||||
if (flags & CLONE_VFORK) {
|
||||
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
|
||||
NewThread->ExecutionThread.join();
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(execve, [](FEXCore::Core::InternalThreadState *Thread, const char *pathname, char *const argv[], char *const envp[]) -> uint64_t {
|
||||
|
||||
Reference in new issue
Block a user