Implement enough process handling logic to make psyq4.0 happy (#46)

* Implement enough process handling logic to make psyq4.0 happy

* revert gitignore

* data type update

* PR review

* DEBUG_LOG mistake

---------

Co-authored-by: ConorBobbleHat <c.github@firstpartners.net>
This commit is contained in:
ConorB 2023-09-18 07:05:47 +01:00 committed by GitHub
parent ceb13b34de
commit 218b4d7d76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 167 additions and 23 deletions

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ build/
.vscode/ .vscode/
# CLion # CLion
.idea/ .idea/
cmake-build-*/ cmake-build-*/

View File

@ -28,6 +28,7 @@ add_executable(wibo
dll/vcruntime.cpp dll/vcruntime.cpp
dll/version.cpp dll/version.cpp
files.cpp files.cpp
processes.cpp
handles.cpp handles.cpp
loader.cpp loader.cpp
main.cpp main.cpp

View File

@ -72,8 +72,10 @@ namespace wibo {
extern uint32_t lastError; extern uint32_t lastError;
extern char **argv; extern char **argv;
extern int argc; extern int argc;
extern char *executableName;
extern char *commandLine; extern char *commandLine;
extern bool debugEnabled; extern bool debugEnabled;
extern unsigned int debugIndent;
void debug_log(const char *fmt, ...); void debug_log(const char *fmt, ...);

View File

@ -1,7 +1,9 @@
#include "common.h" #include "common.h"
#include "files.h" #include "files.h"
#include "processes.h"
#include "handles.h" #include "handles.h"
#include <algorithm> #include <algorithm>
#include <cstdlib>
#include <ctype.h> #include <ctype.h>
#include <filesystem> #include <filesystem>
#include <fnmatch.h> #include <fnmatch.h>
@ -11,6 +13,8 @@
#include <system_error> #include <system_error>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <spawn.h>
typedef union _RTL_RUN_ONCE { typedef union _RTL_RUN_ONCE {
PVOID Ptr; PVOID Ptr;
@ -198,32 +202,115 @@ namespace kernel32 {
exit(uExitCode); exit(uExitCode);
} }
int WIN_FUNC CreateProcessA( BOOL WIN_FUNC GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
const char *lpApplicationName, DEBUG_LOG("GetExitCodeProcess\n");
char *lpCommandLine,
void *lpProcessAttributes, processes::Process* process = processes::processFromHandle(hProcess, false);
void *lpThreadAttributes, *lpExitCode = process->exitCode;
int bInheritHandles, return 1; // success in retrieval
int dwCreationFlags, }
void *lpEnvironment,
const char *lpCurrentDirectory, struct PROCESS_INFORMATION {
void *lpStartupInfo, HANDLE hProcess;
void *lpProcessInformation HANDLE hThread;
) { DWORD dwProcessId;
printf("CreateProcessA %s \"%s\" %p %p %d 0x%x %p %s %p %p\n", DWORD dwThreadId;
lpApplicationName, };
lpCommandLine,
lpProcessAttributes,
BOOL WIN_FUNC CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
void *lpProcessAttributes,
void *lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
void *lpStartupInfo,
PROCESS_INFORMATION *lpProcessInformation
) {
DEBUG_LOG("CreateProcessA %s \"%s\" %p %p %d 0x%x %p %s %p %p\n",
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes, lpThreadAttributes,
bInheritHandles, bInheritHandles,
dwCreationFlags, dwCreationFlags,
lpEnvironment, lpEnvironment,
lpCurrentDirectory ? lpCurrentDirectory : "<none>", lpCurrentDirectory ? lpCurrentDirectory : "<none>",
lpStartupInfo, lpStartupInfo,
lpProcessInformation lpProcessInformation
); );
printf("Cannot handle process creation, aborting\n");
exit(1); // Argument parsing
// First: how many arguments do we have?
size_t argc = 2;
for (size_t i = 1; i < strlen(lpCommandLine); i++) {
if (isspace(lpCommandLine[i]) && !isspace(lpCommandLine[i - 1]))
argc++;
}
char **argv = (char **) calloc(argc + 1, sizeof(char*));
argv[0] = wibo::executableName;
argv[1] = (char *) files::pathFromWindows(lpApplicationName).string().c_str();
char* arg = strtok(lpCommandLine, " ");
size_t current_arg_index = 2;
while (arg != NULL) {
// We're deliberately discarding the first token here
// to prevent from doubling up on the target executable name
// (it appears as lpApplicationName, and as the first token in lpCommandLine)
arg = strtok(NULL, " ");
argv[current_arg_index++] = arg;
}
argv[argc] = NULL; // Last element in argv should be a null pointer
// YET TODO: take into account process / thread attributes, environment variables
// working directory, etc.
setenv("WIBO_DEBUG_INDENT", std::to_string(wibo::debugIndent + 1).c_str(), true);
pid_t pid;
if (posix_spawn(&pid, wibo::executableName, NULL, NULL, argv, environ)) {
return 0;
};
*lpProcessInformation = {
.hProcess = processes::allocProcessHandle(pid),
.hThread = nullptr,
.dwProcessId = (DWORD) pid,
.dwThreadId = 42
};
return 1;
}
unsigned int WIN_FUNC WaitForSingleObject(void *hHandle, unsigned int dwMilliseconds) {
DEBUG_LOG("WaitForSingleObject (%u)\n", dwMilliseconds);
// TODO - wait on other objects?
// TODO: wait for less than forever
assert(dwMilliseconds == 0xffffffff);
processes::Process* process = processes::processFromHandle(hHandle, false);
int status;
waitpid(process->pid, &status, 0);
if (WIFEXITED(status)) {
process->exitCode = WEXITSTATUS(status);
} else {
// If we're here, *something* has caused our child process to exit abnormally
// Specific exit codes don't really map onto any of these situations - we just know it's bad.
// Specify a non-zero exit code to alert our parent process something's gone wrong.
DEBUG_LOG("WaitForSingleObject: Child process exited abnormally - returning exit code 1.");
process->exitCode = 1;
}
return 0; return 0;
} }
@ -498,6 +585,8 @@ namespace kernel32 {
if (data.ptr != (void *) 0x1) { if (data.ptr != (void *) 0x1) {
munmap(data.ptr, data.size); munmap(data.ptr, data.size);
} }
} else if (data.type == handles::TYPE_PROCESS) {
delete (processes::Process*) data.ptr;
} }
return TRUE; return TRUE;
} }
@ -1895,6 +1984,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "GetCurrentProcessId") == 0) return (void *) kernel32::GetCurrentProcessId; if (strcmp(name, "GetCurrentProcessId") == 0) return (void *) kernel32::GetCurrentProcessId;
if (strcmp(name, "GetCurrentThreadId") == 0) return (void *) kernel32::GetCurrentThreadId; if (strcmp(name, "GetCurrentThreadId") == 0) return (void *) kernel32::GetCurrentThreadId;
if (strcmp(name, "ExitProcess") == 0) return (void *) kernel32::ExitProcess; if (strcmp(name, "ExitProcess") == 0) return (void *) kernel32::ExitProcess;
if (strcmp(name, "GetExitCodeProcess") == 0) return (void *) kernel32::GetExitCodeProcess;
if (strcmp(name, "CreateProcessA") == 0) return (void *) kernel32::CreateProcessA; if (strcmp(name, "CreateProcessA") == 0) return (void *) kernel32::CreateProcessA;
if (strcmp(name, "TlsAlloc") == 0) return (void *) kernel32::TlsAlloc; if (strcmp(name, "TlsAlloc") == 0) return (void *) kernel32::TlsAlloc;
if (strcmp(name, "TlsFree") == 0) return (void *) kernel32::TlsFree; if (strcmp(name, "TlsFree") == 0) return (void *) kernel32::TlsFree;
@ -1934,6 +2024,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "AcquireSRWLockExclusive") == 0) return (void *) kernel32::AcquireSRWLockExclusive; if (strcmp(name, "AcquireSRWLockExclusive") == 0) return (void *) kernel32::AcquireSRWLockExclusive;
if (strcmp(name, "ReleaseSRWLockExclusive") == 0) return (void *) kernel32::ReleaseSRWLockExclusive; if (strcmp(name, "ReleaseSRWLockExclusive") == 0) return (void *) kernel32::ReleaseSRWLockExclusive;
if (strcmp(name, "TryAcquireSRWLockExclusive") == 0) return (void *) kernel32::TryAcquireSRWLockExclusive; if (strcmp(name, "TryAcquireSRWLockExclusive") == 0) return (void *) kernel32::TryAcquireSRWLockExclusive;
if (strcmp(name, "WaitForSingleObject") == 0) return (void *) kernel32::WaitForSingleObject;
// winbase.h // winbase.h
if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc; if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc;

View File

@ -5,6 +5,7 @@ namespace handles {
TYPE_UNUSED, TYPE_UNUSED,
TYPE_FILE, TYPE_FILE,
TYPE_MAPPED, TYPE_MAPPED,
TYPE_PROCESS
}; };
struct Data { struct Data {

View File

@ -13,15 +13,22 @@
uint32_t wibo::lastError = 0; uint32_t wibo::lastError = 0;
char** wibo::argv; char** wibo::argv;
int wibo::argc; int wibo::argc;
char *wibo::executableName;
char *wibo::commandLine; char *wibo::commandLine;
wibo::Executable *wibo::mainModule = 0; wibo::Executable *wibo::mainModule = 0;
bool wibo::debugEnabled = false; bool wibo::debugEnabled = false;
unsigned int wibo::debugIndent = 0;
void wibo::debug_log(const char *fmt, ...) { void wibo::debug_log(const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
if (wibo::debugEnabled) if (wibo::debugEnabled) {
for (size_t i = 0; i < wibo::debugIndent; i++)
fprintf(stderr, "\t");
vfprintf(stderr, fmt, args); vfprintf(stderr, fmt, args);
}
va_end(args); va_end(args);
} }
@ -198,6 +205,11 @@ int main(int argc, char **argv) {
wibo::debugEnabled = true; wibo::debugEnabled = true;
} }
if (getenv("WIBO_DEBUG_INDENT")) {
wibo::debugIndent = std::stoul(getenv("WIBO_DEBUG_INDENT"));
}
files::init(); files::init();
// Create TIB // Create TIB
@ -264,6 +276,7 @@ int main(int argc, char **argv) {
wibo::commandLine = cmdLine.data(); wibo::commandLine = cmdLine.data();
DEBUG_LOG("Command line: %s\n", wibo::commandLine); DEBUG_LOG("Command line: %s\n", wibo::commandLine);
wibo::executableName = argv[0];
wibo::argv = argv + 1; wibo::argv = argv + 1;
wibo::argc = argc - 1; wibo::argc = argc - 1;

24
processes.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "processes.h"
#include "handles.h"
#include <cassert>
#include <cstdio>
namespace processes {
void *allocProcessHandle(pid_t pid) {
auto* process = new Process;
process->pid = pid;
process->exitCode = 0;
return handles::allocDataHandle(handles::Data{handles::TYPE_PROCESS, (void*)process, 0});
}
Process* processFromHandle(void *handle, bool pop) {
handles::Data data = handles::dataFromHandle(handle, pop);
if (data.type == handles::TYPE_PROCESS) {
return (Process*)data.ptr;
} else {
printf("Invalid file handle %p\n", handle);
assert(0);
}
}
}

12
processes.h Normal file
View File

@ -0,0 +1,12 @@
#include <cstdint>
#include <sched.h>
namespace processes {
struct Process {
pid_t pid;
uint32_t exitCode;
};
void *allocProcessHandle(pid_t pid);
Process* processFromHandle(void* hHandle, bool pop);
}