mirror of https://github.com/decompals/wibo.git
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:
parent
ceb13b34de
commit
218b4d7d76
|
@ -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
|
||||||
|
|
2
common.h
2
common.h
|
@ -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, ...);
|
||||||
|
|
||||||
|
|
133
dll/kernel32.cpp
133
dll/kernel32.cpp
|
@ -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;
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace handles {
|
||||||
TYPE_UNUSED,
|
TYPE_UNUSED,
|
||||||
TYPE_FILE,
|
TYPE_FILE,
|
||||||
TYPE_MAPPED,
|
TYPE_MAPPED,
|
||||||
|
TYPE_PROCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
|
|
15
main.cpp
15
main.cpp
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue