Author Topic: Structured Exception Handling  (Read 10007 times)

Offline Borneq

  • Jr. Member
  • *
  • Posts: 26
Structured Exception Handling
« on: December 13, 2012, 12:31:57 PM »
I write simple code to handling with SEH. First I install handler, next whern handle is called, it change IP to safe place - usually finally part.
Code: [Select]
   mov esi, [argv(.pContext)]
   mov edi, [argv(.pErr)]
   mov ebx, [edi+ERR.safe_place]
   mov [esi+CONTEXT.Eip],ebx
ERR structure (is anywhere defined in .inc?) I augment by "safe_place" field:
Code: [Select]
NASMX_STRUC ERR
    NASMX_RESERVE prev,        uint32_t, 1
    NASMX_RESERVE handler,     uint32_t, 1
    NASMX_RESERVE safe_place,  uint32_t, 1
NASMX_ENDSTRUC
It works, but I don't know how handle nested try-catch statement in one function, for instance:
Code: [Select]
void Function1( void )
{
    // Set up 3 nested _try levels (thereby forcing 3 scopetable entries)
    _try
    {
        _try
        {
            _try
            {
                WalkSEHFrames();    // Now show all the exception frames
            }
            _except( EXCEPTION_CONTINUE_SEARCH )
            {
            }
        }
        _except( EXCEPTION_CONTINUE_SEARCH )
        {
        }
    }
    _except( EXCEPTION_CONTINUE_SEARCH )
    {
    }
}

Offline Borneq

  • Jr. Member
  • *
  • Posts: 26
Re: Structured Exception Handling
« Reply #1 on: December 13, 2012, 01:27:28 PM »
How raise/throw exception? When to use RtlUnwind?

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Structured Exception Handling
« Reply #2 on: December 14, 2012, 01:57:11 AM »
We create try blocks in much the same way we create procedure blocks. We create what is known as a "Frame". Basically the frame is setup and undone around whatever code we wish to protect. This allows values to be specific to that frame (like our local variables and procedure arguments, in this case it's our ERR structure.

The following is an untested attempt at translating your Function1 procedure. It should be commented well enough to follow.

Code: [Select]
Function1:
;// Set up 3 nested _try levels (thereby forcing 3 scopetable entries)

; Beginning of first _try
push dword .End_of_First_Frame
push dword .EXCEPTION_HANDLER_A
push dword [fs:0]
mov [fs:0], esp

;_try {

; Beginning of second _try
push dword .End_of_Second_Frame
push dword .EXCEPTION_HANDLER_B
push dword [fs:0]
mov [fs:0], esp

;_try {

; Beginning of third _try
push dword .End_of_Third_Frame
push dword .EXCEPTION_HANDLER_C
push dword [fs:0]
mov [fs:0], esp

;_try {

;WalkSEHFrames();    // Now show all the exception frames
call WalkSEHFrames

;}

; End of third _try
jmp .End_of_Third_Frame

.EXCEPTION_HANDLER_C:
;_except( EXCEPTION_CONTINUE_SEARCH ) {

;}
ret

.End_of_Third_Frame:
pop [fs:0]
add esp, 4
;}

; End of second _try
jmp .End_of_Second_Frame

.EXCEPTION_HANDLER_B:
;_except( EXCEPTION_CONTINUE_SEARCH ) {

;}
ret

.End_of_Second_Frame:
pop [fs:0]
add esp, 4
;}

; End of first _try
jmp .End_of_First_Frame

.EXCEPTION_HANDLER_A:
;_except( EXCEPTION_CONTINUE_SEARCH ) {

;}
ret

.End_of_First_Frame:

pop [fs:0]
add esp, 4

; This is the unprotected end of our Function1 procedure.

ret

How raise/throw exception?

Various system events will throw exceptions (divide by zero, int3, etc) There should be an OS dependent call to raise an exception (eg. RaiseException)

When to use RtlUnwind?

Keep reading a little further.

Quote from: Jeremy Gordon
Here as each function is called things are PUSHed onto the stack: firstly the return address, then local data, and then the exception handler (this is the "ERR" structure referred to earlier).
Then suppose that an exception occurs in Function C. As we have seen, the system will cause a walk of the handler chain. Handler 3 will be called first. Suppose Handler 3 does not deal with the exception (returning EAX=1), then Handler 2 will be called. Suppose Handler 2 also returns EAX=1 so that Handler 1 is called. If Handler 1 deals with the exception, it may need to cause a clear-up using local data in the stack frames created by Functions B and C.
It can do so by causing an Unwind.

EDIT: Fixed tabs in example code.
« Last Edit: December 14, 2012, 02:37:26 AM by Bryant Keller »

About Bryant Keller
bkeller@about.me