EXCEPTION HANDLING

Here's how OZONE handles exceptions:

  1. hardware detects an exception (like divide-by-zero or general protection)
  2. hardware calls exception handler in kernel (oz_kernel_486.s)
  3. exception handler builds 'machine arguments' on stack. The machine arguments are a machine-dependent representation of the machine state at the time of the exception. It contains stuff like the registers and any parameters pushed on the stack by the hardware to describe the exception.
  4. exception handler builds 'signal arguments' on stack. This is a machine- independent description of the exception. Like for an access violation, it would have the faulting virtual address and the type of access (read or write). It also has a machine-independent error code saying what the exception was.
  5. If in kernel mode and hw int delivery inhibited or its a single step/breakpoint, just call debugger
  6. Otherwise, find an active condition handler and call it. If none present, call the default handler, which for kernel mode, is the debugger, for user mode, it prints a stack dump and exits.

Here's how OZONE finds the active condition handler:

The routine that wants to trap an exception calls routine oz_sys_condhand_try:

        status = oz_sys_condhand_try (routine_to_try, param_to_pass_to_it, catch_routine, param_for_it)

          Input:

            routine_to_try = entrypoint of routine that oz_sys_condhand_try is 
                             to call under the protection of a condition handler
            param_to_pass_to_it = parameter (void *) to pass to routine_to_try
            catch_routine = entrypoint of routine to call if there is an 
                            exception while routine_to_try is active
            param_for_it = parameter (void *) to pass to catch_routine

          Output:

            status = value returned by routine_to_try or, if an 
                     exception occurred, as returned by catch_routine

      routine_to_try is called by oz_sys_condhand_try thusly:

        status = routine_to_try (param_to_pass_to_it)

      catch_routine is called by the kernel if there is an exception thusly:

        status = catch_routine (param_for_it, OZ_Sigargs *sigargs, OZ_Mchargs *mchargs)

          Input:

            param_for_it = as passed to oz_sys_condhand_try
            sigargs = points to signal arguments array
            mchargs = points to machine arguments struct

          Output:

            status = OZ_RESIGNAL : this condition handler can't handle the condition, 
                                   resignal the exception to an outer level handler
                       OZ_RESUME : the state causing the exception has been corrected, 
                                   resume processing at the point of the exception
                            else : unwind the call stack (ie, longjmp) and return this 
                                   status value to caller of oz_sys_condhand_try

The oz_sys_condhand_try routine makes a 'burp' in the call frames on the stack. Then, when an exception handler goes to look for a condition handler, it will see the burp in the call frames and it will know there is a condition handler there.

A normal call frame looks like:

         +---------------------------------+
         |               .                 |
         |               .                 |
         |               .                 |
         |  subroutine call arguments      |
         +---------------------------------+
         |  return address                 |
         +---------------------------------+
         |  saved %ebp                     |  <- %ebp
         +---------------------------------+
         |               .                 |
         |               .                 |
         |               .                 |
         |  local variables                |
         +---------------------------------+
         |  optional saved %ebx,%esi,%edi  |
         +---------------------------------+
A 'burped' call frame looks like:
         +---------------------------------+
         |  param_for_it                   |
         +---------------------------------+
         |  catch_routine                  |
         +---------------------------------+
         |  param_to_pass_to_it            |
         +---------------------------------+
         |  routine_to_try                 |
         +---------------------------------+
         |  return address                 |
         +---------------------------------+
         |  saved %ebp                     |
         +---------------------------------+
         |  burp flag value                |  <- %ebp during oz_sys_condhand_try routine
         +---------------------------------+
         |  saved %ebx,%esi,%edi           |
         +---------------------------------+
The burp flag has the value:

Notes: