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,143 @@
// Native user-raised exception smoke test.
#include <stdint.h>
#include <stddef.h>
#include <ntlite/exception.h>
#include <ntlite/syscall.h>
#define SMOKE_EXCEPTION_CODE 0xE1111001u
static volatile uint32_t gHandlerHits;
// 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_raise_exception_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_raise_exception_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_raise_exception_smoke: ");
print(what);
print(" expected=");
print_u64(expected);
print(" got=");
print_u64(got);
print("\n");
exit_now(1);
}
}
// Reads aggregate exception counters.
static void query_exception_stats(SYS_EXCEPTION_STATS* out) {
uint32_t status = SysQueryKernelStats(SYS_KERNEL_STATS_EXCEPTION, out, sizeof(*out), 0);
expect_status("query exception stats", status, NTLSTATUS_SUCCESS);
if (out->Size != sizeof(*out) || out->Version != SYS_STATS_VERSION)
fail("exception stats ABI mismatch");
}
// Handles the user-raised exception and verifies its native record payload.
static int smoke_handler(SYS_EXCEPTION_RECORD* record, SYS_USER_CONTEXT* context, void* userContext) {
if (userContext != (void*)(uintptr_t)0x111E)
fail("handler context mismatch");
if (!record || !context)
fail("handler received null records");
if (record->Code != SMOKE_EXCEPTION_CODE)
fail("handler received wrong exception code");
if ((record->Flags & SYS_EXCEPTION_FLAG_FIRST_CHANCE) == 0)
fail("handler missing first-chance flag");
if (record->Flags & SYS_EXCEPTION_FLAG_NONCONTINUABLE)
fail("handler received unexpected noncontinuable flag");
if (record->ParameterCount != 2)
fail("handler received wrong parameter count");
if (record->Parameters[0] != 0x12345678u || record->Parameters[1] != 0xABCDEF00u)
fail("handler received wrong parameters");
if (!context->Rip || !context->Rsp)
fail("handler received empty context");
gHandlerHits++;
return NTL_EXCEPTION_CONTINUE_EXECUTION;
}
int main(void) {
print("native_raise_exception_smoke: start\n");
SYS_EXCEPTION_STATS before;
SYS_EXCEPTION_STATS after;
query_exception_stats(&before);
void* handle = NtlAddExceptionHandler(1, smoke_handler, (void*)(uintptr_t)0x111E);
if (!handle)
fail("failed to add native exception handler");
uint64_t args[2] = { 0x12345678u, 0xABCDEF00u };
SYS_RAISE_EXCEPTION_REQUEST request;
request.Size = sizeof(request);
request.Flags = SYS_RAISE_EXCEPTION_FLAG_NONE;
request.Code = SMOKE_EXCEPTION_CODE;
request.ParameterCount = 2;
request.Parameters = args;
uint32_t status = SysRaiseException(&request);
expect_status("raise exception", status, NTLSTATUS_SUCCESS);
if (gHandlerHits != 1)
fail("handler was not called exactly once");
status = NtlRemoveExceptionHandler(handle);
expect_status("remove native exception handler", status, NTLSTATUS_SUCCESS);
query_exception_stats(&after);
if (after.Delivered < before.Delivered + 1 ||
after.UserRaised < before.UserRaised + 1 ||
after.Continued < before.Continued + 1)
fail("exception counters did not advance");
if (after.LastCode != SMOKE_EXCEPTION_CODE)
fail("last exception code was not updated");
print("native_raise_exception_smoke: PASS\n");
exit_now(0);
return 0;
}