Fix up some kernel32 logging

This commit is contained in:
Luke Street 2025-09-29 22:30:57 -06:00
parent 7f9d141a20
commit cb154f3118
2 changed files with 72 additions and 48 deletions

View File

@ -23,7 +23,7 @@
- Target pre-XP behavior; our binaries are old and don't expect modern WinAPI behavior. - Target pre-XP behavior; our binaries are old and don't expect modern WinAPI behavior.
- Use the `microsoft_docs` tools to fetch WinAPI signatures and documentation; always fetch the documentation when working on an API function. - Use the `microsoft_docs` tools to fetch WinAPI signatures and documentation; always fetch the documentation when working on an API function.
- Create minimal, self-contained repros in `test/` when implementing or debugging APIs; this aids both development and future testing. - Create minimal, self-contained repros in `test/` when implementing or debugging APIs; this aids both development and future testing.
- Stub unimplemented APIs with `DEBUG_LOG` calls to track usage; prioritize based on the needs of real-world binaries. - Add `DEBUG_LOG` calls to trace execution and parameter values; these are invaluable when diagnosing issues with real-world binaries.
## Testing Guidelines ## Testing Guidelines
- Fixture binaries live in `test/` and are compiled automatically when `BUILD_TESTING` is enabled; keep new repros small and self-contained (`test_<feature>.c`). - Fixture binaries live in `test/` and are compiled automatically when `BUILD_TESTING` is enabled; keep new repros small and self-contained (`test_<feature>.c`).

View File

@ -584,7 +584,7 @@ namespace kernel32 {
} }
BOOL WIN_FUNC GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) { BOOL WIN_FUNC GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
DEBUG_LOG("GetExitCodeProcess\n"); DEBUG_LOG("GetExitCodeProcess(%p, %p)\n", hProcess, lpExitCode);
processes::Process* process = processes::processFromHandle(hProcess, false); processes::Process* process = processes::processFromHandle(hProcess, false);
*lpExitCode = process->exitCode; *lpExitCode = process->exitCode;
@ -598,7 +598,7 @@ namespace kernel32 {
} }
void WIN_FUNC GetSystemInfo(SYSTEM_INFO *lpSystemInfo) { void WIN_FUNC GetSystemInfo(SYSTEM_INFO *lpSystemInfo) {
DEBUG_LOG("GetSystemInfo\n"); DEBUG_LOG("GetSystemInfo(%p)\n", lpSystemInfo);
if (!lpSystemInfo) { if (!lpSystemInfo) {
return; return;
} }
@ -783,7 +783,7 @@ namespace kernel32 {
} }
unsigned int WIN_FUNC WaitForSingleObject(void *hHandle, unsigned int dwMilliseconds) { unsigned int WIN_FUNC WaitForSingleObject(void *hHandle, unsigned int dwMilliseconds) {
DEBUG_LOG("WaitForSingleObject (%u)\n", dwMilliseconds); DEBUG_LOG("WaitForSingleObject(%p, %u)\n", hHandle, dwMilliseconds);
handles::Data data = handles::dataFromHandle(hHandle, false); handles::Data data = handles::dataFromHandle(hHandle, false);
switch (data.type) { switch (data.type) {
case handles::TYPE_PROCESS: { case handles::TYPE_PROCESS: {
@ -886,7 +886,7 @@ namespace kernel32 {
} }
int WIN_FUNC GetSystemDefaultLangID() { int WIN_FUNC GetSystemDefaultLangID() {
DEBUG_LOG("STUB GetSystemDefaultLangID\n"); DEBUG_LOG("STUB: GetSystemDefaultLangID()\n");
return 0; return 0;
} }
@ -919,32 +919,35 @@ namespace kernel32 {
}; };
void WIN_FUNC InitializeCriticalSection(CRITICAL_SECTION *param) { void WIN_FUNC InitializeCriticalSection(CRITICAL_SECTION *param) {
// DEBUG_LOG("InitializeCriticalSection(...)\n"); VERBOSE_LOG("STUB: InitializeCriticalSection(%p)\n", param);
}
void WIN_FUNC InitializeCriticalSectionEx(CRITICAL_SECTION *param) {
// DEBUG_LOG("InitializeCriticalSection(...)\n");
}
void WIN_FUNC DeleteCriticalSection(CRITICAL_SECTION *param) {
// DEBUG_LOG("DeleteCriticalSection(...)\n");
}
void WIN_FUNC EnterCriticalSection(CRITICAL_SECTION *param) {
// DEBUG_LOG("EnterCriticalSection(...)\n");
}
void WIN_FUNC LeaveCriticalSection(CRITICAL_SECTION *param) {
// DEBUG_LOG("LeaveCriticalSection(...)\n");
} }
unsigned int WIN_FUNC InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection, unsigned int dwSpinCount) { void WIN_FUNC InitializeCriticalSectionEx(CRITICAL_SECTION *param) {
DEBUG_LOG("InitializeCriticalSectionAndSpinCount (%i)\n", dwSpinCount); VERBOSE_LOG("STUB: InitializeCriticalSectionEx(%p)\n", param);
// can we get away with doing nothing...? }
void WIN_FUNC DeleteCriticalSection(CRITICAL_SECTION *param) {
VERBOSE_LOG("STUB: DeleteCriticalSection(%p)\n", param);
}
void WIN_FUNC EnterCriticalSection(CRITICAL_SECTION *param) {
VERBOSE_LOG("STUB: EnterCriticalSection(%p)\n", param);
}
void WIN_FUNC LeaveCriticalSection(CRITICAL_SECTION *param) {
VERBOSE_LOG("STUB: LeaveCriticalSection(%p)\n", param);
}
unsigned int WIN_FUNC InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *lpCriticalSection,
unsigned int dwSpinCount) {
DEBUG_LOG("STUB: InitializeCriticalSectionAndSpinCount(%p, %i)\n", lpCriticalSection, dwSpinCount);
memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION)); memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION));
lpCriticalSection->SpinCount = dwSpinCount; lpCriticalSection->SpinCount = dwSpinCount;
return 1; return 1;
} }
int WIN_FUNC InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext) { int WIN_FUNC InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext) {
DEBUG_LOG("STUB: InitOnceBeginInitialize\n"); DEBUG_LOG("STUB: InitOnceBeginInitialize(%p, %u, %p, %p)\n", lpInitOnce, dwFlags, fPending, lpContext);
if (fPending != nullptr) { if (fPending != nullptr) {
*fPending = TRUE; *fPending = TRUE;
} }
@ -952,20 +955,24 @@ namespace kernel32 {
} }
BOOL WIN_FUNC InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext) { BOOL WIN_FUNC InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext) {
DEBUG_LOG("STUB: InitOnceComplete\n"); DEBUG_LOG("STUB: InitOnceComplete(%p, %u, %p)\n", lpInitOnce, dwFlags, lpContext);
return TRUE; return TRUE;
} }
void WIN_FUNC AcquireSRWLockShared(void *SRWLock) { DEBUG_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock); } void WIN_FUNC AcquireSRWLockShared(void *SRWLock) { VERBOSE_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock); }
void WIN_FUNC ReleaseSRWLockShared(void *SRWLock) { DEBUG_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock); } void WIN_FUNC ReleaseSRWLockShared(void *SRWLock) { VERBOSE_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock); }
void WIN_FUNC AcquireSRWLockExclusive(void *SRWLock) { DEBUG_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock); } void WIN_FUNC AcquireSRWLockExclusive(void *SRWLock) {
VERBOSE_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock);
}
void WIN_FUNC ReleaseSRWLockExclusive(void *SRWLock) { DEBUG_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock); } void WIN_FUNC ReleaseSRWLockExclusive(void *SRWLock) {
VERBOSE_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock);
}
int WIN_FUNC TryAcquireSRWLockExclusive(void *SRWLock) { int WIN_FUNC TryAcquireSRWLockExclusive(void *SRWLock) {
DEBUG_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock); VERBOSE_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock);
return 1; return 1;
} }
@ -976,22 +983,22 @@ namespace kernel32 {
static bool tlsValuesUsed[MAX_TLS_VALUES] = { false }; static bool tlsValuesUsed[MAX_TLS_VALUES] = { false };
static void *tlsValues[MAX_TLS_VALUES]; static void *tlsValues[MAX_TLS_VALUES];
unsigned int WIN_FUNC TlsAlloc() { unsigned int WIN_FUNC TlsAlloc() {
DEBUG_LOG("TlsAlloc()\n"); VERBOSE_LOG("TlsAlloc()\n");
for (size_t i = 0; i < MAX_TLS_VALUES; i++) { for (size_t i = 0; i < MAX_TLS_VALUES; i++) {
if (tlsValuesUsed[i] == false) { if (tlsValuesUsed[i] == false) {
tlsValuesUsed[i] = true; tlsValuesUsed[i] = true;
tlsValues[i] = 0; tlsValues[i] = 0;
DEBUG_LOG("...returning %d\n", i); VERBOSE_LOG("...returning %d\n", i);
return i; return i;
} }
} }
DEBUG_LOG("...returning nothing\n"); VERBOSE_LOG("...returning nothing\n");
wibo::lastError = 1; wibo::lastError = 1;
return 0xFFFFFFFF; // TLS_OUT_OF_INDEXES return 0xFFFFFFFF; // TLS_OUT_OF_INDEXES
} }
unsigned int WIN_FUNC TlsFree(unsigned int dwTlsIndex) { unsigned int WIN_FUNC TlsFree(unsigned int dwTlsIndex) {
DEBUG_LOG("TlsFree(%u)\n", dwTlsIndex); VERBOSE_LOG("TlsFree(%u)\n", dwTlsIndex);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) { if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValuesUsed[dwTlsIndex] = false; tlsValuesUsed[dwTlsIndex] = false;
return 1; return 1;
@ -1002,7 +1009,7 @@ namespace kernel32 {
} }
void *WIN_FUNC TlsGetValue(unsigned int dwTlsIndex) { void *WIN_FUNC TlsGetValue(unsigned int dwTlsIndex) {
// DEBUG_LOG("TlsGetValue(%u)", dwTlsIndex); VERBOSE_LOG("TlsGetValue(%u)\n", dwTlsIndex);
void *result = nullptr; void *result = nullptr;
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) { if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
result = tlsValues[dwTlsIndex]; result = tlsValues[dwTlsIndex];
@ -1016,7 +1023,7 @@ namespace kernel32 {
} }
unsigned int WIN_FUNC TlsSetValue(unsigned int dwTlsIndex, void *lpTlsValue) { unsigned int WIN_FUNC TlsSetValue(unsigned int dwTlsIndex, void *lpTlsValue) {
// DEBUG_LOG("TlsSetValue(%u, %p)\n", dwTlsIndex, lpTlsValue); VERBOSE_LOG("TlsSetValue(%u, %p)\n", dwTlsIndex, lpTlsValue);
if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) { if (dwTlsIndex >= 0 && dwTlsIndex < MAX_TLS_VALUES && tlsValuesUsed[dwTlsIndex]) {
tlsValues[dwTlsIndex] = lpTlsValue; tlsValues[dwTlsIndex] = lpTlsValue;
return 1; return 1;
@ -1030,7 +1037,7 @@ namespace kernel32 {
* Memory * Memory
*/ */
void *WIN_FUNC GlobalAlloc(uint32_t uFlags, size_t dwBytes) { void *WIN_FUNC GlobalAlloc(uint32_t uFlags, size_t dwBytes) {
// DEBUG_LOG("GlobalAlloc(flags=%x, size=%x)\n", uFlags, dwBytes); VERBOSE_LOG("GlobalAlloc(%x, %zu)\n", uFlags, dwBytes);
if (uFlags & 2) { if (uFlags & 2) {
// GMEM_MOVEABLE - not implemented rn // GMEM_MOVEABLE - not implemented rn
assert(0); assert(0);
@ -1042,11 +1049,13 @@ namespace kernel32 {
} }
} }
void *WIN_FUNC GlobalFree(void *hMem) { void *WIN_FUNC GlobalFree(void *hMem) {
VERBOSE_LOG("GlobalFree(%p)\n", hMem);
free(hMem); free(hMem);
return 0; return 0;
} }
void *WIN_FUNC GlobalReAlloc(void *hMem, size_t dwBytes, uint32_t uFlags) { void *WIN_FUNC GlobalReAlloc(void *hMem, size_t dwBytes, uint32_t uFlags) {
VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, dwBytes, uFlags);
if (uFlags & 0x80) { // GMEM_MODIFY if (uFlags & 0x80) { // GMEM_MODIFY
assert(0); assert(0);
} else { } else {
@ -1056,6 +1065,7 @@ namespace kernel32 {
} }
unsigned int WIN_FUNC GlobalFlags(void *hMem) { unsigned int WIN_FUNC GlobalFlags(void *hMem) {
VERBOSE_LOG("GlobalFlags(%p)\n", hMem);
return 0; return 0;
} }
@ -1063,7 +1073,7 @@ namespace kernel32 {
constexpr uint32_t LMEM_ZEROINIT = 0x0040; constexpr uint32_t LMEM_ZEROINIT = 0x0040;
void *WIN_FUNC LocalAlloc(uint32_t uFlags, size_t uBytes) { void *WIN_FUNC LocalAlloc(uint32_t uFlags, size_t uBytes) {
DEBUG_LOG("LocalAlloc(flags=%x, size=%zu)\n", uFlags, uBytes); VERBOSE_LOG("LocalAlloc(%x, %zu)\n", uFlags, uBytes);
bool zero = (uFlags & LMEM_ZEROINIT) != 0; bool zero = (uFlags & LMEM_ZEROINIT) != 0;
if ((uFlags & LMEM_MOVEABLE) != 0) { if ((uFlags & LMEM_MOVEABLE) != 0) {
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n"); DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
@ -1080,6 +1090,7 @@ namespace kernel32 {
} }
void *WIN_FUNC LocalFree(void *hMem) { void *WIN_FUNC LocalFree(void *hMem) {
VERBOSE_LOG("LocalFree(%p)\n", hMem);
// Windows returns NULL on success. // Windows returns NULL on success.
free(hMem); free(hMem);
wibo::lastError = ERROR_SUCCESS; wibo::lastError = ERROR_SUCCESS;
@ -1087,7 +1098,7 @@ namespace kernel32 {
} }
void *WIN_FUNC LocalReAlloc(void *hMem, size_t uBytes, uint32_t uFlags) { void *WIN_FUNC LocalReAlloc(void *hMem, size_t uBytes, uint32_t uFlags) {
DEBUG_LOG("LocalReAlloc(%p, size=%zu, flags=%x)\n", hMem, uBytes, uFlags); VERBOSE_LOG("LocalReAlloc(%p, %zu, %x)\n", hMem, uBytes, uFlags);
bool zero = (uFlags & LMEM_ZEROINIT) != 0; bool zero = (uFlags & LMEM_ZEROINIT) != 0;
if ((uFlags & LMEM_MOVEABLE) != 0) { if ((uFlags & LMEM_MOVEABLE) != 0) {
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n"); DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
@ -1104,25 +1115,30 @@ namespace kernel32 {
} }
void *WIN_FUNC LocalHandle(void *hMem) { void *WIN_FUNC LocalHandle(void *hMem) {
VERBOSE_LOG("LocalHandle(%p)\n", hMem);
return hMem; return hMem;
} }
void *WIN_FUNC LocalLock(void *hMem) { void *WIN_FUNC LocalLock(void *hMem) {
VERBOSE_LOG("LocalLock(%p)\n", hMem);
wibo::lastError = ERROR_SUCCESS; wibo::lastError = ERROR_SUCCESS;
return hMem; return hMem;
} }
unsigned int WIN_FUNC LocalUnlock(void *hMem) { unsigned int WIN_FUNC LocalUnlock(void *hMem) {
VERBOSE_LOG("LocalUnlock(%p)\n", hMem);
(void)hMem; (void)hMem;
wibo::lastError = ERROR_SUCCESS; wibo::lastError = ERROR_SUCCESS;
return 1; return 1;
} }
size_t WIN_FUNC LocalSize(void *hMem) { size_t WIN_FUNC LocalSize(void *hMem) {
VERBOSE_LOG("LocalSize(%p)\n", hMem);
return hMem ? mi_usable_size(hMem) : 0; return hMem ? mi_usable_size(hMem) : 0;
} }
unsigned int WIN_FUNC LocalFlags(void *hMem) { unsigned int WIN_FUNC LocalFlags(void *hMem) {
VERBOSE_LOG("LocalFlags(%p)\n", hMem);
(void)hMem; (void)hMem;
return 0; return 0;
} }
@ -1131,17 +1147,17 @@ namespace kernel32 {
* Environment * Environment
*/ */
LPSTR WIN_FUNC GetCommandLineA() { LPSTR WIN_FUNC GetCommandLineA() {
DEBUG_LOG("GetCommandLineA\n"); DEBUG_LOG("GetCommandLineA() -> %s\n", wibo::commandLine.c_str());
return const_cast<LPSTR>(wibo::commandLine.c_str()); return const_cast<LPSTR>(wibo::commandLine.c_str());
} }
LPWSTR WIN_FUNC GetCommandLineW() { LPWSTR WIN_FUNC GetCommandLineW() {
DEBUG_LOG("GetCommandLineW -> \n"); DEBUG_LOG("GetCommandLineW() -> %s\n", wideStringToString(wibo::commandLineW.data()).c_str());
return wibo::commandLineW.data(); return wibo::commandLineW.data();
} }
char *WIN_FUNC GetEnvironmentStrings() { char *WIN_FUNC GetEnvironmentStrings() {
DEBUG_LOG("GetEnvironmentStrings\n"); DEBUG_LOG("GetEnvironmentStrings()\n");
// Step 1, figure out the size of the buffer we need. // Step 1, figure out the size of the buffer we need.
size_t bufSize = 0; size_t bufSize = 0;
char **work = environ; char **work = environ;
@ -1170,7 +1186,7 @@ namespace kernel32 {
} }
uint16_t* WIN_FUNC GetEnvironmentStringsW() { uint16_t* WIN_FUNC GetEnvironmentStringsW() {
DEBUG_LOG("GetEnvironmentStringsW\n"); DEBUG_LOG("GetEnvironmentStringsW()\n");
// Step 1, figure out the size of the buffer we need. // Step 1, figure out the size of the buffer we need.
size_t bufSizeW = 0; size_t bufSizeW = 0;
char **work = environ; char **work = environ;
@ -1201,7 +1217,7 @@ namespace kernel32 {
} }
void WIN_FUNC FreeEnvironmentStringsA(char *buffer) { void WIN_FUNC FreeEnvironmentStringsA(char *buffer) {
DEBUG_LOG("FreeEnvironmentStringsA\n"); DEBUG_LOG("FreeEnvironmentStringsA(%p)\n", buffer);
free(buffer); free(buffer);
} }
@ -1209,17 +1225,25 @@ namespace kernel32 {
* I/O * I/O
*/ */
void *WIN_FUNC GetStdHandle(uint32_t nStdHandle) { void *WIN_FUNC GetStdHandle(uint32_t nStdHandle) {
DEBUG_LOG("GetStdHandle %d\n", nStdHandle); DEBUG_LOG("GetStdHandle(%d)\n", nStdHandle);
return files::getStdHandle(nStdHandle); return files::getStdHandle(nStdHandle);
} }
unsigned int WIN_FUNC SetStdHandle(uint32_t nStdHandle, void *hHandle) { unsigned int WIN_FUNC SetStdHandle(uint32_t nStdHandle, void *hHandle) {
DEBUG_LOG("SetStdHandle %d %p\n", nStdHandle, hHandle); DEBUG_LOG("SetStdHandle(%d, %p)\n", nStdHandle, hHandle);
return files::setStdHandle(nStdHandle, hHandle); return files::setStdHandle(nStdHandle, hHandle);
} }
unsigned int WIN_FUNC DuplicateHandle(void *hSourceProcessHandle, void *hSourceHandle, void *hTargetProcessHandle, void **lpTargetHandle, unsigned int dwDesiredAccess, unsigned int bInheritHandle, unsigned int dwOptions) { unsigned int WIN_FUNC DuplicateHandle(void *hSourceProcessHandle, void *hSourceHandle, void *hTargetProcessHandle,
DEBUG_LOG("DuplicateHandle(source=%p)\n", hSourceHandle); void **lpTargetHandle, unsigned int dwDesiredAccess,
unsigned int bInheritHandle, unsigned int dwOptions) {
DEBUG_LOG("DuplicateHandle(%p, %p, %p, %p, %x, %d, %x)\n", hSourceProcessHandle, hSourceHandle,
hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
assert(hSourceProcessHandle == (void *)0xFFFFFFFF); // current process
assert(hTargetProcessHandle == (void *)0xFFFFFFFF); // current process
(void)dwDesiredAccess;
(void)bInheritHandle;
(void)dwOptions;
FILE *fp = files::fpFromHandle(hSourceHandle); FILE *fp = files::fpFromHandle(hSourceHandle);
if (fp == stdin || fp == stdout || fp == stderr) { if (fp == stdin || fp == stdout || fp == stderr) {
// we never close standard handles so they are fine to duplicate // we never close standard handles so they are fine to duplicate