implement user mode catchable exceptions, refactor system status codes to use NTLSTATUS_ prefix, update build scripts to use shared literal macros for linker arguments, update named queue lifetime cleanup to include KeNamedQueueUnpublishHandle.

This commit is contained in:
maksw committed 2026-06-27 20:38:43 +02:00
1 parent 1f5477cf66
commit b7fcfce6f7
140 files changed
+7649 -3943

No files matched your search

@@ -0,0 +1,151 @@
// Native exception runtime smoke test. This file verifies process-start registration and handler dispatch.
#include <stdint.h>
#include <stddef.h>
#include <ntlite/exception.h>
#include <ntlite/syscall.h>
static volatile uint32_t gSearchHits;
static volatile uint32_t gContinueHits;
// Prints one NUL-terminated string to the kernel console.
static void print(const char* s) {
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
SysWriteConsole(&req);
}
// Prints one unsigned integer.
static void print_u64(uint64_t v) {
char buf[32];
int i = 0;
if (v == 0) {
print("0");
return;
}
while (v && i < (int)sizeof(buf)) {
buf[i++] = (char)('0' + (v % 10));
v /= 10;
}
while (i--) {
char c = buf[i];
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
SysWriteConsole(&req);
}
}
// Terminates the current process.
static void exit_now(int32_t code) {
for (;;) SysExitProcess(code);
}
// Fails the test with one message.
static void fail(const char* message) {
print("native_exception_runtime_smoke: ");
print(message);
print("\n");
exit_now(1);
}
// Fails the test with one status value.
static void fail_status(const char* what, uint32_t status) {
print("native_exception_runtime_smoke: ");
print(what);
print(" status=");
print_u64(status);
print("\n");
exit_now(1);
}
// Requires one syscall to return the expected status.
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
if (got != expected) {
print("native_exception_runtime_smoke: ");
print(what);
print(" expected=");
print_u64(expected);
print(" got=");
print_u64(got);
print("\n");
exit_now(1);
}
}
// Verifies the native runtime installed the process dispatcher during startup.
static void verify_startup_registration(void) {
SYS_EXCEPTION_DISPATCHER_REQUEST request;
for (size_t i = 0; i < sizeof(request); i++)
((char*)&request)[i] = 0;
request.Size = sizeof(request);
uint32_t status = SysGetExceptionDispatcher(&request);
if (status != NTLSTATUS_SUCCESS)
fail_status("get dispatcher", status);
if (!request.DispatcherRoutine)
fail("runtime dispatcher was not registered");
}
// Verifies one breakpoint exception record has the expected native shape.
static void verify_breakpoint_record(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context) {
if (!record || !context)
fail("handler received null state");
if (record->Size != sizeof(*record) || record->Version != SYS_EXCEPTION_ABI_VERSION)
fail("record ABI mismatch");
if (context->Size != sizeof(*context) || context->Version != SYS_EXCEPTION_ABI_VERSION)
fail("context ABI mismatch");
if (record->Code != SYS_EXCEPTION_CODE_BREAKPOINT)
fail("unexpected exception code");
}
// Records a first-chance exception and asks the dispatcher to continue searching.
static int search_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
if (userContext != (void*)(uintptr_t)0x1111)
fail("search handler context mismatch");
verify_breakpoint_record(record, context);
gSearchHits++;
return NTL_EXCEPTION_CONTINUE_SEARCH;
}
// Records a first-chance exception and asks the kernel to resume the saved context.
static int continue_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
if (userContext != (void*)(uintptr_t)0x2222)
fail("continue handler context mismatch");
verify_breakpoint_record(record, context);
gContinueHits++;
return NTL_EXCEPTION_CONTINUE_EXECUTION;
}
// Verifies the process-local handler list can dispatch and remove handlers.
static void verify_handler_dispatch(void) {
expect_status("remove null", NtlRemoveExceptionHandler(0), NTLSTATUS_INVALID_PARAMETER);
if (NtlAddExceptionHandler(0, 0, 0))
fail("null handler was accepted");
void* search = NtlAddExceptionHandler(0, search_handler, (void*)(uintptr_t)0x1111);
void* cont = NtlAddExceptionHandler(0, continue_handler, (void*)(uintptr_t)0x2222);
if (!search || !cont)
fail("handler registration failed");
__debugbreak();
if (gSearchHits != 1 || gContinueHits != 1)
fail("breakpoint did not visit both handlers");
expect_status("remove search", NtlRemoveExceptionHandler(search), NTLSTATUS_SUCCESS);
__debugbreak();
if (gSearchHits != 1 || gContinueHits != 2)
fail("removed handler still participated");
expect_status("remove continue", NtlRemoveExceptionHandler(cont), NTLSTATUS_SUCCESS);
expect_status("remove continue twice", NtlRemoveExceptionHandler(cont), NTLSTATUS_NOT_FOUND);
}
// Runs the native exception runtime smoke test.
int main(void) {
print("native_exception_runtime_smoke: start\n");
verify_startup_registration();
verify_handler_dispatch();
print("native_exception_runtime_smoke: PASS\n");
exit_now(0);
return 0;
}