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:
1 parent
1f5477cf66
commit
b7fcfce6f7
140 files changed
+7649
-3943
No files matched your search
+95
-156
@@ -8,6 +8,7 @@
|
||||
#include <kernel/hal/hal_apic.h>
|
||||
#include <intrin.h>
|
||||
#include <kernel/ke_debug.h>
|
||||
#include <kernel/ke_exception.h>
|
||||
#include <kernel/ke_cpu.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_process.h>
|
||||
@@ -220,12 +221,12 @@ __declspec(dllexport) void DbgPrint(const char* fmt, ...) {
|
||||
// Flushes debug Log To File.
|
||||
__declspec(dllexport) KSTATUS KeFlushDebugLogToFile(SYS_STRING_VIEW path) {
|
||||
if (!gDebugLogBuffer || gDebugLogSize == 0 || !SysSvIsValid(path) || path.Length == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (!KeCanWait())
|
||||
return STATUS_INVALID_IRQL;
|
||||
return NTLSTATUS_INVALID_IRQL;
|
||||
|
||||
if (_InterlockedCompareExchange((volatile long*)&gDebugLogFlushing, 1, 0) != 0)
|
||||
return STATUS_PENDING;
|
||||
return NTLSTATUS_PENDING;
|
||||
|
||||
size_t used;
|
||||
size_t start;
|
||||
@@ -236,7 +237,7 @@ __declspec(dllexport) KSTATUS KeFlushDebugLogToFile(SYS_STRING_VIEW path) {
|
||||
|
||||
if (used == 0) {
|
||||
_InterlockedExchange((volatile long*)&gDebugLogFlushing, 0);
|
||||
return STATUS_SUCCESS;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
(void)IoDeleteFile(path);
|
||||
@@ -264,7 +265,7 @@ __declspec(dllexport) KSTATUS KeFlushDebugLogToFile(SYS_STRING_VIEW path) {
|
||||
IoCloseFile(file);
|
||||
|
||||
_InterlockedExchange((volatile long*)&gDebugLogFlushing, 0);
|
||||
return (KSUCCESS(st) && totalWritten == used) ? STATUS_SUCCESS : st;
|
||||
return (KSUCCESS(st) && totalWritten == used) ? NTLSTATUS_SUCCESS : st;
|
||||
}
|
||||
|
||||
// Attempts to persist the debug log during a panic when the filesystem is usable.
|
||||
@@ -348,73 +349,6 @@ static void KiFaultPrintf(const char* format, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// KeBugCheckProcess - user-mode fault handler
|
||||
|
||||
// Resolves the faulting RIP to a module name, prints a yellow crash banner,
|
||||
// kills the offending process, then exits the current thread so the scheduler
|
||||
// can continue running everything else.
|
||||
|
||||
// Return the short exception name for a CPU exception vector.
|
||||
// Keep this table complete for vectors 0..31 so faults never collapse into
|
||||
// a vague "general protection" bucket just because the IDT entry existed
|
||||
// first or the crash printer lacked a name.
|
||||
static const char* KiFaultVectorName(int vector) {
|
||||
switch (vector) {
|
||||
case 0: return "#DE Divide Error";
|
||||
case 1: return "#DB Debug";
|
||||
case 2: return "NMI Interrupt";
|
||||
case 3: return "#BP Breakpoint";
|
||||
case 4: return "#OF Overflow";
|
||||
case 5: return "#BR Bound Range Exceeded";
|
||||
case 6: return "#UD Invalid Opcode";
|
||||
case 7: return "#NM Device Not Available";
|
||||
case 8: return "#DF Double Fault";
|
||||
case 9: return "Coprocessor Segment Overrun";
|
||||
case 10: return "#TS Invalid TSS";
|
||||
case 11: return "#NP Segment Not Present";
|
||||
case 12: return "#SS Stack-Segment Fault";
|
||||
case 13: return "#GP General Protection";
|
||||
case 14: return "#PF Page Fault";
|
||||
case 15: return "Reserved Exception 15";
|
||||
case 16: return "#MF x87 Floating-Point Exception";
|
||||
case 17: return "#AC Alignment Check";
|
||||
case 18: return "#MC Machine Check";
|
||||
case 19: return "#XM SIMD Floating-Point Exception";
|
||||
case 20: return "#VE Virtualization Exception";
|
||||
case 21: return "#CP Control Protection Exception";
|
||||
case 22: return "Reserved Exception 22";
|
||||
case 23: return "Reserved Exception 23";
|
||||
case 24: return "Reserved Exception 24";
|
||||
case 25: return "Reserved Exception 25";
|
||||
case 26: return "Reserved Exception 26";
|
||||
case 27: return "Reserved Exception 27";
|
||||
case 28: return "#HV Hypervisor Injection Exception";
|
||||
case 29: return "#VC VMM Communication Exception";
|
||||
case 30: return "#SX Security Exception";
|
||||
case 31: return "Reserved Exception 31";
|
||||
default: return "Unknown Exception";
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the fault Has Error Code operation.
|
||||
static int KiFaultHasErrorCode(int vector) {
|
||||
switch (vector) {
|
||||
case 8: // #DF
|
||||
case 10: // #TS
|
||||
case 11: // #NP
|
||||
case 12: // #SS
|
||||
case 13: // #GP
|
||||
case 14: // #PF
|
||||
case 17: // #AC
|
||||
case 21: // #CP
|
||||
case 29: // #VC
|
||||
case 30: // #SX
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk the process module list to find which image owns an address.
|
||||
// Returns the module name string, or "unknown" if the address is outside all
|
||||
// known image ranges. Base/size are optional and are useful for offset dumps.
|
||||
@@ -703,21 +637,9 @@ static void KiDumpFaultFrame(PROCESS* proc, const KFAULT_FRAME* f) {
|
||||
KiDumpUserStack(proc, (uintptr_t)f->Rsp);
|
||||
}
|
||||
|
||||
static KSTATUS KiFaultExitStatus(int vector) {
|
||||
switch (vector) {
|
||||
case 0: return STATUS_PROCESS_DIVIDE_BY_ZERO;
|
||||
case 3: return STATUS_PROCESS_BREAKPOINT;
|
||||
case 6: return STATUS_PROCESS_ILLEGAL_OPCODE;
|
||||
case 13: return STATUS_PROCESS_GENERAL_PROTECTION;
|
||||
case 14: return STATUS_PROCESS_PAGE_FAULT;
|
||||
case 17: return STATUS_PROCESS_ALIGNMENT_FAULT;
|
||||
default: return STATUS_PROCESS_UNKNOWN_FAULT;
|
||||
}
|
||||
}
|
||||
|
||||
static void KiPrintCrashHeader(PROCESS* proc, int vector, uintptr_t rip,
|
||||
uintptr_t errCode, uintptr_t cr2) {
|
||||
const char* faultName = KiFaultVectorName(vector);
|
||||
const char* faultName = KeExceptionVectorName((uint32_t)vector);
|
||||
const char* procName = proc ? proc->Name : "unknown";
|
||||
uint32_t pid = proc ? proc->ProcessId : 0;
|
||||
const char* modName = proc ? KiResolveModule(proc, rip) : "unknown";
|
||||
@@ -768,11 +690,79 @@ _Noreturn void KeBugCheckProcess(int vector, uintptr_t rip, uintptr_t errCode, u
|
||||
KiPrintCrashHeader(proc, vector, rip, errCode, cr2);
|
||||
KiDumpModules(proc);
|
||||
|
||||
KiFinishFaultedProcess(proc, thread, KiFaultExitStatus(vector));
|
||||
KiFinishFaultedProcess(proc, thread, KeExceptionProcessExitStatus((uint32_t)vector));
|
||||
}
|
||||
|
||||
// Dispatches a CPU fault frame and returns only when a user #PF was repaired.
|
||||
__declspec(dllexport) KSTATUS KeFaultDispatchFrame(const KFAULT_FRAME* frame) {
|
||||
// Panics after printing a kernel-mode CPU exception report.
|
||||
static _Noreturn void KiPanicKernelFault(PROCESS* proc, THREAD* thread, const KFAULT_FRAME* frame) {
|
||||
KiBeginFatalReport();
|
||||
|
||||
int vector = (int)frame->Vector;
|
||||
const char* name = KeExceptionVectorName((uint32_t)vector);
|
||||
|
||||
DbgPrint("FAULT: kernel exception vector=%d name=%s rip=%016llx rsp=%016llx err=%04llx cr2=%016llx thread=0x%016llX pid=%u proc=%s\n",
|
||||
vector,
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Rsp,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cr2,
|
||||
thread,
|
||||
proc ? proc->ProcessId : 0,
|
||||
proc ? proc->Name : "<none>");
|
||||
KiDumpFaultFrame(proc, frame);
|
||||
if (vector == 14) {
|
||||
MmDebugDescribeAddress((uintptr_t)frame->Cr2);
|
||||
if (frame->Rip) MmDebugDescribeAddress((uintptr_t)frame->Rip);
|
||||
if (frame->Rsp) MmDebugDescribeAddress((uintptr_t)frame->Rsp);
|
||||
MmVadDebugDumpProcess(proc);
|
||||
}
|
||||
|
||||
if (vector == 14) {
|
||||
KePanic(KE_PANIC_CODE_FAULT, "PANIC: %s | RIP: %016llx | RSP: %016llx | Code: %04llx | CR2: %016llx\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Rsp,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cr2);
|
||||
} else if (KeExceptionVectorHasErrorCode((uint32_t)vector)) {
|
||||
const uint8_t* ip = (const uint8_t*)(uintptr_t)frame->Rip;
|
||||
KePanic(KE_PANIC_CODE_FAULT,
|
||||
"PANIC: %s | RIP: %016llx | Code: %04llx | CS=%04llx RFLAGS=%016llx RSP=%016llx | bytes=%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cs,
|
||||
(unsigned long long)frame->Rflags,
|
||||
(unsigned long long)frame->Rsp,
|
||||
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
|
||||
} else {
|
||||
const uint8_t* ip = (const uint8_t*)(uintptr_t)frame->Rip;
|
||||
KePanic(KE_PANIC_CODE_FAULT,
|
||||
"PANIC: %s | RIP: %016llx | CS=%04llx RFLAGS=%016llx RSP=%016llx | bytes=%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Cs,
|
||||
(unsigned long long)frame->Rflags,
|
||||
(unsigned long long)frame->Rsp,
|
||||
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
|
||||
}
|
||||
}
|
||||
|
||||
// Terminates the current process after printing an unhandled user exception report.
|
||||
static _Noreturn void KiTerminateUserFault(PROCESS* proc, THREAD* thread, const KFAULT_FRAME* frame) {
|
||||
KiPrintCrashHeader(proc, (int)frame->Vector,
|
||||
(uintptr_t)frame->Rip,
|
||||
(uintptr_t)frame->ErrorCode,
|
||||
(uintptr_t)frame->Cr2);
|
||||
KiDumpFaultFrame(proc, frame);
|
||||
KiDumpModules(proc);
|
||||
|
||||
KiFinishFaultedProcess(proc, thread, KeExceptionProcessExitStatus((uint32_t)frame->Vector));
|
||||
}
|
||||
|
||||
// Dispatches a CPU fault frame and returns only when a page fault was repaired.
|
||||
__declspec(dllexport) KSTATUS KeFaultDispatchFrame(KFAULT_FRAME* frame) {
|
||||
// Panic NMIs are broadcast to stop all other CPUs. Do not try to decode
|
||||
// the interrupted context on a secondary CPU once another CPU owns panic.
|
||||
if (KiPanicIsActive())
|
||||
@@ -781,93 +771,42 @@ __declspec(dllexport) KSTATUS KeFaultDispatchFrame(const KFAULT_FRAME* frame) {
|
||||
THREAD* thread = KeGetCurrentThread();
|
||||
PROCESS* proc = thread ? thread->Owner : (PROCESS*)0;
|
||||
|
||||
if (!frame || frame->Magic != 0x3146544C5541464BULL) {
|
||||
if (!KeFaultFrameIsValid(frame)) {
|
||||
KePanic(KE_PANIC_CODE_FAULT, "PANIC: bad KFAULT_FRAME %016llx\n",
|
||||
(unsigned long long)(uintptr_t)frame);
|
||||
}
|
||||
|
||||
if (frame->Vector == 14) {
|
||||
KSTATUS handled = MmVadResolvePageFaultByAddress((uintptr_t)frame->Cr2, frame->ErrorCode);
|
||||
if (KSUCCESS(handled))
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
KSTATUS repaired = KeExceptionResolveRecoverableFault(frame);
|
||||
if (KSUCCESS(repaired))
|
||||
return NTLSTATUS_SUCCESS;
|
||||
|
||||
if ((frame->Cs & 3) == 0) {
|
||||
KiBeginFatalReport();
|
||||
if (!KeFaultFrameFromUser(frame))
|
||||
KiPanicKernelFault(proc, thread, frame);
|
||||
|
||||
int vector = (int)frame->Vector;
|
||||
const char* name = KiFaultVectorName(vector);
|
||||
KSTATUS delivered = KeDeliverUserException(frame);
|
||||
if (KSUCCESS(delivered))
|
||||
return NTLSTATUS_SUCCESS;
|
||||
|
||||
DbgPrint("FAULT: kernel exception vector=%d name=%s rip=%016llx rsp=%016llx err=%04llx cr2=%016llx thread=%p pid=%u proc=%s\n",
|
||||
vector,
|
||||
name,
|
||||
if (delivered != NTLSTATUS_NOT_FOUND)
|
||||
DbgPrint("USER/EXC: delivery failed vector=%llu rip=%016llx rsp=%016llx status=%u\n",
|
||||
frame->Vector,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Rsp,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cr2,
|
||||
thread,
|
||||
proc ? proc->ProcessId : 0,
|
||||
proc ? proc->Name : "<none>");
|
||||
KiDumpFaultFrame(proc, frame);
|
||||
if (vector == 14) {
|
||||
MmDebugDescribeAddress((uintptr_t)frame->Cr2);
|
||||
if (frame->Rip) MmDebugDescribeAddress((uintptr_t)frame->Rip);
|
||||
if (frame->Rsp) MmDebugDescribeAddress((uintptr_t)frame->Rsp);
|
||||
MmVadDebugDumpProcess(proc);
|
||||
}
|
||||
delivered);
|
||||
|
||||
if (vector == 14) {
|
||||
KePanic(KE_PANIC_CODE_FAULT, "PANIC: %s | RIP: %016llx | RSP: %016llx | Code: %04llx | CR2: %016llx\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Rsp,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cr2);
|
||||
} else if (KiFaultHasErrorCode(vector)) {
|
||||
const uint8_t* ip = (const uint8_t*)(uintptr_t)frame->Rip;
|
||||
KePanic(KE_PANIC_CODE_FAULT,
|
||||
"PANIC: %s | RIP: %016llx | Code: %04llx | CS=%04llx RFLAGS=%016llx RSP=%016llx | bytes=%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->ErrorCode,
|
||||
(unsigned long long)frame->Cs,
|
||||
(unsigned long long)frame->Rflags,
|
||||
(unsigned long long)frame->Rsp,
|
||||
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
|
||||
} else {
|
||||
const uint8_t* ip = (const uint8_t*)(uintptr_t)frame->Rip;
|
||||
KePanic(KE_PANIC_CODE_FAULT,
|
||||
"PANIC: %s | RIP: %016llx | CS=%04llx RFLAGS=%016llx RSP=%016llx | bytes=%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
name,
|
||||
(unsigned long long)frame->Rip,
|
||||
(unsigned long long)frame->Cs,
|
||||
(unsigned long long)frame->Rflags,
|
||||
(unsigned long long)frame->Rsp,
|
||||
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
|
||||
}
|
||||
}
|
||||
|
||||
KiPrintCrashHeader(proc, (int)frame->Vector,
|
||||
(uintptr_t)frame->Rip,
|
||||
(uintptr_t)frame->ErrorCode,
|
||||
(uintptr_t)frame->Cr2);
|
||||
KiDumpFaultFrame(proc, frame);
|
||||
KiDumpModules(proc);
|
||||
|
||||
KiFinishFaultedProcess(proc, thread, KiFaultExitStatus((int)frame->Vector));
|
||||
KiTerminateUserFault(proc, thread, frame);
|
||||
}
|
||||
|
||||
// KeFaultDispatch - single C entry point for all three IDT fault stubs.
|
||||
|
||||
// The asm stubs (ke_syscall.asm) collect the CPU exception frame values and
|
||||
// call here. We check the CS RPL to decide: kernel fault → panic and halt,
|
||||
// user fault → KeBugCheckProcess (kill process, resume scheduler).
|
||||
// The asm stubs collect the CPU exception frame values and call here.
|
||||
// KeFaultDispatchFrame owns the mode split and default unhandled policy.
|
||||
__declspec(dllexport) _Noreturn void KeFaultDispatch(int vector, uintptr_t rip,
|
||||
uintptr_t errCode, uintptr_t cr2,
|
||||
uintptr_t cs) {
|
||||
KFAULT_FRAME frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.Magic = 0x3146544C5541464BULL;
|
||||
frame.Magic = KFAULT_FRAME_MAGIC_VALUE;
|
||||
frame.Vector = (uint64_t)vector;
|
||||
frame.ErrorCode = errCode;
|
||||
frame.Cr2 = cr2;
|
||||
|
||||
Reference in new issue
Block a user