_try/_except does work at elevated IRQL and should even catch a reference to
address 0. It is only page faults in the "nonpaged area" which lead directly to a
bugcheck rather than an exception.
It is possible that your divide-by-zero code has been removed by the optimizer
because the result is not used, so the error that is trapped by SoftICE may be
occuring in another part of your driver.
Gary
The page fault occurs (according to SoftICE) in ntoskrnl!KeRestoreFloatingPointState, at offset 0x0C8B, which is this instruction:
mov cl, [eax]
but EAX=7FFF0000, which happens to be an invalid address (again, according to SoftICE). The value was loaded into EAX a few instructions before the
failing one, from ntoskrnl!MmUserProbeAddress. I am guessing that the latter is a data area, since it does not unassemble into valid instructions.
I've no idea why KeRestoreFloatingPointState would be called, since I am not (so far as I know) using any floating-point registers.
If I cause execution to proceed beginning at the instruction just after the failing instruction, my exception filter routine is entered, and then my
exception handler. Maybe that's just dumb luck, but it does suggest the page fault occurs before the exception filter gets control.
(By the way, this is the result of dividing by 0, since I can step up to the DIV instruction that fails. I cannot instruction-step beyond that, since
I get a BSOD with IRQL_NOT_LESS_OR_EQUAL. I must guess that that is due to some debugging interaction. The only way I can get a page fault, and see it
and still be running, is to "let 'er rip" at the failing DIV.)
--
James Antognini
IBM Watson Research
The routine KeRestoreFloatingPointState is much shorter than 0x0C8B bytes long. What build of NT are
you running, what is the actual address at the time of the access violation, and what does the call
stack (kb) look like?
Gary
I explicitly loaded symbols for NTOSKRNL.exe from NT 4 SP4 checked build. Now
SoftICE says the failure is in ntoskrnl!Ki386CheckDivideByZeroTrap+005F. The
failing address is 801c6375. The call stack is:
_Ki386CheckDivideByZeroTrap+005F, Kt0000+0021, CmdUrlPathDefine+0353 and so
forth. CmdUrlPathDefine is my module.
Now back to the real problem: I cannot get _try/_except to work at IRQL=2. Any
ideas?
Ki386CheckDivideByZeroTrap checks whether the divide error exception was caused by a divide by zero
or overflow condition and returns STATUS_INTEGER_DIVIDE_BY_ZERO or STATUS_INTEGER_OVERFLOW
accordingly. This value is used subsequently as the exception code. The determination of the cause
of the exception is made by examining the instruction which caused the exception and in order to
avoid the dreaded PAGE_FAULT_IN_NONPAGED_AREA bugcheck, the routine checks whether the instruction
is above or below MmUserProbeAddress. Ki386CheckDivideByZeroTrap preforms these checks inside an
exception handler of its own and if the handler is invoked then STATUS_INTEGER_DIVIDE_BY_ZERO is
returned.
If you continue from the access violation exception with gn (go non-handled) then the exception
handler of Ki386CheckDivideByZeroTrap will be invoked and your code will work as expected. I.e. what
you have been observing is normal and correct behaviour - you have just been over-cautious.
Gary
KeRaiseIrql(
DISPATCH_LEVEL,
&SaveIrql
);
_try
{
ULONG zits1 = 1, zits2 = 0;
zits1 = zits1/zits2;
}
_except(
pExceptionInfo = GetExceptionInformation (),
lclExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode,
lclExceptionAddr = pExceptionInfo->ExceptionRecord->ExceptionAddress,
EXCEPTION_EXECUTE_HANDLER
)
{
zits = 0;
}
KeLowerIrql(
SaveIrql
);
That is, tell me how to make things work so that the exception filter and then the exception handler get control.
However, the exception handling mechanism itself does work
at elevated
IRQL. I have attached a slightly modified version of your
code which
generates an invalid opcode exception rather than a divide
by zero
exception.
Gary
extern "C" {
#include <ntddk.h>
}
extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
{
PEXCEPTION_POINTERS Ep;
KIRQL SaveIrql;
ULONG zits;
KeRaiseIrql(DISPATCH_LEVEL, &SaveIrql);
__try {
ULONG zits1 = 1, zits2 = 0;
__asm _emit 0x0F __asm _emit 0x0B // ud2
zits = zits1 / zits2;
}
__except (Ep = GetExceptionInformation(),
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Ep->ExceptionRecord->ExceptionCode,
Ep->ExceptionRecord->ExceptionAddress);
zits = 0;
}
KeLowerIrql(SaveIrql);
return STATUS_UNSUCCESSFUL;
}
* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!
Gary
extern "C" {
#include <ntddk.h>
}
extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
{
EXCEPTION_RECORD Er;
CONTEXT Cr;
KIRQL SaveIrql;
KeRaiseIrql(DISPATCH_LEVEL, &SaveIrql);
__try {
// __asm xor ebx, ebx __asm div ebx //
IRQL_NOT_LESS_OR_EQUAL
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
__try {
__asm int 3
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
__try {
__asm mov al, 0x44 __asm add al, 0x44 __asm into
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
__try {
ULONG Bounds[] = {1, 2};
// __asm xor eax, eax __asm bound eax, Bounds //
UNEXPECTED_KERNEL_MODE_TRAP
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
__try {
__asm _emit 0x0F __asm _emit 0x0B // ud2
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
__try {
// __asm xor eax, eax __asm mov ebx, [eax] //
IRQL_NOT_LESS_OR_EQUAL
}
__except (Er = *(GetExceptionInformation())-
>ExceptionRecord,
Cr = *(GetExceptionInformation())-
>ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %
p\n",
Er.ExceptionCode, Er.ExceptionAddress);
0.00000 1 3 0 8.40 test.sys
0.00098 2 1 2 8.40 ExceptionCode = 80000004, ExceptionAddress = F931D3D9
0.00102 3 1 2 8.40 ExceptionCode = 80000003, ExceptionAddress = F931D426
0.00105 4 1 2 8.40 ExceptionCode = c0000095, ExceptionAddress = F931D478
0.00107 5 1 2 8.40 ExceptionCode = c000001d, ExceptionAddress = F931D527
0.00110 6 1 2 8.40 ExceptionCode = c0000002, ExceptionAddress = F931D6B5
0.00122 7 4 0 8.40 test.sys
Gary
extern "C" {
#include <ntddk.h>
}
extern "C" NTSTATUS
DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING)
{
EXCEPTION_RECORD Er;
CONTEXT Cr;
KIRQL SaveIrql;
KeRaiseIrql(DISPATCH_LEVEL, &SaveIrql);
// Interrupt 0 - Divide Error Exception - IRQL_NOT_LESS_OR_EQUAL
__try {
// __asm xor ebx, ebx __asm div ebx
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 1 - Debug Exception
__try {
__asm pushfd __asm or dword ptr [esp], 0x100 __asm popfd __asm xor eax, eax
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 2 - NMI Interrupt
// Interrupt 3 - Breakpoint Exception
__try {
__asm int 3
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 4 - Overflow Exception
__try {
__asm mov al, 0x44 __asm add al, 0x44 __asm into
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 5 - BOUND Range Exceeded Exception - UNEXPECTED_KERNEL_MODE_TRAP
__try {
ULONG Bounds[] = {1, 2};
// __asm xor eax, eax __asm bound eax, Bounds
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 6 - Invalid Opcode Exception
__try {
__asm _emit 0x0F __asm _emit 0x0B // ud2
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 7 - Device Not Available Exception
// Interrupt 8 - Double Fault Exception - UNEXPECTED_KERNEL_MODE_TRAP
__try {
// __asm mov ecx, 0x4000 __asm push es __asm _emit 0xe2 __asm _emit 0xfd
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 9 - CoProcessor Segment Overrun
// Interrupt 10 - Invalid TSS Exception
// Interrupt 11 - Segment Not Present
// Interrupt 12 - Stack Fault Exception
// Interrupt 13 - General Protection Exception - UNEXPECTED_KERNEL_MODE_TRAP
__try {
// __asm mov ax, 0x28 __asm mov gs, ax
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 14 - Page Fault Exception - IRQL_NOT_LESS_OR_EQUAL
__try {
// __asm xor eax, eax __asm mov ebx, [eax]
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 14 - Page Fault Exception - PAGE_FAULT_IN_NONPAGED_AREA
__try {
// __asm mov eax, 0xffff0000 __asm mov ebx, [eax]
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",
Er.ExceptionCode, Er.ExceptionAddress);
}
// Interrupt 16 - Floating-Point Error Exception
// Interrupt 17 - Alignment Check Exception
// Interrupt 18 - Machine Check Exception
// ExRaiseStatus - Docs say only call at PASSIVE_LEVEL, but seems safe if handler is invoked
__try {
ExRaiseStatus(STATUS_NOT_IMPLEMENTED);
}
__except (Er = *(GetExceptionInformation())->ExceptionRecord,
Cr = *(GetExceptionInformation())->ContextRecord,
EXCEPTION_EXECUTE_HANDLER) {
DbgPrint("ExceptionCode = %lx, ExceptionAddress = %p\n",