Exception Handling in Windows driver

Hi,

We found that in Windows drivers if an operation can cause an exception, we
must enclose it in try/except blocks. We are just curious to know if there
is any other mechanism through which one can tell the kernel that a
particular section of code might cause an exception. It will be very nice
if somebody can please tell us how the Windows kernel handles these
exceptions. For example, the Linux kernel maintains an exception table of
these PCs and the exception handler checks whether the exception occurred
in the kernel mode, and if so it checks if the PC is present in the
exception table or not.

Thanks,
Piyus

Effectively, only MmProbeAndLockPages and usermode pointer accesses can do this.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

“Piyus Kedia” wrote in message news:xxxxx@ntdev…
Hi,

We found that in Windows drivers if an operation can cause an exception, we must enclose it in try/except blocks. We are just curious to know if there is any other mechanism through which one can tell the kernel that a particular section of code might cause an exception. It will be very nice if somebody can please tell us how the Windows kernel handles these exceptions. For example, the Linux kernel maintains an exception table of these PCs and the exception handler checks whether the exception occurred in the kernel mode, and if so it checks if the PC is present in the exception table or not.

Thanks,
Piyus

There are only a couple of instances where you need an exception handler in a driver. It is a common mistake to try to use exception handling to mask/fix over bugs (like NULL deref) instead of fixing the actual bugs. What specific problem are you trying to solve?

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Piyus Kedia
Sent: Monday, August 26, 2013 4:02 AM
To: Windows System Software Devs Interest List
Cc: Sorav Bansal
Subject: [ntdev] Exception Handling in Windows driver

Hi,

We found that in Windows drivers if an operation can cause an exception, we must enclose it in try/except blocks. We are just curious to know if there is any other mechanism through which one can tell the kernel that a particular section of code might cause an exception. It will be very nice if somebody can please tell us how the Windows kernel handles these exceptions. For example, the Linux kernel maintains an exception table of these PCs and the exception handler checks whether the exception occurred in the kernel mode, and if so it checks if the PC is present in the exception table or not.

Thanks,
Piyus
— NTDEV is sponsored by OSR Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See http://www.osr.com/careers For our schedule of WDF, WDM, debugging and other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi Doron,

We are working on developing a dynamic binary translator for the kernel.
Towards this, we wanted to confirm if the interrupted PC value pushed on
stack by an interrupt/exception is used by the interrupt/exception
handlers? For example, is the PC value compared against a fixed address to
determine the handler behaviour (like Linux’s page fault handler compares
the faulting PC against an exception table, to allow functions like
copy_from_user to fault). We want to know that how exception in kernel is
handled in Windows. Does it maintain a table like Linux or simply set some
variable if there is fault in try/except blocks and doesn’t panic if the
variable is set?

Thanks,
Piyus

On Mon, Aug 26, 2013 at 8:43 PM, Doron Holan wrote:

> There are only a couple of instances where you need an exception handler
> in a driver. It is a common mistake to try to use exception handling to
> mask/fix over bugs (like NULL deref) instead of fixing the actual bugs.
> What specific problem are you trying to solve? **
>
>

>
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of Piyus Kedia
> Sent: Monday, August 26, 2013 4:02 AM
> To: Windows System Software Devs Interest List
> Cc: Sorav Bansal
> Subject: [ntdev] Exception Handling in Windows driver

>
> ****
>
> Hi,
>
> We found that in Windows drivers if an operation can cause an exception,
> we must enclose it in try/except blocks. We are just curious to know if
> there is any other mechanism through which one can tell the kernel that a
> particular section of code might cause an exception. It will be very nice
> if somebody can please tell us how the Windows kernel handles these
> exceptions. For example, the Linux kernel maintains an exception table of
> these PCs and the exception handler checks whether the exception occurred
> in the kernel mode, and if so it checks if the PC is present in the
> exception table or not.
>
> Thanks,
> Piyus
>
> — NTDEV is sponsored by OSR Visit the list at:
> http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
> http://www.osr.com/careers For our schedule of WDF, WDM, debugging and
> other seminars visit: http://www.osr.com/seminars To unsubscribe, visit
> the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> Hi Doron,

We are working on developing a dynamic binary translator for the kernel.
Towards this, we wanted to confirm if the interrupted PC value pushed on
stack by an interrupt/exception is used by the interrupt/exception
handlers? For example, is the PC value compared against a fixed address to
determine the handler behaviour (like Linux’s page fault handler compares
the faulting PC against an exception table, to allow functions like
copy_from_user to fault). We want to know that how exception in kernel is
handled in Windows. Does it maintain a table like Linux or simply set some
variable if there is fault in try/except blocks and doesn’t panic if the
variable is set?

It took a couple readings to realize that by “PC” you mean “EIP” or “RIP”.
Generally, you need to adopt the platform terminology to make the
questions understandable.

Generally, you can determine the execution context from other information,
such as the flags register (although I have not looked at its contents in
many years, so I could be wrong).

Generally, an exception that occurs in the kernel is treated as any other
exception: the top exception frame specifies the target location to
receive control transfer, and a stack address to reset to, and unwinds and
transfers control. So there should never be a need to examine the address
to determine where it came from.

Unlike Linux, Windows was coded with the notion of nested exception
frames, so essentially, you are merely reproducing built-in functionality
that already exists in Microsoft C; Linux has to simulate it the hard way
because it lacks this mechanism.

The only way you can even vaguely care about this is if you are hooking
exception handlers, which is so far beyond acceptable practice that it is
never considered.

You have not yet said what problem you are trying to solve. Note that if
you are trying to solve the problem of taking a page fault in the kernel,
there are other, well-documented, solutions to make sure that such errors
cannot possibly happen, and if you ignore those mechanisms, and try to
implement your own simulations of them to try to emulate the behavior of
Linux, you are choosing the just-about-worst-possible-solution to your
problem.

There is always, logically, a “default exception handler”, and its action
on an exception is to BSOD 0x7E, unhandled kernel exception. But also,
note that you can’t handle page faults in general. You need to study the
actual exception mechanism.

The one-paragraph description is this: there is a known location which
contains the link to the first exception frame. Every time try/except is
encountered, there is an update; the current contents of the head pointer
are stored in the new exception frame, and the head pointer points to the
new exception frame. When an exception is taken, the frame on the stack
is used to reset ESP to a known stack value, and EIP to the
exception-handling code. Note that this is a raw stack-strip; if you were
using C++, it means none of the scope destructors are called, which is
generally a fatal set of behaviors. If it gets to the bottom of the stack
without finding a handler, the default handler is called: BSOD or “Fatal
application error”

Now the even uglier truth: This simplistic model has an overhead which
should be avoided. Thus, there is a simulation of the linked-stack-block
behavior, which is relatively expensive to compute, but the compiler emits
control blocks in a separate section that allow the simulation of the
aforementioned behavior. The 64-bit compiler definitely emits these, and
I’m not sure about the 32-bit compiler. I haven’t looked at the code from
the most recent compilers. The overhead of simulating this behavior is
considerable, but the mechanism is called an /exception/ mechanism, and
thus it is expected that there will be some kind of substantial cost
involved in the recovery, so the overhead of getting there is not a
significant addition to the recovery action (and if the “recovery” action
is a BSOD or interaction with the user, who cares how much it costs
internally?).

So you have to state the problem you are trying to solve, not that you are
trying to implement somebody else’s solution from some other operating
system.
joe

Thanks,
Piyus

On Mon, Aug 26, 2013 at 8:43 PM, Doron Holan
wrote:
>
>> There are only a couple of instances where you need an exception
>> handler
>> in a driver. It is a common mistake to try to use exception handling to
>> mask/fix over bugs (like NULL deref) instead of fixing the actual bugs.
>> What specific problem are you trying to solve? **
>>
>>

>>
>> From: xxxxx@lists.osr.com [mailto:
>> xxxxx@lists.osr.com] On Behalf Of Piyus Kedia
>> Sent: Monday, August 26, 2013 4:02 AM
>> To: Windows System Software Devs Interest List
>> Cc: Sorav Bansal
>> Subject: [ntdev] Exception Handling in Windows driver

>>
>> ****
>>
>> Hi,
>>
>> We found that in Windows drivers if an operation can cause an exception,
>> we must enclose it in try/except blocks. We are just curious to know if
>> there is any other mechanism through which one can tell the kernel that
>> a
>> particular section of code might cause an exception. It will be very
>> nice
>> if somebody can please tell us how the Windows kernel handles these
>> exceptions. For example, the Linux kernel maintains an exception table
>> of
>> these PCs and the exception handler checks whether the exception
>> occurred
>> in the kernel mode, and if so it checks if the PC is present in the
>> exception table or not.
>>
>> Thanks,
>> Piyus
>>
>> — NTDEV is sponsored by OSR Visit the list at:
>> http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
>> http://www.osr.com/careers For our schedule of WDF, WDM, debugging and
>> other seminars visit: http://www.osr.com/seminars To unsubscribe, visit
>> the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer

>>
>> —
>> NTDEV is sponsored by OSR
>>
>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>
>> OSR is HIRING!! See http://www.osr.com/careers
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

Hi Joe,

I am really sorry that I didn’t use the correct terminology. Thanks for
such a clear description of try/except blocks. It really very much helped
us and answers our question.

Thanks,
Piyus

On Tue, Aug 27, 2013 at 6:32 AM, wrote:

> > Hi Doron,
> >
> > We are working on developing a dynamic binary translator for the kernel.
> > Towards this, we wanted to confirm if the interrupted PC value pushed on
> > stack by an interrupt/exception is used by the interrupt/exception
> > handlers? For example, is the PC value compared against a fixed address
> to
> > determine the handler behaviour (like Linux’s page fault handler compares
> > the faulting PC against an exception table, to allow functions like
> > copy_from_user to fault). We want to know that how exception in kernel is
> > handled in Windows. Does it maintain a table like Linux or simply set
> some
> > variable if there is fault in try/except blocks and doesn’t panic if the
> > variable is set?
>
> It took a couple readings to realize that by “PC” you mean “EIP” or “RIP”.
> Generally, you need to adopt the platform terminology to make the
> questions understandable.
>
> Generally, you can determine the execution context from other information,
> such as the flags register (although I have not looked at its contents in
> many years, so I could be wrong).
>
> Generally, an exception that occurs in the kernel is treated as any other
> exception: the top exception frame specifies the target location to
> receive control transfer, and a stack address to reset to, and unwinds and
> transfers control. So there should never be a need to examine the address
> to determine where it came from.
>
> Unlike Linux, Windows was coded with the notion of nested exception
> frames, so essentially, you are merely reproducing built-in functionality
> that already exists in Microsoft C; Linux has to simulate it the hard way
> because it lacks this mechanism.
>
> The only way you can even vaguely care about this is if you are hooking
> exception handlers, which is so far beyond acceptable practice that it is
> never considered.
>
> You have not yet said what problem you are trying to solve. Note that if
> you are trying to solve the problem of taking a page fault in the kernel,
> there are other, well-documented, solutions to make sure that such errors
> cannot possibly happen, and if you ignore those mechanisms, and try to
> implement your own simulations of them to try to emulate the behavior of
> Linux, you are choosing the just-about-worst-possible-solution to your
> problem.
>
> There is always, logically, a “default exception handler”, and its action
> on an exception is to BSOD 0x7E, unhandled kernel exception. But also,
> note that you can’t handle page faults in general. You need to study the
> actual exception mechanism.
>
> The one-paragraph description is this: there is a known location which
> contains the link to the first exception frame. Every time try/except is
> encountered, there is an update; the current contents of the head pointer
> are stored in the new exception frame, and the head pointer points to the
> new exception frame. When an exception is taken, the frame on the stack
> is used to reset ESP to a known stack value, and EIP to the
> exception-handling code. Note that this is a raw stack-strip; if you were
> using C++, it means none of the scope destructors are called, which is
> generally a fatal set of behaviors. If it gets to the bottom of the stack
> without finding a handler, the default handler is called: BSOD or “Fatal
> application error”
>
> Now the even uglier truth: This simplistic model has an overhead which
> should be avoided. Thus, there is a simulation of the linked-stack-block
> behavior, which is relatively expensive to compute, but the compiler emits
> control blocks in a separate section that allow the simulation of the
> aforementioned behavior. The 64-bit compiler definitely emits these, and
> I’m not sure about the 32-bit compiler. I haven’t looked at the code from
> the most recent compilers. The overhead of simulating this behavior is
> considerable, but the mechanism is called an /exception/ mechanism, and
> thus it is expected that there will be some kind of substantial cost
> involved in the recovery, so the overhead of getting there is not a
> significant addition to the recovery action (and if the “recovery” action
> is a BSOD or interaction with the user, who cares how much it costs
> internally?).
>
> So you have to state the problem you are trying to solve, not that you are
> trying to implement somebody else’s solution from some other operating
> system.
> joe
>
> >
> > Thanks,
> > Piyus
> >
> > On Mon, Aug 26, 2013 at 8:43 PM, Doron Holan
> > wrote:
> >
> >> There are only a couple of instances where you need an exception
> >> handler
> >> in a driver. It is a common mistake to try to use exception handling to
> >> mask/fix over bugs (like NULL deref) instead of fixing the actual bugs.
> >> What specific problem are you trying to solve? **
> >>
> >>

> >>
> >> From: xxxxx@lists.osr.com [mailto:
> >> xxxxx@lists.osr.com] On Behalf Of Piyus Kedia
> >> Sent: Monday, August 26, 2013 4:02 AM
> >> To: Windows System Software Devs Interest List
> >> Cc: Sorav Bansal
> >> Subject: [ntdev] Exception Handling in Windows driver

> >>
> >> ****
> >>
> >> Hi,
> >>
> >> We found that in Windows drivers if an operation can cause an exception,
> >> we must enclose it in try/except blocks. We are just curious to know if
> >> there is any other mechanism through which one can tell the kernel that
> >> a
> >> particular section of code might cause an exception. It will be very
> >> nice
> >> if somebody can please tell us how the Windows kernel handles these
> >> exceptions. For example, the Linux kernel maintains an exception table
> >> of
> >> these PCs and the exception handler checks whether the exception
> >> occurred
> >> in the kernel mode, and if so it checks if the PC is present in the
> >> exception table or not.
> >>
> >> Thanks,
> >> Piyus
> >>
> >> — NTDEV is sponsored by OSR Visit the list at:
> >> http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
> >> http://www.osr.com/careers For our schedule of WDF, WDM, debugging and
> >> other seminars visit: http://www.osr.com/seminars To unsubscribe, visit
> >> the List Server section of OSR Online at
> >> http://www.osronline.com/page.cfm?name=ListServer

> >>
> >> —
> >> NTDEV is sponsored by OSR
> >>
> >> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
> >>
> >> OSR is HIRING!! See http://www.osr.com/careers
> >>
> >> For our schedule of WDF, WDM, debugging and other seminars visit:
> >> http://www.osr.com/seminars
> >>
> >> To unsubscribe, visit the List Server section of OSR Online at
> >> http://www.osronline.com/page.cfm?name=ListServer
> >>
> >
> > —
> > NTDEV is sponsored by OSR
> >
> > Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
> >
> > OSR is HIRING!! See http://www.osr.com/careers
> >
> > For our schedule of WDF, WDM, debugging and other seminars visit:
> > http://www.osr.com/seminars
> >
> > To unsubscribe, visit the List Server section of OSR Online at
> > http://www.osronline.com/page.cfm?name=ListServer
>
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Piyus Kedia wrote:

We are working on developing a dynamic binary translator for the kernel.

“What I really need is a droid that understands the binary language of
moisture vaporators.”

Towards this, we wanted to confirm if the interrupted PC value pushed
on stack by an interrupt/exception is used by the interrupt/exception
handlers?

To a certain extent, it has to. Remember that the compiler doesn’t have
any concept of user vs kernel code. When it sees try/except, it does
what it does. In 64-bit code, it creates a table in a separate section
of the driver’s executable that identifies the “try” blocks. So, the
kernel exception handler has to scan those blocks to see if it is in a
“try” block.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I think your best bet is to read the windows internals book. Good luck trying to get linux drivers to run unmodified on windows, simple translation ain’t going to cut it

d

Bent from my phone


From: Piyus Kediamailto:xxxxx
Sent: ?8/?26/?2013 6:14 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Cc: Sorav Bansalmailto:xxxxx
Subject: Re: [ntdev] Exception Handling in Windows driver

Hi Joe,

I am really sorry that I didn’t use the correct terminology. Thanks for such a clear description of try/except blocks. It really very much helped us and answers our question.

Thanks,
Piyus

On Tue, Aug 27, 2013 at 6:32 AM, > wrote:
> Hi Doron,
>
> We are working on developing a dynamic binary translator for the kernel.
> Towards this, we wanted to confirm if the interrupted PC value pushed on
> stack by an interrupt/exception is used by the interrupt/exception
> handlers? For example, is the PC value compared against a fixed address to
> determine the handler behaviour (like Linux’s page fault handler compares
> the faulting PC against an exception table, to allow functions like
> copy_from_user to fault). We want to know that how exception in kernel is
> handled in Windows. Does it maintain a table like Linux or simply set some
> variable if there is fault in try/except blocks and doesn’t panic if the
> variable is set?

It took a couple readings to realize that by “PC” you mean “EIP” or “RIP”.
Generally, you need to adopt the platform terminology to make the
questions understandable.

Generally, you can determine the execution context from other information,
such as the flags register (although I have not looked at its contents in
many years, so I could be wrong).

Generally, an exception that occurs in the kernel is treated as any other
exception: the top exception frame specifies the target location to
receive control transfer, and a stack address to reset to, and unwinds and
transfers control. So there should never be a need to examine the address
to determine where it came from.

Unlike Linux, Windows was coded with the notion of nested exception
frames, so essentially, you are merely reproducing built-in functionality
that already exists in Microsoft C; Linux has to simulate it the hard way
because it lacks this mechanism.

The only way you can even vaguely care about this is if you are hooking
exception handlers, which is so far beyond acceptable practice that it is
never considered.

You have not yet said what problem you are trying to solve. Note that if
you are trying to solve the problem of taking a page fault in the kernel,
there are other, well-documented, solutions to make sure that such errors
cannot possibly happen, and if you ignore those mechanisms, and try to
implement your own simulations of them to try to emulate the behavior of
Linux, you are choosing the just-about-worst-possible-solution to your
problem.

There is always, logically, a “default exception handler”, and its action
on an exception is to BSOD 0x7E, unhandled kernel exception. But also,
note that you can’t handle page faults in general. You need to study the
actual exception mechanism.

The one-paragraph description is this: there is a known location which
contains the link to the first exception frame. Every time try/except is
encountered, there is an update; the current contents of the head pointer
are stored in the new exception frame, and the head pointer points to the
new exception frame. When an exception is taken, the frame on the stack
is used to reset ESP to a known stack value, and EIP to the
exception-handling code. Note that this is a raw stack-strip; if you were
using C++, it means none of the scope destructors are called, which is
generally a fatal set of behaviors. If it gets to the bottom of the stack
without finding a handler, the default handler is called: BSOD or “Fatal
application error”

Now the even uglier truth: This simplistic model has an overhead which
should be avoided. Thus, there is a simulation of the linked-stack-block
behavior, which is relatively expensive to compute, but the compiler emits
control blocks in a separate section that allow the simulation of the
aforementioned behavior. The 64-bit compiler definitely emits these, and
I’m not sure about the 32-bit compiler. I haven’t looked at the code from
the most recent compilers. The overhead of simulating this behavior is
considerable, but the mechanism is called an /exception/ mechanism, and
thus it is expected that there will be some kind of substantial cost
involved in the recovery, so the overhead of getting there is not a
significant addition to the recovery action (and if the “recovery” action
is a BSOD or interaction with the user, who cares how much it costs
internally?).

So you have to state the problem you are trying to solve, not that you are
trying to implement somebody else’s solution from some other operating
system.
joe

>
> Thanks,
> Piyus
>
> On Mon, Aug 26, 2013 at 8:43 PM, Doron Holan
> >wrote:
>
>> There are only a couple of instances where you need an exception
>> handler
>> in a driver. It is a common mistake to try to use exception handling to
>> mask/fix over bugs (like NULL deref) instead of fixing the actual bugs.
>> What specific problem are you trying to solve? **
>>
>>

>>
>> From: xxxxx@lists.osr.commailto:xxxxx [mailto:
>> xxxxx@lists.osr.commailto:xxxxx] On Behalf Of Piyus Kedia
>> Sent: Monday, August 26, 2013 4:02 AM
>> To: Windows System Software Devs Interest List
>> Cc: Sorav Bansal
>> Subject: [ntdev] Exception Handling in Windows driver

>>
>> ****
>>
>> Hi,
>>
>> We found that in Windows drivers if an operation can cause an exception,
>> we must enclose it in try/except blocks. We are just curious to know if
>> there is any other mechanism through which one can tell the kernel that
>> a
>> particular section of code might cause an exception. It will be very
>> nice
>> if somebody can please tell us how the Windows kernel handles these
>> exceptions. For example, the Linux kernel maintains an exception table
>> of
>> these PCs and the exception handler checks whether the exception
>> occurred
>> in the kernel mode, and if so it checks if the PC is present in the
>> exception table or not.
>>
>> Thanks,
>> Piyus
>>
>> — NTDEV is sponsored by OSR Visit the list at:
>> http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
>> http://www.osr.com/careers For our schedule of WDF, WDM, debugging and
>> other seminars visit: http://www.osr.com/seminars To unsubscribe, visit
>> the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer

>>
>> —
>> NTDEV is sponsored by OSR
>>
>> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>>
>> OSR is HIRING!! See http://www.osr.com/careers
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

— NTDEV is sponsored by OSR Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See http://www.osr.com/careers For our schedule of WDF, WDM, debugging and other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx>

>determine the handler behaviour (like Linux’s page fault handler compares the faulting PC against an

exception table, to allow functions like copy_from_user to fault).

Oh yes, Windows is similar.

Each function which contrains __try has a hidden _SEH_Rec local var, which is a small structure.

On function entrance, the _SEH_Rec is put to the top of their list, the current list head is kept at fs:[0] thread/processor local storage.

Also, the _SEH_Rec has a pointer to this function’s constant table, which also has the address of the __except operator in the function.

When exception occurs, the _SEH_Rec list is scanned and EIP is compared to each function’s constant table, and the matching one is executed. Then the filter expression (which is inside __except()) is executed, and then RtlUnwind.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

> It took a couple readings to realize that by “PC” you mean “EIP” or “RIP”.

He’s back in PDP-11 days :slight_smile:


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks

On Tue, Aug 27, 2013 at 12:19 PM, Maxim S. Shatskih
wrote:

> >determine the handler behaviour (like Linux’s page fault handler compares
> the faulting PC against an
> >exception table, to allow functions like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Let’s take a step back for a moment (for the archives only), as this description is a bit misleading.

First, a high level, logical overview, from the operating system layer (excluding more complicated corner cases like nested unwinds, frame consolidation unwinds, and collided exceptions):

The NT Structured Exception Handling (SEH) model implements a two-part method for handling exceptions. In this model, the first part of exception handling is known as “dispatching”, and involves logically searching for a handler function that wants to accept the given exception. The second part of exception handling is known as “unwinding”, and involves logically tearing down the state of frames in between the frame causing the exception, and the frame that handled (i.e. accepted) the exception.

Each function in a program has the opportunity to declare a single logical handler, typically termed the “language-specific handler”, which is logically called during each of the two parts of exception handling (dispatch, and the unwind), as appropriate.

When an exception occurs, the operating system initiates the first phase of exception handling, dispatching. The exception dispatcher logically searches backwards through the call stack; each frame on the stack is inspected to see if it contains an exception handler; if so, that handler is invoked for exception dispatch. The handler is given the opportunity to handle the exception; if it decline to do so, the exception dispatcher searches the next frame to see if it wants to handle the exception, and so on. (If nobody handles the exception, the process crashes or a bugcheck occurs, depending on whether this is user mode or kernel mode.)

If the handler does want to handle the exception, it has two choices; the first of which is to ask the exception dispatcher to just re-try execution of the code that raised exception (typically after adjusting the state of the program). If this happens, then exception dispatching is logically completed. Otherwise, the exception handler is responsible for invoking the unwinder (via RtlUnwindEx - http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx - or, RtlUnwind on native x86 only), specifying a target IP and frame pointer to unwind to.

The unwinder searches the stack downwards from the point where the exception occurs, frame by frame, aiming to reach the specified target frame pointer. Along the way, each intervening frame is logically inspected to see if it contains an exception handler; if so, that handler is invoked for unwind. The handler performs whatever necessary cleanup tasks are necessary for that stack frame (such as running C++ object destructors, etc.), and then returns back to the unwinder. In this way, each intervening frame that participates in exception handling is given the chance to clean up appropriately.

Once the unwinder reaches the target frame, it arranges for control to resume at the target IP, and unwinding logically completes; the program picks off running again in the target frame, at whatever code resides at the target IP. Control is transferred directly by the unwinder, which does not return to its caller.

This more or less describes a simple, high level view of how the operating system itself approaches exception handling. There are other nuances and complexities for various corner cases, which you can research online if you are particularly interested in; I’ll not cover them here for brevity’s sake. Now, most programs do not use “raw” exception handling (except for the very rare function written in assembler that participates in exception handling directly). Most programs use a high level language like C or C++ with a compiler that supports SEH; the compiler provides a “language-specific handler” that is called each time the operating system asks a function written in that language to participate in exception handling.

The language-specific handler handles various tasks like supporting the concept of nested __try/__except blocks, or __finally blocks, in C (http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it handles details like arranging for C++ objects to be destructed at appropriate times, as well as abstracting the details of SEH away in favor of the standard C++ exception handling model that is externally visible to C++ programs. In effect, the language-specific handler’s purpose is to adhere to the operating system level contract for exception handling, and then provide whatever per-function, per-language behavior is required, such as nested try scopes, etc. Based on the underlying primitives exposed for exception dispatch and unwind, you can likely imagine some logical ways that, for example, the high level __try/__except and __finally constructs might be implemented by a C compiler and its corresponding language-specific handler.

Various other high-level constructs heavily leverage this framework for various means; for example, safe setjmp and longjmp utilize the unwinder infrastructure to tear down state in intervening frames in a safe fashion.

Now, the above is only part of the story; different architectures map the high level exception handling model to their local peculiarities in various ways. The standard, modern approach that we take is that each executable has an exception directory that contains a table of functions and, indirectly, a description of each function’s language-specific exception handler (and other minutia needed to unwind the processor nonvolatile register state through the function). Every architecture except x86 implements this approach (for example, AMD64 and ARM do, and IA64 did, etc.), and it would be the one that I would strongly recommend that you study first when learning about the NT exception handling model. In this model, the operating system looks up a function in its table of functions that support exception handling, and, if it finds a match, it can then learn what the language-specific exception handler for that function is, etc. The exception dispatcher and unwinder look up exception handling and unwinding information for each frame visited in this fashion.

The AMD64 exception handling ABI is fairly well documented on MSDN (http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested reading.

On native x86, which is by far the odd-ball out, a somewhat different implementation is used. Ignoring later bolt-ons like SafeSEH for the moment, instead of a static description of exception handlers, the x86 maintains a linked list of frames that participate in exception handling, the list head of which is in turn stored in a per-thread location (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames participating in exception handling are logically pushed on to this list during frame establishment, and popped off during unwind or frame de-establishment. The unwinder implementation is minimalistic compared to other architectures as all registers except the frame pointer are considered volatile across an x86 unwind; at heart, it simply removes entries from the frame chain and invokes exception handlers as appropriate. The same high level SEH model is ultimately implemented, but in a different way.

Again, this is only a high level overview and glosses over various details for more complicated edge conditions, for which there are other references available.

  • S (Msft)
    (Exception handling guy.)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Monday, August 26, 2013 11:50 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Exception Handling in Windows driver

determine the handler behaviour (like Linux’s page fault handler
compares the faulting PC against an exception table, to allow functions like copy_from_user to fault).

Oh yes, Windows is similar.

Each function which contrains __try has a hidden _SEH_Rec local var, which is a small structure.

On function entrance, the _SEH_Rec is put to the top of their list, the current list head is kept at fs:[0] thread/processor local storage.

Also, the _SEH_Rec has a pointer to this function’s constant table, which also has the address of the __except operator in the function.

When exception occurs, the _SEH_Rec list is scanned and EIP is compared to each function’s constant table, and the matching one is executed. Then the filter expression (which is inside __except()) is executed, and then RtlUnwind.


Maxim S. Shatskih
Microsoft MVP on File System And Storage xxxxx@storagecraft.com http://www.storagecraft.com


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

That’s an answer alright.

Thanks, Ken.

Mm

Sent from my Verizon Wireless 4G LTE DROID

Skywing wrote:

Let’s take a step back for a moment (for the archives only), as this
description is a bit misleading.

First, a high level, logical overview, from the operating system layer
(excluding more complicated corner cases like nested unwinds, frame
consolidation unwinds, and collided exceptions):

The NT Structured Exception Handling (SEH) model implements a two-part
method for handling exceptions. In this model, the first part of
exception handling is known as “dispatching”, and involves logically
searching for a handler function that wants to accept the given
exception. The second part of exception handling is known as
“unwinding”, and involves logically tearing down the state of frames
in between the frame causing the exception, and the frame that handled
(i.e. accepted) the exception.

Each function in a program has the opportunity to declare a single
logical handler, typically termed the “language-specific handler”,
which is logically called during each of the two parts of exception
handling (dispatch, and the unwind), as appropriate.

When an exception occurs, the operating system initiates the first
phase of exception handling, dispatching. The exception dispatcher
logically searches backwards through the call stack; each frame on the
stack is inspected to see if it contains an exception handler; if so,
that handler is invoked for exception dispatch. The handler is given
the opportunity to handle the exception; if it decline to do so, the
exception dispatcher searches the next frame to see if it wants to
handle the exception, and so on. (If nobody handles the exception,
the process crashes or a bugcheck occurs, depending on whether this is
user mode or kernel mode.)

If the handler does want to handle the exception, it has two choices;
the first of which is to ask the exception dispatcher to just re-try
execution of the code that raised exception (typically after adjusting
the state of the program). If this happens, then exception
dispatching is logically completed. Otherwise, the exception handler
is responsible for invoking the unwinder (via RtlUnwindEx -
http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx
- or, RtlUnwind on native x86 only), specifying a target IP and frame
pointer to unwind to.

The unwinder searches the stack downwards from the point where the
exception occurs, frame by frame, aiming to reach the specified target
frame pointer. Along the way, each intervening frame is logically
inspected to see if it contains an exception handler; if so, that
handler is invoked for unwind. The handler performs whatever
necessary cleanup tasks are necessary for that stack frame (such as
running C++ object destructors, etc.), and then returns back to the
unwinder. In this way, each intervening frame that participates in
exception handling is given the chance to clean up appropriately.

Once the unwinder reaches the target frame, it arranges for control to
resume at the target IP, and unwinding logically completes; the
program picks off running again in the target frame, at whatever code
resides at the target IP. Control is transferred directly by the
unwinder, which does not return to its caller.

This more or less describes a simple, high level view of how the
operating system itself approaches exception handling. There are
other nuances and complexities for various corner cases, which you can
research online if you are particularly interested in; I’ll not cover
them here for brevity’s sake. Now, most programs do not use “raw”
exception handling (except for the very rare function written in
assembler that participates in exception handling directly). Most
programs use a high level language like C or C++ with a compiler that
supports SEH; the compiler provides a “language-specific handler” that
is called each time the operating system asks a function written in
that language to participate in exception handling.

The language-specific handler handles various tasks like supporting
the concept of nested try/ except blocks, or __finally blocks, in C
(http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it
handles details like arranging for C++ objects to be destructed at
appropriate times, as well as abstracting the details of SEH away in
favor of the standard C++ exception handling model that is externally
visible to C++ programs. In effect, the language-specific handler’s
purpose is to adhere to the operating system level contract for
exception handling, and then provide whatever per-function,
per-language behavior is required, such as nested try scopes, etc.
Based on the underlying primitives exposed for exception dispatch and
unwind, you can likely imagine some logical ways that, for example,
the high level__try/ except and finally constructs might be
implemented by a C compiler and its corresponding language-specific
handler.

Various other high-level constructs heavily leverage this framework
for various means; for example, safe setjmp and longjmp utilize the
unwinder infrastructure to tear down state in intervening frames in a
safe fashion.

Now, the above is only part of the story; different architectures map
the high level exception handling model to their local peculiarities
in various ways. The standard, modern approach that we take is that
each executable has an exception directory that contains a table of
functions and, indirectly, a description of each function’s
language-specific exception handler (and other minutia needed to
unwind the processor nonvolatile register state through the function).
Every architecture except x86 implements this approach (for example,
AMD64 and ARM do, and IA64 did, etc.), and it would be the one that I
would strongly recommend that you study first when learning about the
NT exception handling model. In this model, the operating system
looks up a function in its table of functions that support exception
handling, and, if it finds a match, it can then learn what the
language-specific exception handler for that function is, etc. The
exception dispatcher and unwinder look up exception handling and
unwinding information for each frame visited in this fashion.

The AMD64 exception handling ABI is fairly well documented on MSDN
(http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
reading.

On native x86, which is by far the odd-ball out, a somewhat different
implementation is used. Ignoring later bolt-ons like SafeSEH for the
moment, instead of a static description of exception handlers, the x86
maintains a linked list of frames that participate in exception
handling, the list head of which is in turn stored in a per-thread
location (NT_TIB.ExceptionList, what Maxim alludes to below with
fs:[0]). Frames participating in exception handling are logically
pushed on to this list during frame establishment, and popped off
during unwind or frame de-establishment. The unwinder implementation
is minimalistic compared to other architectures as all registers
except the frame pointer are considered volatile across an x86 unwind;
at heart, it simply removes entries from the frame chain and invokes
exception handlers as appropriate. The same high level SEH model is
ultimately implemented, but in a different way.

Again, this is only a high level overview and glosses over various
details for more complicated edge conditions, for which there are
other references available.

- S (Msft)
(Exception handling guy.)

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S.
Shatskih
Sent: Monday, August 26, 2013 11:50 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Exception Handling in Windows driver

>determine the handler behaviour (like Linux’s page fault handler
>compares the faulting PC against an exception table, to allow functions like copy_from_user to fault).

Oh yes, Windows is similar.

Each function which contrains __try has a hidden _SEH_Rec local var,
which is a small structure.

On function entrance, the _SEH_Rec is put to the top of their list,
the current list head is kept at fs:[0] thread/processor local
storage.

Also, the _SEH_Rec has a pointer to this function’s constant table,
which also has the address of the__except operator in the function.

When exception occurs, the _SEH_Rec list is scanned and EIP is
compared to each function’s constant table, and the matching one is
executed. Then the filter expression (which is inside __except()) is
executed, and then RtlUnwind.


Maxim S. Shatskih
Microsoft MVP on File System And Storage xxxxx@storagecraft.com
http://www.storagecraft.com


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Thank you very much for such a nice discussion.

On Tue, Aug 27, 2013 at 1:39 PM, Skywing wrote:

> Let’s take a step back for a moment (for the archives only), as this
> description is a bit misleading.
>
> First, a high level, logical overview, from the operating system layer
> (excluding more complicated corner cases like nested unwinds, frame
> consolidation unwinds, and collided exceptions):
>
> The NT Structured Exception Handling (SEH) model implements a two-part
> method for handling exceptions. In this model, the first part of exception
> handling is known as “dispatching”, and involves logically searching for a
> handler function that wants to accept the given exception. The second part
> of exception handling is known as “unwinding”, and involves logically
> tearing down the state of frames in between the frame causing the
> exception, and the frame that handled (i.e. accepted) the exception.
>
> Each function in a program has the opportunity to declare a single logical
> handler, typically termed the “language-specific handler”, which is
> logically called during each of the two parts of exception handling
> (dispatch, and the unwind), as appropriate.
>
> When an exception occurs, the operating system initiates the first phase
> of exception handling, dispatching. The exception dispatcher logically
> searches backwards through the call stack; each frame on the stack is
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for exception dispatch. The handler is given the opportunity to
> handle the exception; if it decline to do so, the exception dispatcher
> searches the next frame to see if it wants to handle the exception, and so
> on. (If nobody handles the exception, the process crashes or a bugcheck
> occurs, depending on whether this is user mode or kernel mode.)
>
> If the handler does want to handle the exception, it has two choices; the
> first of which is to ask the exception dispatcher to just re-try execution
> of the code that raised exception (typically after adjusting the state of
> the program). If this happens, then exception dispatching is logically
> completed. Otherwise, the exception handler is responsible for invoking
> the unwinder (via RtlUnwindEx -
> http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx - or, RtlUnwind on native x86 only), specifying a target IP and frame
> pointer to unwind to.
>
> The unwinder searches the stack downwards from the point where the
> exception occurs, frame by frame, aiming to reach the specified target
> frame pointer. Along the way, each intervening frame is logically
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for unwind. The handler performs whatever necessary cleanup
> tasks are necessary for that stack frame (such as running C++ object
> destructors, etc.), and then returns back to the unwinder. In this way,
> each intervening frame that participates in exception handling is given the
> chance to clean up appropriately.
>
> Once the unwinder reaches the target frame, it arranges for control to
> resume at the target IP, and unwinding logically completes; the program
> picks off running again in the target frame, at whatever code resides at
> the target IP. Control is transferred directly by the unwinder, which does
> not return to its caller.
>
>
> This more or less describes a simple, high level view of how the operating
> system itself approaches exception handling. There are other nuances and
> complexities for various corner cases, which you can research online if you
> are particularly interested in; I’ll not cover them here for brevity’s
> sake. Now, most programs do not use “raw” exception handling (except for
> the very rare function written in assembler that participates in exception
> handling directly). Most programs use a high level language like C or C++
> with a compiler that supports SEH; the compiler provides a
> “language-specific handler” that is called each time the operating system
> asks a function written in that language to participate in exception
> handling.
>
> The language-specific handler handles various tasks like supporting the
> concept of nested try/ except blocks, or __finally blocks, in C (
> http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it
> handles details like arranging for C++ objects to be destructed at
> appropriate times, as well as abstracting the details of SEH away in favor
> of the standard C++ exception handling model that is externally visible to
> C++ programs. In effect, the language-specific handler’s purpose is to
> adhere to the operating system level contract for exception handling, and
> then provide whatever per-function, per-language behavior is required, such
> as nested try scopes, etc. Based on the underlying primitives exposed for
> exception dispatch and unwind, you can likely imagine some logical ways
> that, for example, the high level__try/ except and finally constructs
> might be implemented by a C compiler and its corresponding
> language-specific handler.
>
> Various other high-level constructs heavily leverage this framework for
> various means; for example, safe setjmp and longjmp utilize the unwinder
> infrastructure to tear down state in intervening frames in a safe fashion.
>
>
> Now, the above is only part of the story; different architectures map the
> high level exception handling model to their local peculiarities in various
> ways. The standard, modern approach that we take is that each executable
> has an exception directory that contains a table of functions and,
> indirectly, a description of each function’s language-specific exception
> handler (and other minutia needed to unwind the processor nonvolatile
> register state through the function). Every architecture except x86
> implements this approach (for example, AMD64 and ARM do, and IA64 did,
> etc.), and it would be the one that I would strongly recommend that you
> study first when learning about the NT exception handling model. In this
> model, the operating system looks up a function in its table of functions
> that support exception handling, and, if it finds a match, it can then
> learn what the language-specific exception handler for that function is,
> etc. The exception dispatcher and unwinder look up exception handling and
> unwinding information for each frame visited in this fashion.
>
> The AMD64 exception handling ABI is fairly well documented on MSDN (
> http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
> reading.
>
> On native x86, which is by far the odd-ball out, a somewhat different
> implementation is used. Ignoring later bolt-ons like SafeSEH for the
> moment, instead of a static description of exception handlers, the x86
> maintains a linked list of frames that participate in exception handling,
> the list head of which is in turn stored in a per-thread location
> (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames
> participating in exception handling are logically pushed on to this list
> during frame establishment, and popped off during unwind or frame
> de-establishment. The unwinder implementation is minimalistic compared to
> other architectures as all registers except the frame pointer are
> considered volatile across an x86 unwind; at heart, it simply removes
> entries from the frame chain and invokes exception handlers as appropriate.
> The same high level SEH model is ultimately implemented, but in a
> different way.
>
>
> Again, this is only a high level overview and glosses over various details
> for more complicated edge conditions, for which there are other references
> available.
>
> - S (Msft)
> (Exception handling guy.)
>
> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
> Sent: Monday, August 26, 2013 11:50 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Exception Handling in Windows driver
>
> >determine the handler behaviour (like Linux’s page fault handler
> >compares the faulting PC against an exception table, to allow functions
> like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Hi,

I was wondering if you know why x86 and non-x86 architectures use different
implementations for exception handling. Can you please also tell us if the
kernel exception handler follows a similar implementation for different
architectures?

Thanks,
Piyus

On Tue, Aug 27, 2013 at 1:39 PM, Skywing wrote:

> Let’s take a step back for a moment (for the archives only), as this
> description is a bit misleading.
>
> First, a high level, logical overview, from the operating system layer
> (excluding more complicated corner cases like nested unwinds, frame
> consolidation unwinds, and collided exceptions):
>
> The NT Structured Exception Handling (SEH) model implements a two-part
> method for handling exceptions. In this model, the first part of exception
> handling is known as “dispatching”, and involves logically searching for a
> handler function that wants to accept the given exception. The second part
> of exception handling is known as “unwinding”, and involves logically
> tearing down the state of frames in between the frame causing the
> exception, and the frame that handled (i.e. accepted) the exception.
>
> Each function in a program has the opportunity to declare a single logical
> handler, typically termed the “language-specific handler”, which is
> logically called during each of the two parts of exception handling
> (dispatch, and the unwind), as appropriate.
>
> When an exception occurs, the operating system initiates the first phase
> of exception handling, dispatching. The exception dispatcher logically
> searches backwards through the call stack; each frame on the stack is
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for exception dispatch. The handler is given the opportunity to
> handle the exception; if it decline to do so, the exception dispatcher
> searches the next frame to see if it wants to handle the exception, and so
> on. (If nobody handles the exception, the process crashes or a bugcheck
> occurs, depending on whether this is user mode or kernel mode.)
>
> If the handler does want to handle the exception, it has two choices; the
> first of which is to ask the exception dispatcher to just re-try execution
> of the code that raised exception (typically after adjusting the state of
> the program). If this happens, then exception dispatching is logically
> completed. Otherwise, the exception handler is responsible for invoking
> the unwinder (via RtlUnwindEx -
> http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx - or, RtlUnwind on native x86 only), specifying a target IP and frame
> pointer to unwind to.
>
> The unwinder searches the stack downwards from the point where the
> exception occurs, frame by frame, aiming to reach the specified target
> frame pointer. Along the way, each intervening frame is logically
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for unwind. The handler performs whatever necessary cleanup
> tasks are necessary for that stack frame (such as running C++ object
> destructors, etc.), and then returns back to the unwinder. In this way,
> each intervening frame that participates in exception handling is given the
> chance to clean up appropriately.
>
> Once the unwinder reaches the target frame, it arranges for control to
> resume at the target IP, and unwinding logically completes; the program
> picks off running again in the target frame, at whatever code resides at
> the target IP. Control is transferred directly by the unwinder, which does
> not return to its caller.
>
>
> This more or less describes a simple, high level view of how the operating
> system itself approaches exception handling. There are other nuances and
> complexities for various corner cases, which you can research online if you
> are particularly interested in; I’ll not cover them here for brevity’s
> sake. Now, most programs do not use “raw” exception handling (except for
> the very rare function written in assembler that participates in exception
> handling directly). Most programs use a high level language like C or C++
> with a compiler that supports SEH; the compiler provides a
> “language-specific handler” that is called each time the operating system
> asks a function written in that language to participate in exception
> handling.
>
> The language-specific handler handles various tasks like supporting the
> concept of nested try/ except blocks, or __finally blocks, in C (
> http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it
> handles details like arranging for C++ objects to be destructed at
> appropriate times, as well as abstracting the details of SEH away in favor
> of the standard C++ exception handling model that is externally visible to
> C++ programs. In effect, the language-specific handler’s purpose is to
> adhere to the operating system level contract for exception handling, and
> then provide whatever per-function, per-language behavior is required, such
> as nested try scopes, etc. Based on the underlying primitives exposed for
> exception dispatch and unwind, you can likely imagine some logical ways
> that, for example, the high level__try/ except and finally constructs
> might be implemented by a C compiler and its corresponding
> language-specific handler.
>
> Various other high-level constructs heavily leverage this framework for
> various means; for example, safe setjmp and longjmp utilize the unwinder
> infrastructure to tear down state in intervening frames in a safe fashion.
>
>
> Now, the above is only part of the story; different architectures map the
> high level exception handling model to their local peculiarities in various
> ways. The standard, modern approach that we take is that each executable
> has an exception directory that contains a table of functions and,
> indirectly, a description of each function’s language-specific exception
> handler (and other minutia needed to unwind the processor nonvolatile
> register state through the function). Every architecture except x86
> implements this approach (for example, AMD64 and ARM do, and IA64 did,
> etc.), and it would be the one that I would strongly recommend that you
> study first when learning about the NT exception handling model. In this
> model, the operating system looks up a function in its table of functions
> that support exception handling, and, if it finds a match, it can then
> learn what the language-specific exception handler for that function is,
> etc. The exception dispatcher and unwinder look up exception handling and
> unwinding information for each frame visited in this fashion.
>
> The AMD64 exception handling ABI is fairly well documented on MSDN (
> http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
> reading.
>
> On native x86, which is by far the odd-ball out, a somewhat different
> implementation is used. Ignoring later bolt-ons like SafeSEH for the
> moment, instead of a static description of exception handlers, the x86
> maintains a linked list of frames that participate in exception handling,
> the list head of which is in turn stored in a per-thread location
> (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames
> participating in exception handling are logically pushed on to this list
> during frame establishment, and popped off during unwind or frame
> de-establishment. The unwinder implementation is minimalistic compared to
> other architectures as all registers except the frame pointer are
> considered volatile across an x86 unwind; at heart, it simply removes
> entries from the frame chain and invokes exception handlers as appropriate.
> The same high level SEH model is ultimately implemented, but in a
> different way.
>
>
> Again, this is only a high level overview and glosses over various details
> for more complicated edge conditions, for which there are other references
> available.
>
> - S (Msft)
> (Exception handling guy.)
>
> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
> Sent: Monday, August 26, 2013 11:50 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Exception Handling in Windows driver
>
> >determine the handler behaviour (like Linux’s page fault handler
> >compares the faulting PC against an exception table, to allow functions
> like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

It is different because of evolution. We learned from the x86 mistakes when new architectures were added

d
From: Piyus Kedia
Sent: ?Tuesday?, ?August? ?27?, ?2013 ?10?:?53? ?PM
To: Windows System Software Devs Interest List
Cc: Sorav Bansal

Hi,

I was wondering if you know why x86 and non-x86 architectures use different implementations for exception handling. Can you please also tell us if the kernel exception handler follows a similar implementation for different architectures?

Thanks,
Piyus

On Tue, Aug 27, 2013 at 1:39 PM, Skywing > wrote:
Let’s take a step back for a moment (for the archives only), as this description is a bit misleading.

First, a high level, logical overview, from the operating system layer (excluding more complicated corner cases like nested unwinds, frame consolidation unwinds, and collided exceptions):

The NT Structured Exception Handling (SEH) model implements a two-part method for handling exceptions. In this model, the first part of exception handling is known as “dispatching”, and involves logically searching for a handler function that wants to accept the given exception. The second part of exception handling is known as “unwinding”, and involves logically tearing down the state of frames in between the frame causing the exception, and the frame that handled (i.e. accepted) the exception.

Each function in a program has the opportunity to declare a single logical handler, typically termed the “language-specific handler”, which is logically called during each of the two parts of exception handling (dispatch, and the unwind), as appropriate.

When an exception occurs, the operating system initiates the first phase of exception handling, dispatching. The exception dispatcher logically searches backwards through the call stack; each frame on the stack is inspected to see if it contains an exception handler; if so, that handler is invoked for exception dispatch. The handler is given the opportunity to handle the exception; if it decline to do so, the exception dispatcher searches the next frame to see if it wants to handle the exception, and so on. (If nobody handles the exception, the process crashes or a bugcheck occurs, depending on whether this is user mode or kernel mode.)

If the handler does want to handle the exception, it has two choices; the first of which is to ask the exception dispatcher to just re-try execution of the code that raised exception (typically after adjusting the state of the program). If this happens, then exception dispatching is logically completed. Otherwise, the exception handler is responsible for invoking the unwinder (via RtlUnwindEx - http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspxhttp: - or, RtlUnwind on native x86 only), specifying a target IP and frame pointer to unwind to.

The unwinder searches the stack downwards from the point where the exception occurs, frame by frame, aiming to reach the specified target frame pointer. Along the way, each intervening frame is logically inspected to see if it contains an exception handler; if so, that handler is invoked for unwind. The handler performs whatever necessary cleanup tasks are necessary for that stack frame (such as running C++ object destructors, etc.), and then returns back to the unwinder. In this way, each intervening frame that participates in exception handling is given the chance to clean up appropriately.

Once the unwinder reaches the target frame, it arranges for control to resume at the target IP, and unwinding logically completes; the program picks off running again in the target frame, at whatever code resides at the target IP. Control is transferred directly by the unwinder, which does not return to its caller.

This more or less describes a simple, high level view of how the operating system itself approaches exception handling. There are other nuances and complexities for various corner cases, which you can research online if you are particularly interested in; I’ll not cover them here for brevity’s sake. Now, most programs do not use “raw” exception handling (except for the very rare function written in assembler that participates in exception handling directly). Most programs use a high level language like C or C++ with a compiler that supports SEH; the compiler provides a “language-specific handler” that is called each time the operating system asks a function written in that language to participate in exception handling.

The language-specific handler handles various tasks like supporting the concept of nested try/ except blocks, or __finally blocks, in C (http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it handles details like arranging for C++ objects to be destructed at appropriate times, as well as abstracting the details of SEH away in favor of the standard C++ exception handling model that is externally visible to C++ programs. In effect, the language-specific handler’s purpose is to adhere to the operating system level contract for exception handling, and then provide whatever per-function, per-language behavior is required, such as nested try scopes, etc. Based on the underlying primitives exposed for exception dispatch and unwind, you can likely imagine some logical ways that, for example, the high level__try/ except and finally constructs might be implemented by a C compiler and its corresponding language-specific handler.

Various other high-level constructs heavily leverage this framework for various means; for example, safe setjmp and longjmp utilize the unwinder infrastructure to tear down state in intervening frames in a safe fashion.

Now, the above is only part of the story; different architectures map the high level exception handling model to their local peculiarities in various ways. The standard, modern approach that we take is that each executable has an exception directory that contains a table of functions and, indirectly, a description of each function’s language-specific exception handler (and other minutia needed to unwind the processor nonvolatile register state through the function). Every architecture except x86 implements this approach (for example, AMD64 and ARM do, and IA64 did, etc.), and it would be the one that I would strongly recommend that you study first when learning about the NT exception handling model. In this model, the operating system looks up a function in its table of functions that support exception handling, and, if it finds a match, it can then learn what the language-specific exception handler for that function is, etc. The exception dispatcher and unwinder look up exception handling and unwinding information for each frame visited in this fashion.

The AMD64 exception handling ABI is fairly well documented on MSDN (http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested reading.

On native x86, which is by far the odd-ball out, a somewhat different implementation is used. Ignoring later bolt-ons like SafeSEH for the moment, instead of a static description of exception handlers, the x86 maintains a linked list of frames that participate in exception handling, the list head of which is in turn stored in a per-thread location (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames participating in exception handling are logically pushed on to this list during frame establishment, and popped off during unwind or frame de-establishment. The unwinder implementation is minimalistic compared to other architectures as all registers except the frame pointer are considered volatile across an x86 unwind; at heart, it simply removes entries from the frame chain and invokes exception handlers as appropriate. The same high level SEH model is ultimately implemented, but in a different way.

Again, this is only a high level overview and glosses over various details for more complicated edge conditions, for which there are other references available.

- S (Msft)
(Exception handling guy.)

-----Original Message-----
From: xxxxx@lists.osr.commailto:xxxxx [mailto:xxxxx@lists.osr.commailto:xxxxx] On Behalf Of Maxim S. Shatskih
Sent: Monday, August 26, 2013 11:50 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Exception Handling in Windows driver

>determine the handler behaviour (like Linux’s page fault handler
>compares the faulting PC against an exception table, to allow functions like copy_from_user to fault).

Oh yes, Windows is similar.

Each function which contrains __try has a hidden _SEH_Rec local var, which is a small structure.

On function entrance, the _SEH_Rec is put to the top of their list, the current list head is kept at fs:[0] thread/processor local storage.

Also, the _SEH_Rec has a pointer to this function’s constant table, which also has the address of the__except operator in the function.

When exception occurs, the _SEH_Rec list is scanned and EIP is compared to each function’s constant table, and the matching one is executed. Then the filter expression (which is inside __except()) is executed, and then RtlUnwind.


Maxim S. Shatskih
Microsoft MVP on File System And Storage xxxxx@storagecraft.commailto:xxxxx http://www.storagecraft.com


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

— NTDEV is sponsored by OSR Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See http://www.osr.com/careers For our schedule of WDF, WDM, debugging and other seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></http:>

  • S (Msft)
    (Exception handling guy.)

copycat :slight_smile:

thanks ken that was a nice explanation

On 8/28/13, Doron Holan wrote:
> It is different because of evolution. We learned from the x86 mistakes when
> new architectures were added
>
> d
> From: Piyus Kedia
> Sent: Tuesday, August 27, 2013 10:53 PM
> To: Windows System Software Devs Interest List
> Cc: Sorav Bansal
>
> Hi,
>
> I was wondering if you know why x86 and non-x86 architectures use different
> implementations for exception handling. Can you please also tell us if the
> kernel exception handler follows a similar implementation for different
> architectures?
>
> Thanks,
> Piyus
>
>
> On Tue, Aug 27, 2013 at 1:39 PM, Skywing
> > wrote:
> Let’s take a step back for a moment (for the archives only), as this
> description is a bit misleading.
>
> First, a high level, logical overview, from the operating system layer
> (excluding more complicated corner cases like nested unwinds, frame
> consolidation unwinds, and collided exceptions):
>
> The NT Structured Exception Handling (SEH) model implements a two-part
> method for handling exceptions. In this model, the first part of exception
> handling is known as “dispatching”, and involves logically searching for a
> handler function that wants to accept the given exception. The second part
> of exception handling is known as “unwinding”, and involves logically
> tearing down the state of frames in between the frame causing the exception,
> and the frame that handled (i.e. accepted) the exception.
>
> Each function in a program has the opportunity to declare a single logical
> handler, typically termed the “language-specific handler”, which is
> logically called during each of the two parts of exception handling
> (dispatch, and the unwind), as appropriate.
>
> When an exception occurs, the operating system initiates the first phase of
> exception handling, dispatching. The exception dispatcher logically
> searches backwards through the call stack; each frame on the stack is
> inspected to see if it contains an exception handler; if so, that handler is
> invoked for exception dispatch. The handler is given the opportunity to
> handle the exception; if it decline to do so, the exception dispatcher
> searches the next frame to see if it wants to handle the exception, and so
> on. (If nobody handles the exception, the process crashes or a bugcheck
> occurs, depending on whether this is user mode or kernel mode.)
>
> If the handler does want to handle the exception, it has two choices; the
> first of which is to ask the exception dispatcher to just re-try execution
> of the code that raised exception (typically after adjusting the state of
> the program). If this happens, then exception dispatching is logically
> completed. Otherwise, the exception handler is responsible for invoking the
> unwinder (via RtlUnwindEx -
> http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspxhttp:
> - or, RtlUnwind on native x86 only), specifying a target IP and frame
> pointer to unwind to.
>
> The unwinder searches the stack downwards from the point where the exception
> occurs, frame by frame, aiming to reach the specified target frame pointer.
> Along the way, each intervening frame is logically inspected to see if it
> contains an exception handler; if so, that handler is invoked for unwind.
> The handler performs whatever necessary cleanup tasks are necessary for that
> stack frame (such as running C++ object destructors, etc.), and then returns
> back to the unwinder. In this way, each intervening frame that participates
> in exception handling is given the chance to clean up appropriately.
>
> Once the unwinder reaches the target frame, it arranges for control to
> resume at the target IP, and unwinding logically completes; the program
> picks off running again in the target frame, at whatever code resides at the
> target IP. Control is transferred directly by the unwinder, which does not
> return to its caller.
>
>
> This more or less describes a simple, high level view of how the operating
> system itself approaches exception handling. There are other nuances and
> complexities for various corner cases, which you can research online if you
> are particularly interested in; I’ll not cover them here for brevity’s sake.
> Now, most programs do not use “raw” exception handling (except for the very
> rare function written in assembler that participates in exception handling
> directly). Most programs use a high level language like C or C++ with a
> compiler that supports SEH; the compiler provides a “language-specific
> handler” that is called each time the operating system asks a function
> written in that language to participate in exception handling.
>
> The language-specific handler handles various tasks like supporting the
> concept of nested try/ except blocks, or __finally blocks, in C
> (http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it handles
> details like arranging for C++ objects to be destructed at appropriate
> times, as well as abstracting the details of SEH away in favor of the
> standard C++ exception handling model that is externally visible to C++
> programs. In effect, the language-specific handler’s purpose is to adhere
> to the operating system level contract for exception handling, and then
> provide whatever per-function, per-language behavior is required, such as
> nested try scopes, etc. Based on the underlying primitives exposed for
> exception dispatch and unwind, you can likely imagine some logical ways
> that, for example, the high level__try/ except and finally constructs
> might be implemented by a C compiler and its corresponding language-specific
> handler.
>
> Various other high-level constructs heavily leverage this framework for
> various means; for example, safe setjmp and longjmp utilize the unwinder
> infrastructure to tear down state in intervening frames in a safe fashion.
>
>
> Now, the above is only part of the story; different architectures map the
> high level exception handling model to their local peculiarities in various
> ways. The standard, modern approach that we take is that each executable
> has an exception directory that contains a table of functions and,
> indirectly, a description of each function’s language-specific exception
> handler (and other minutia needed to unwind the processor nonvolatile
> register state through the function). Every architecture except x86
> implements this approach (for example, AMD64 and ARM do, and IA64 did,
> etc.), and it would be the one that I would strongly recommend that you
> study first when learning about the NT exception handling model. In this
> model, the operating system looks up a function in its table of functions
> that support exception handling, and, if it finds a match, it can then learn
> what the language-specific exception handler for that function is, etc. The
> exception dispatcher and unwinder look up exception handling and unwinding
> information for each frame visited in this fashion.
>
> The AMD64 exception handling ABI is fairly well documented on MSDN
> (http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
> reading.
>
> On native x86, which is by far the odd-ball out, a somewhat different
> implementation is used. Ignoring later bolt-ons like SafeSEH for the
> moment, instead of a static description of exception handlers, the x86
> maintains a linked list of frames that participate in exception handling,
> the list head of which is in turn stored in a per-thread location
> (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames
> participating in exception handling are logically pushed on to this list
> during frame establishment, and popped off during unwind or frame
> de-establishment. The unwinder implementation is minimalistic compared to
> other architectures as all registers except the frame pointer are considered
> volatile across an x86 unwind; at heart, it simply removes entries from the
> frame chain and invokes exception handlers as appropriate. The same high
> level SEH model is ultimately implemented, but in a different way.
>
>
> Again, this is only a high level overview and glosses over various details
> for more complicated edge conditions, for which there are other references
> available.
>
> - S (Msft)
> (Exception handling guy.)
>
> -----Original Message-----
> From:
> xxxxx@lists.osr.commailto:xxxxx
> [mailto:xxxxx@lists.osr.commailto:xxxxx]
> On Behalf Of Maxim S. Shatskih
> Sent: Monday, August 26, 2013 11:50 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Exception Handling in Windows driver
>
>>determine the handler behaviour (like Linux’s page fault handler
>>compares the faulting PC against an exception table, to allow functions
>> like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage
> xxxxx@storagecraft.commailto:xxxxx
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> — NTDEV is sponsored by OSR Visit the list at:
> http://www.osronline.com/showlists.cfm?list=ntdev OSR is HIRING!! See
> http://www.osr.com/careers For our schedule of WDF, WDM, debugging and other
> seminars visit: http://www.osr.com/seminars To unsubscribe, visit the List
> Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></http:>

Because x86 impl is older, it is as old as early 90ies (as Win32 and NT kernel), and requires execution overhead of filling _SEH_Rec (2 pointers + some more stuff) on each function prolog. It also eats the stack space for _SEH_Rec structures.

x64 (and also the newer GCC stuff for x86) uses zero-overhead, newer approach.

To look at these details, run the MS’s compiler in “generate assembler text” mode, which is IIRC /FA command line switch.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

“Piyus Kedia” wrote in message news:xxxxx@ntdev…
Hi,

I was wondering if you know why x86 and non-x86 architectures use different implementations for exception handling. Can you please also tell us if the kernel exception handler follows a similar implementation for different architectures?

Thanks,

Piyus

On Tue, Aug 27, 2013 at 1:39 PM, Skywing wrote:

Let’s take a step back for a moment (for the archives only), as this description is a bit misleading.

First, a high level, logical overview, from the operating system layer (excluding more complicated corner cases like nested unwinds, frame consolidation unwinds, and collided exceptions):

The NT Structured Exception Handling (SEH) model implements a two-part method for handling exceptions. In this model, the first part of exception handling is known as “dispatching”, and involves logically searching for a handler function that wants to accept the given exception. The second part of exception handling is known as “unwinding”, and involves logically tearing down the state of frames in between the frame causing the exception, and the frame that handled (i.e. accepted) the exception.

Each function in a program has the opportunity to declare a single logical handler, typically termed the “language-specific handler”, which is logically called during each of the two parts of exception handling (dispatch, and the unwind), as appropriate.

When an exception occurs, the operating system initiates the first phase of exception handling, dispatching. The exception dispatcher logically searches backwards through the call stack; each frame on the stack is inspected to see if it contains an exception handler; if so, that handler is invoked for exception dispatch. The handler is given the opportunity to handle the exception; if it decline to do so, the exception dispatcher searches the next frame to see if it wants to handle the exception, and so on. (If nobody handles the exception, the process crashes or a bugcheck occurs, depending on whether this is user mode or kernel mode.)

If the handler does want to handle the exception, it has two choices; the first of which is to ask the exception dispatcher to just re-try execution of the code that raised exception (typically after adjusting the state of the program). If this happens, then exception dispatching is logically completed. Otherwise, the exception handler is responsible for invoking the unwinder (via RtlUnwindEx - http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx - or, RtlUnwind on native x86 only), specifying a target IP and frame pointer to unwind to.

The unwinder searches the stack downwards from the point where the exception occurs, frame by frame, aiming to reach the specified target frame pointer. Along the way, each intervening frame is logically inspected to see if it contains an exception handler; if so, that handler is invoked for unwind. The handler performs whatever necessary cleanup tasks are necessary for that stack frame (such as running C++ object destructors, etc.), and then returns back to the unwinder. In this way, each intervening frame that participates in exception handling is given the chance to clean up appropriately.

Once the unwinder reaches the target frame, it arranges for control to resume at the target IP, and unwinding logically completes; the program picks off running again in the target frame, at whatever code resides at the target IP. Control is transferred directly by the unwinder, which does not return to its caller.

This more or less describes a simple, high level view of how the operating system itself approaches exception handling. There are other nuances and complexities for various corner cases, which you can research online if you are particularly interested in; I’ll not cover them here for brevity’s sake. Now, most programs do not use “raw” exception handling (except for the very rare function written in assembler that participates in exception handling directly). Most programs use a high level language like C or C++ with a compiler that supports SEH; the compiler provides a “language-specific handler” that is called each time the operating system asks a function written in that language to participate in exception handling.

The language-specific handler handles various tasks like supporting the concept of nested try/ except blocks, or __finally blocks, in C (http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it handles details like arranging for C++ objects to be destructed at appropriate times, as well as abstracting the details of SEH away in favor of the standard C++ exception handling model that is externally visible to C++ programs. In effect, the language-specific handler’s purpose is to adhere to the operating system level contract for exception handling, and then provide whatever per-function, per-language behavior is required, such as nested try scopes, etc. Based on the underlying primitives exposed for exception dispatch and unwind, you can likely imagine some logical ways that, for example, the high level__try/ except and finally constructs might be implemented by a C compiler and its corresponding language-specific handler.

Various other high-level constructs heavily leverage this framework for various means; for example, safe setjmp and longjmp utilize the unwinder infrastructure to tear down state in intervening frames in a safe fashion.

Now, the above is only part of the story; different architectures map the high level exception handling model to their local peculiarities in various ways. The standard, modern approach that we take is that each executable has an exception directory that contains a table of functions and, indirectly, a description of each function’s language-specific exception handler (and other minutia needed to unwind the processor nonvolatile register state through the function). Every architecture except x86 implements this approach (for example, AMD64 and ARM do, and IA64 did, etc.), and it would be the one that I would strongly recommend that you study first when learning about the NT exception handling model. In this model, the operating system looks up a function in its table of functions that support exception handling, and, if it finds a match, it can then learn what the language-specific exception handler for that function is, etc. The exception dispatcher and unwinder look up exception handling and unwinding information for each frame visited in this fashion.

The AMD64 exception handling ABI is fairly well documented on MSDN (http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested reading.

On native x86, which is by far the odd-ball out, a somewhat different implementation is used. Ignoring later bolt-ons like SafeSEH for the moment, instead of a static description of exception handlers, the x86 maintains a linked list of frames that participate in exception handling, the list head of which is in turn stored in a per-thread location (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames participating in exception handling are logically pushed on to this list during frame establishment, and popped off during unwind or frame de-establishment. The unwinder implementation is minimalistic compared to other architectures as all registers except the frame pointer are considered volatile across an x86 unwind; at heart, it simply removes entries from the frame chain and invokes exception handlers as appropriate. The same high level SEH model is ultimately implemented, but in a different way.

Again, this is only a high level overview and glosses over various details for more complicated edge conditions, for which there are other references available.

- S (Msft)
(Exception handling guy.)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Monday, August 26, 2013 11:50 PM
To: Windows System Software Devs Interest List

Subject: Re:[ntdev] Exception Handling in Windows driver

>determine the handler behaviour (like Linux’s page fault handler
>compares the faulting PC against an exception table, to allow functions like copy_from_user to fault).

Oh yes, Windows is similar.

Each function which contrains __try has a hidden _SEH_Rec local var, which is a small structure.

On function entrance, the _SEH_Rec is put to the top of their list, the current list head is kept at fs:[0] thread/processor local storage.

Also, the _SEH_Rec has a pointer to this function’s constant table, which also has the address of the__except operator in the function.

When exception occurs, the _SEH_Rec list is scanned and EIP is compared to each function’s constant table, and the matching one is executed. Then the filter expression (which is inside __except()) is executed, and then RtlUnwind.


Maxim S. Shatskih
Microsoft MVP on File System And Storage xxxxx@storagecraft.com http://www.storagecraft.com


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Because x86 impl is older, it is as old as early 90ies (as Win32 and

NT kernel), and requires execution overhead of filling _SEH_Rec (2
pointers + some more stuff) on each function prolog. It also eats the
stack space for _SEH_Rec structures.

x64 (and also the newer GCC stuff for x86) uses zero-overhead, newer
approach.

To look at these details, run the MS’s compiler in “generate assembler
text” mode, which is IIRC /FA command line switch.

This can be a fascinating and informative exercise. Especially with the
64-bit compiler with full optimizations enabled. And no matter what you
see from /FA, if you use LTCG you will see even more amazing
optimizations. The ability to collapse C++ template code to a single
function, for example, is quite awesome.

In my assembly-code course (which I never taught, because I was forced
into retirement by medical issues), I used both 32-bit and 64-bit output,
and often would compare the two.

The x86 is simply a way of doing nested setjmp/longjmp in a fashion that
is both well-structured and visible to the compiler (many optimizations do
not work correctly around a setjmp, because in the normal course of code
generation the compiler failed to recognize that all registers are
volatile around a setjmp. I remember finding these bugs in early
compilers.
joe


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

“Piyus Kedia” wrote in message news:xxxxx@ntdev…
> Hi,
>
>
> I was wondering if you know why x86 and non-x86 architectures use
> different implementations for exception handling. Can you please also tell
> us if the kernel exception handler follows a similar implementation for
> different architectures?
>
>
> Thanks,
>
> Piyus
>
>
>
>
> On Tue, Aug 27, 2013 at 1:39 PM, Skywing
> wrote:
>
> Let’s take a step back for a moment (for the archives only), as this
> description is a bit misleading.
>
> First, a high level, logical overview, from the operating system layer
> (excluding more complicated corner cases like nested unwinds, frame
> consolidation unwinds, and collided exceptions):
>
> The NT Structured Exception Handling (SEH) model implements a two-part
> method for handling exceptions. In this model, the first part of
> exception handling is known as “dispatching”, and involves logically
> searching for a handler function that wants to accept the given exception.
> The second part of exception handling is known as “unwinding”, and
> involves logically tearing down the state of frames in between the frame
> causing the exception, and the frame that handled (i.e. accepted) the
> exception.
>
> Each function in a program has the opportunity to declare a single logical
> handler, typically termed the “language-specific handler”, which is
> logically called during each of the two parts of exception handling
> (dispatch, and the unwind), as appropriate.
>
> When an exception occurs, the operating system initiates the first phase
> of exception handling, dispatching. The exception dispatcher logically
> searches backwards through the call stack; each frame on the stack is
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for exception dispatch. The handler is given the opportunity
> to handle the exception; if it decline to do so, the exception dispatcher
> searches the next frame to see if it wants to handle the exception, and so
> on. (If nobody handles the exception, the process crashes or a bugcheck
> occurs, depending on whether this is user mode or kernel mode.)
>
> If the handler does want to handle the exception, it has two choices; the
> first of which is to ask the exception dispatcher to just re-try execution
> of the code that raised exception (typically after adjusting the state of
> the program). If this happens, then exception dispatching is logically
> completed. Otherwise, the exception handler is responsible for invoking
> the unwinder (via RtlUnwindEx -
> http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx
> - or, RtlUnwind on native x86 only), specifying a target IP and frame
> pointer to unwind to.
>
> The unwinder searches the stack downwards from the point where the
> exception occurs, frame by frame, aiming to reach the specified target
> frame pointer. Along the way, each intervening frame is logically
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for unwind. The handler performs whatever necessary cleanup
> tasks are necessary for that stack frame (such as running C++ object
> destructors, etc.), and then returns back to the unwinder. In this way,
> each intervening frame that participates in exception handling is given
> the chance to clean up appropriately.
>
> Once the unwinder reaches the target frame, it arranges for control to
> resume at the target IP, and unwinding logically completes; the program
> picks off running again in the target frame, at whatever code resides at
> the target IP. Control is transferred directly by the unwinder, which
> does not return to its caller.
>
>
> This more or less describes a simple, high level view of how the operating
> system itself approaches exception handling. There are other nuances and
> complexities for various corner cases, which you can research online if
> you are particularly interested in; I’ll not cover them here for brevity’s
> sake. Now, most programs do not use “raw” exception handling (except for
> the very rare function written in assembler that participates in exception
> handling directly). Most programs use a high level language like C or C++
> with a compiler that supports SEH; the compiler provides a
> “language-specific handler” that is called each time the operating system
> asks a function written in that language to participate in exception
> handling.
>
> The language-specific handler handles various tasks like supporting the
> concept of nested try/ except blocks, or __finally blocks, in C
> (http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it
> handles details like arranging for C++ objects to be destructed at
> appropriate times, as well as abstracting the details of SEH away in favor
> of the standard C++ exception handling model that is externally visible to
> C++ programs. In effect, the language-specific handler’s purpose is to
> adhere to the operating system level contract for exception handling, and
> then provide whatever per-function, per-language behavior is required,
> such as nested try scopes, etc. Based on the underlying primitives
> exposed for exception dispatch and unwind, you can likely imagine some
> logical ways that, for example, the high level__try/ except and
>
finally constructs might be implemented by a C compiler and its
> corresponding language-specific handler.
>
> Various other high-level constructs heavily leverage this framework for
> various means; for example, safe setjmp and longjmp utilize the unwinder
> infrastructure to tear down state in intervening frames in a safe fashion.
>
>
> Now, the above is only part of the story; different architectures map the
> high level exception handling model to their local peculiarities in
> various ways. The standard, modern approach that we take is that each
> executable has an exception directory that contains a table of functions
> and, indirectly, a description of each function’s language-specific
> exception handler (and other minutia needed to unwind the processor
> nonvolatile register state through the function). Every architecture
> except x86 implements this approach (for example, AMD64 and ARM do, and
> IA64 did, etc.), and it would be the one that I would strongly recommend
> that you study first when learning about the NT exception handling model.
> In this model, the operating system looks up a function in its table of
> functions that support exception handling, and, if it finds a match, it
> can then learn what the language-specific exception handler for that
> function is, etc. The exception dispatcher and unwinder look up exception
> handling and unwinding information for each frame visited in this fashion.
>
> The AMD64 exception handling ABI is fairly well documented on MSDN
> (http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
> reading.
>
> On native x86, which is by far the odd-ball out, a somewhat different
> implementation is used. Ignoring later bolt-ons like SafeSEH for the
> moment, instead of a static description of exception handlers, the x86
> maintains a linked list of frames that participate in exception handling,
> the list head of which is in turn stored in a per-thread location
> (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames
> participating in exception handling are logically pushed on to this list
> during frame establishment, and popped off during unwind or frame
> de-establishment. The unwinder implementation is minimalistic compared to
> other architectures as all registers except the frame pointer are
> considered volatile across an x86 unwind; at heart, it simply removes
> entries from the frame chain and invokes exception handlers as
> appropriate. The same high level SEH model is ultimately implemented, but
> in a different way.
>
>
> Again, this is only a high level overview and glosses over various details
> for more complicated edge conditions, for which there are other references
> available.
>
> - S (Msft)
> (Exception handling guy.)
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
> Sent: Monday, August 26, 2013 11:50 PM
> To: Windows System Software Devs Interest List
>
> Subject: Re:[ntdev] Exception Handling in Windows driver
>
>>determine the handler behaviour (like Linux’s page fault handler
>>compares the faulting PC against an exception table, to allow functions
>> like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Thanks.

On Thu, Aug 29, 2013 at 12:46 AM, Maxim S. Shatskih
wrote:

> Because x86 impl is older, it is as old as early 90ies (as Win32 and
> NT kernel), and requires execution overhead of filling _SEH_Rec (2 pointers
> + some more stuff) on each function prolog. It also eats the stack space
> for _SEH_Rec structures.
>
> x64 (and also the newer GCC stuff for x86) uses zero-overhead, newer
> approach.
>
> To look at these details, run the MS’s compiler in “generate assembler
> text” mode, which is IIRC /FA command line switch.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
> “Piyus Kedia” wrote in message news:xxxxx@ntdev…
> Hi,
>
>
> I was wondering if you know why x86 and non-x86 architectures use
> different implementations for exception handling. Can you please also tell
> us if the kernel exception handler follows a similar implementation for
> different architectures?
>
>
> Thanks,
>
> Piyus
>
>
>
>
> On Tue, Aug 27, 2013 at 1:39 PM, Skywing
> wrote:
>
> Let’s take a step back for a moment (for the archives only), as this
> description is a bit misleading.
>
> First, a high level, logical overview, from the operating system layer
> (excluding more complicated corner cases like nested unwinds, frame
> consolidation unwinds, and collided exceptions):
>
> The NT Structured Exception Handling (SEH) model implements a two-part
> method for handling exceptions. In this model, the first part of exception
> handling is known as “dispatching”, and involves logically searching for a
> handler function that wants to accept the given exception. The second part
> of exception handling is known as “unwinding”, and involves logically
> tearing down the state of frames in between the frame causing the
> exception, and the frame that handled (i.e. accepted) the exception.
>
> Each function in a program has the opportunity to declare a single logical
> handler, typically termed the “language-specific handler”, which is
> logically called during each of the two parts of exception handling
> (dispatch, and the unwind), as appropriate.
>
> When an exception occurs, the operating system initiates the first phase
> of exception handling, dispatching. The exception dispatcher logically
> searches backwards through the call stack; each frame on the stack is
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for exception dispatch. The handler is given the opportunity to
> handle the exception; if it decline to do so, the exception dispatcher
> searches the next frame to see if it wants to handle the exception, and so
> on. (If nobody handles the exception, the process crashes or a bugcheck
> occurs, depending on whether this is user mode or kernel mode.)
>
> If the handler does want to handle the exception, it has two choices; the
> first of which is to ask the exception dispatcher to just re-try execution
> of the code that raised exception (typically after adjusting the state of
> the program). If this happens, then exception dispatching is logically
> completed. Otherwise, the exception handler is responsible for invoking
> the unwinder (via RtlUnwindEx -
> http://msdn.microsoft.com/en-us/library/windows/apps/ms680615(v=vs.85).aspx - or, RtlUnwind on native x86 only), specifying a target IP and frame
> pointer to unwind to.
>
> The unwinder searches the stack downwards from the point where the
> exception occurs, frame by frame, aiming to reach the specified target
> frame pointer. Along the way, each intervening frame is logically
> inspected to see if it contains an exception handler; if so, that handler
> is invoked for unwind. The handler performs whatever necessary cleanup
> tasks are necessary for that stack frame (such as running C++ object
> destructors, etc.), and then returns back to the unwinder. In this way,
> each intervening frame that participates in exception handling is given the
> chance to clean up appropriately.
>
> Once the unwinder reaches the target frame, it arranges for control to
> resume at the target IP, and unwinding logically completes; the program
> picks off running again in the target frame, at whatever code resides at
> the target IP. Control is transferred directly by the unwinder, which does
> not return to its caller.
>
>
> This more or less describes a simple, high level view of how the operating
> system itself approaches exception handling. There are other nuances and
> complexities for various corner cases, which you can research online if you
> are particularly interested in; I’ll not cover them here for brevity’s
> sake. Now, most programs do not use “raw” exception handling (except for
> the very rare function written in assembler that participates in exception
> handling directly). Most programs use a high level language like C or C++
> with a compiler that supports SEH; the compiler provides a
> “language-specific handler” that is called each time the operating system
> asks a function written in that language to participate in exception
> handling.
>
> The language-specific handler handles various tasks like supporting the
> concept of nested try/ except blocks, or __finally blocks, in C (
> http://msdn.microsoft.com/en-us/library/s58ftw19.aspx). In C++, it
> handles details like arranging for C++ objects to be destructed at
> appropriate times, as well as abstracting the details of SEH away in favor
> of the standard C++ exception handling model that is externally visible to
> C++ programs. In effect, the language-specific handler’s purpose is to
> adhere to the operating system level contract for exception handling, and
> then provide whatever per-function, per-language behavior is required, such
> as nested try scopes, etc. Based on the underlying primitives exposed for
> exception dispatch and unwind, you can likely imagine some logical ways
> that, for example, the high level__try/ except and finally constructs
> might be implemented by a C compiler and its corresponding
> language-specific handler.
>
> Various other high-level constructs heavily leverage this framework for
> various means; for example, safe setjmp and longjmp utilize the unwinder
> infrastructure to tear down state in intervening frames in a safe fashion.
>
>
> Now, the above is only part of the story; different architectures map the
> high level exception handling model to their local peculiarities in various
> ways. The standard, modern approach that we take is that each executable
> has an exception directory that contains a table of functions and,
> indirectly, a description of each function’s language-specific exception
> handler (and other minutia needed to unwind the processor nonvolatile
> register state through the function). Every architecture except x86
> implements this approach (for example, AMD64 and ARM do, and IA64 did,
> etc.), and it would be the one that I would strongly recommend that you
> study first when learning about the NT exception handling model. In this
> model, the operating system looks up a function in its table of functions
> that support exception handling, and, if it finds a match, it can then
> learn what the language-specific exception handler for that function is,
> etc. The exception dispatcher and unwinder look up exception handling and
> unwinding information for each frame visited in this fashion.
>
> The AMD64 exception handling ABI is fairly well documented on MSDN (
> http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx), for suggested
> reading.
>
> On native x86, which is by far the odd-ball out, a somewhat different
> implementation is used. Ignoring later bolt-ons like SafeSEH for the
> moment, instead of a static description of exception handlers, the x86
> maintains a linked list of frames that participate in exception handling,
> the list head of which is in turn stored in a per-thread location
> (NT_TIB.ExceptionList, what Maxim alludes to below with fs:[0]). Frames
> participating in exception handling are logically pushed on to this list
> during frame establishment, and popped off during unwind or frame
> de-establishment. The unwinder implementation is minimalistic compared to
> other architectures as all registers except the frame pointer are
> considered volatile across an x86 unwind; at heart, it simply removes
> entries from the frame chain and invokes exception handlers as appropriate.
> The same high level SEH model is ultimately implemented, but in a
> different way.
>
>
> Again, this is only a high level overview and glosses over various details
> for more complicated edge conditions, for which there are other references
> available.
>
> - S (Msft)
> (Exception handling guy.)
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
> Sent: Monday, August 26, 2013 11:50 PM
> To: Windows System Software Devs Interest List
>
> Subject: Re:[ntdev] Exception Handling in Windows driver
>
> >determine the handler behaviour (like Linux’s page fault handler
> >compares the faulting PC against an exception table, to allow functions
> like copy_from_user to fault).
>
> Oh yes, Windows is similar.
>
> Each function which contrains __try has a hidden _SEH_Rec local var, which
> is a small structure.
>
> On function entrance, the _SEH_Rec is put to the top of their list, the
> current list head is kept at fs:[0] thread/processor local storage.
>
> Also, the _SEH_Rec has a pointer to this function’s constant table, which
> also has the address of the__except operator in the function.
>
> When exception occurs, the _SEH_Rec list is scanned and EIP is compared to
> each function’s constant table, and the matching one is executed. Then the
> filter expression (which is inside __except()) is executed, and then
> RtlUnwind.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>