Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using _try/_except at DISPATCH_LEVEL IRQL

1 view
Skip to first unread message

Gary Nebbett

unread,
Aug 28, 1999, 3:00:00 AM8/28/99
to
James Antognini <anto...@us.ibm.com> wrote in message news:37C6E306...@us.ibm.com...
> As a general matter, does _try/_except work when IRQL is at DISPATCH_LEVEL? I'm
> aware that there is an ill-defined class of known exceptions; for example,
> reference to address 0 or, I think, to any virtual address not backed by real
> storage (I believe the latter falls under the rubric of "page fault").
>
> What I'm trying is to cause a divide-by-zero exception at IRQL=2. I always get a
> page fault (as reported by SoftICE or by the kernel debugger). My exception
> handler is not entered, so far as I can tell (eg, a DbgPrint statement isn't
> executed). I cannot figure out what causes the page fault. But, assuming that I
> did and fixed that, should I expect my exception handler to get control?

_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

James Antognini

unread,
Aug 30, 1999, 3:00:00 AM8/30/99
to
Here's what I've learned so far:

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

Gary Nebbett

unread,
Aug 31, 1999, 3:00:00 AM8/31/99
to
James Antognini <anto...@us.ibm.com> wrote in message news:37CAD344...@us.ibm.com...

> Here's what I've learned so far:
>
> The page fault occurs (according to SoftICE) in ntoskrnl!KeRestoreFloatingPointState, at offset
0x0C8B, which is this instruction:
>
> mov cl, [eax]

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

James Antognini

unread,
Aug 31, 1999, 3:00:00 AM8/31/99
to
Oops...

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?

Gary Nebbett

unread,
Sep 1, 1999, 3:00:00 AM9/1/99
to
James Antognini <anto...@us.ibm.com> wrote in message news:37CBFC6F...@us.ibm.com...

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


James Antognini

unread,
Sep 1, 1999, 3:00:00 AM9/1/99
to
I don't follow. First, 'gn' isn't accepted, apparently because the target machine isn't in thread context. 'g' causes
BSOD to appear on the target's display. Second, "over-cautious"? Sorry, I cannot get _try/_except to work for
divide-by-0 with IRQL=2. Can you? Try this:

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.

Gary Nebbett

unread,
Sep 2, 1999, 3:00:00 AM9/2/99
to
Sorry, I forgot that the access violation caused by the
probe of the faulting
instruction would generate an IRQL_NOT_LESS_OR_EQUAL
bugcheck when running at
an elevated IRQL. This does indeed mean that divide-by-zero
faults cannot be
trapped by the exception handling mechanism when running at
DISPATCH_LEVEL.

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 Nebbett

unread,
Sep 2, 1999, 3:00:00 AM9/2/99
to
The attached program shows which exceptions can and cannot
be caught. The two
exceptions marked IRQL_NOT_LESS_OR_EQUAL can be caught if
IRQL <
DISPATCH_LEVEL, but the exception marked
UNEXPECTED_KERNEL_MODE_TRAP always
causes a bugcheck.

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);

Gary Nebbett

unread,
Sep 3, 1999, 3:00:00 AM9/3/99
to
Here is a final update on using __try/__except at DISPATCH_LEVEL IRQL. The driver built from the
following code, when loaded, produces the output:

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",

James Antognini

unread,
Sep 3, 1999, 3:00:00 AM9/3/99
to
OK, I tried this myself. Now I believe it really is possible to capture some errors at IRQL=2. Thanks.
0 new messages