### Exception Information Provided by OS/2

When an exception occurs, OS/2 provides data in structures that are arguments to the exception handler.

- _EXCEPTIONREPORTRECORD contains the exception number and how it occurred.
- CONTEXTRECORD describes the machine state of the thread.

_EXCEPTIONREPORTRECORD
This structure is defined in IBMCXXO\os2\bsexcpt.h as follows:

>     struct _EXCEPTIONREPORTRECORD
>     {
>        ULONG ExceptionNum;
>        ULONG fHandlerFlags;
>        struct _EXCEPTIONREPORTRECORD *NestedERR;
>        PVOID ExceptionAddress;
>        ULONG cParameters;
>        ULONG ExceptionInfo[EXCEPTION_MAXIMUM_PARAMETERS];
>     };

The fields in _EXCEPTIONREPORTRECORD provide the following information:

ExceptionNum
The exception number. You can encounter the exceptions in the table below only by using an OS/2 exception handler. This is because the IBM C and C++ Compilers default handler passes them to the operating system to handle.

Exception | Description
--- | ---
XCPT_PROCESS_TERMINATE | Indicates that the current thread has called DosExit, and the process is about to end. Until your exception handler ends, the thread continues as though DosExit had not been called.
XCPT_ASYNC_PROCESS_TERMINATE | Indicates that some other thread in the process has called DosExit and that your current thread is about to end also. You can decide to continue running the current thread and return the exception as handled.
XCPT_ACCESS_VIOLATION | Indicates an invalid attempt was made to access memory (similar to the SIGSEGV signal). When this exception occurs, the ExceptionInfo field provides the address that generated the exception and the type of access that was attempted (read or write).
XCPT_GUARD_PAGE_VIOLATION | Indicates that the current thread tried to access a memory page marked as a guard page. Usually it means that your application has accessed a guard page on the stack. In most cases, you will probably pass the exception to the operating system, which will allocate another 4K of committed memory for your thread and a new guard page. The operating system requires about 1.5K to place the information about the exception on the stack and then call the exception handler. If you know you are running out of stack space, you may want to end your process.
XCPT_UNABLE_TO_GROW_STACK | Indicates that the operating system tried to move your guard page, but no memory remained on the stack. If you suppressed stack probe generation by building with /Gs-, there may not be enough stack for you to even receive the exception, in which case your process terminates with an operating system trap.
A user-defined exception | You can also use the OS/2 API DosRaiseException to create and raise your own exceptions that you can then handle with your own exception handler.

fHandlerFlags
How the exception occurred and what you can do to handle it. It includes the following bits:

Bit | Description
--- | ---
EH_NONCONTINUABLE | You cannot continue running the thread once you leave the exception handler. If you try to return XCPT_CONTINUE_EXECUTION, an error is generated. You cannot reset the bit. However, you can intentionally set the bit to make an exception noncontinuable.
EH_UNWINDING | A longjmp has been done over this exception handler and the handler is to be deregistered. If your function uses a mutex semaphore, you should release it when you receive this exception.
EH_EXIT_UNWIND | A DosExit call has been made and the exception has been passed back to the operating system. This exception gives you an opportunity to take action before your exception handler is deregistered.
EH_NESTED_CALL | An exception occurred while another exception was being handled. This situation should be handled carefully: each exception requires about 1.5K of stack, so if you nest exceptions too deep you could run out of stack .

_EXCEPTIONREPORTRECORD *NestedERR
If a nested exception occurs, the information about the exception is found in this structure.

ExceptionAddress
This field contains the instruction address where the exception occurred. Typically, you cannot determine at run time which function caused the problem.

cParameters
This field contains the number of bytes of information.

ExceptionInfo
For some exceptions, this field may contain additional information. For example, if XCPT_ACCESS_VIOLATION occurs, it contains the address at which the memory access failed.

CONTEXTRECORD
This structure contains information about the machine state of the thread. It is generally of limited use to a high-level programmer because to continue a process after a synchronous exception, you must modify the CONTEXTRECORD, and it is extremely difficult to ensure the exception handler code is correct for all possible conditions. You should modify the CONTEXTRECORD only if you have no other alternative to correct your program.

You can use the CONTEXTRECORD to trace the stack and produce useful debugging information. However there are limitations:

- Because the IBM C and C++ Compilers and operating system calling conventions preserve some registers across calls, you cannot reconstruct the registers by traversing the stack to recover from the exception.
- If your code is optimized or the stack is damaged, you may not be able to trace the EBP chain.
- You cannot trace over calls to inlined functions or 16-bit calls.

Here is how the 32-bit stack usually looks:

Signals and Exceptions
Signal and Exception Handling
How OS/2 Chains Exception Handlers

Prototype of an OS/2 Exception Handler
Example of an OS/2 Exception Handler