1 Introduction

(This an Initial Draft)

In this article, I attempt to explore how Exception Handling (EH for
convenience) is implemented in the Mono Runtime. This I do by
considering a simple example assembly. As is customary, the
exploration would be limited to only those aspects of Exception
Handling that kicks in for the example under consideration.

2 Example Assembly

The method Test.Main () invokes ThrowException () within a protected
block. The protected block has a catch handler that swallows the
thrown exception and a finally handler that waits on user input
before exiting.

The property Test.Path and enum Test.MARKER are defined more for
convenience. The specific convenience they offer is –

The enum values of Test.Marker are ‘magical’. These magical
values would help us easily identify try, catch, finally blocks
in the generated native code.

The property Test.Path traces and logs the control flow.

Last but not the least, they help us have non-empty
try-catch-finally blocks.

Marshals a MonoContext struct that is representative of the
machine state at the point of exception. It then kicks off
exception handling via mono_handle_exception ().

Shortly we will examine handling of exceptions in detail. For now
it is sufficient to remark that the context struct is both an
‘in’ and an ‘out’ param of mono_handle_exception (). In essence
the exception handling mechanism examines the current machine
state and also advises a machine state for resumption of normal
control.

Restores the execution context to that advised by the EH
mechanism and transfers control to the new EIP address.

8 Code Generation for Try-Catch-Finally blocks

Before we proceed to look at specifics of exception handling
mechanism, let’s look at the native code generated for
Try-Catch-Finally block in Main ().

In method_to_ir (), a ‘leave’ instruction is translated in to zero
or more OP_CALL_HANDLER followed by an OP_BR. OP_CALL_HANDLER
arranges for a call to into the ‘finally’ block while OP_BR arranges
for control to flow out of the current SEHBlock.

In case of ‘leave’ instruction that occur within a catch handler,
prior to arranging for calling of ‘finally’ handlers as described
above the following special case handling for ThreadAbortException
is done – If the running thread has a ThreadAbortException pending,
it is rethrown immediately 2.

Furthermore, catch (and filter handlers) require an exception object
be passed in the event of an exception. These are passed via
specially allocated variables on the method stack.

9 Exception Handler Internals

Exception Handling is done in following passes –

Handler Identification Pass – In this pass, the runtime walks the
stack and tries to identify a block that is willing to handle the
exception.

Handler Invocation Pass – In this pass the runtime invokes fault
and finally handlers on all blocks that intervene between the
point at which the exception is thrown and the point at which the
exception is handled. Subsequently it transfers control to the
handler identified in part 1.

For the sake of completion, the pseudocode for Handler
Identification and Handler Invocation Passes is given below.

Before one proceeds to examine the pseudo code, it needs to be borne
in mind that the entries in a Method’s Exception Handler Table are
stored in such as way that a nested protected block always occurs
before any of it’s parent protected block.

The following specifics may be noted in the pseudo-code

Stack is merely walked.

In the Handler Identification Pass,

The exception object is passed to the filtering code by storing
it in a pre-defined location on the current stack frame.

The stack walk is terminated as soon as a catch or a filter
handler that is willing to handle the exception is identified.

Failure to locate a handler causes a FALSE to be returned.

In the Handler Invocation Pass,

The intervening finally and fault handlers are called via an
architecture specific stub – mono_arch_get_call_filter ()

Once the matching filter or catch handler is identified, the EIP
in ctx is adjusted to point to the handler address using the macro

MONO_CONTEXT_SET_IP (ctx, ei->handler_start)

The exception object is passed to the catch handler by storing it
in a pre-defined location on the current stack frame

As was earlier mentioned, it is the responsibility ofthrow_exception () to actually resume exception at the handler.