
Exceptq distribution notes
v7.11.3-shl

This is an updated build of Exceptq by Steven H. Levine.

This build is based on the v7.1 sources and reports itself as 7.11.2-shl

It is compatible with the v7.1 release and includes a number of fixes and
features.

This document is an addendum to the exceptq.txt and readme.exceptq documents
included in the 7.1 releases.

== Reminder ==

Exceptq is a DLL, so follows all the standard rules for DLL loading and
unloading.  This means that if Exceptq is already in use by some application
the loaded Exceptq DLL will be used unless you are using LIBPATHSTRICT to
override this behavior.  It also means that you will not be able to replace
the in-use version of exceptq.dll untill you close the applications that are
using it.  It also means that if you have multiple copies of exceptq
installed, the first one found in LIBPATH will be used.

To find out if Exceptq is in use and with copies is being used, run

  psfiles | find "EXCEPTQ"

from the command line.  If Exceptq is in use, the system file
information for exceptq.dll will be listed.  The fourth column is the
number of times Exceptq has been loaded.  If Exceptq is not in use, there
will be no output.

If you have used unlock to allow the DLL to be overwritten, the above will
not work.  You need to use Thesues and use the System->General
system->Modules menu option to display the module list.  Then use
Mark/Find->Find and search for EXCEPTQ.

After installing an exceptq update, it is a good idea to remove any other
copies of exceptq that you or others might have installed.  This prevents
surprises.

== Fixes ==

Exceptq has been updated to work more gracefully on SMP systems.

Exceptq.h has been updated to be compatible with more compiler toolchains.
It has been tested with VisualAge, gcc and OpenWatcom in C and C++ modes.  It 
also includes the INCL_LOADEXCEPTQ and INCL_LIBLOADEXCEPTQ enhancements that 
make the wrappers easier to use.

== Using .dbg .xqs and .sym files ==

As documented in exceptq.txt, Exceptq can use several forms of debug data to
label functions and variables included in the report.  Exceptq can use
embedded debug data, .dbg, .xqs, or .sym files.  If you are using .dbg, .xqs
or .sym files, Exceptq looks for these files in the directory that contains
the associated executable.  The debug data file must have the same base name
as the executable.  This is similar to how the OS/2 Trap Dump Facility
operates.

Exceptq searches for debug data in the following order:

  embedded debug data
  .dbg file
  .sym file
  .xqs file

Embedded debug data is generated by the compiler linker.  .dbg files are
embedded debug data extracted from the executable a written to a file by a
tool such as lxlite or copydbg. .xqs files are generated from .map files by
mapxql which ships with the exceptq distibution.  .sym files are generated by
mapsym, which ships with the Warp4 toolkit.

Note that the above file naming scheme is amibiguous if an application has a
DLL with the same base name as some EXE and the EXEs and DLLs are installed
to the same directory.  It is recommended that developers avoid doing this.

Note also that by default OpenWatcom uses the .sym extension to identify
files containing debug data.  These are not the same as mapsym .sym files.
Use the wlink option symfile directive to override the default naming.

== New Features ==

Exceptq supports several new load time options.  These are described below in
"New Exceptq Options."

Exceptq now reports the date, time and size of each accessible DLL.

Formatting based on embedded debug data has been enhanced to show function
offsets similar to the formatting based on .xqs and .sym files.

Exceptq now reports the cs:eip address of the secondary exception if it is
reentered while processing an exception.  The report will indicate whether
Exceptq itself trapped or if the reentry occurred for some other reason.

There are times when the Exceptq report is not sufficient to resolve an
issue and the application or compiler runtime behavior prevents process dump
files from getting written. The Modula runtime is an example of such a
runtime.  There are new options that provide methods for bypassing
the default behavior and generating a process dump file.

Exceptq now supports the EXCEPTQDIR environment variable.  This variable, if
set, will cause exceptq to write all .trp files to the named directory. It
is the user's responsibility to ensure the directory exists and is writable.

== New Exceptq Options ==

-- R - Remove Handler --

Exceptq can now optionally remove the most recently installed exception
handler before installing the Exceptq handler.  To enable this feature add
"R" to the InstallExceptq options string or the EXCEPTQ environment
variable.

-- U - Dump process --

Exceptq can now optionally invoke DosDumpProcess after the .trp file is
generated.  To enable this feature add "U" to the InstallExceptq options
string or the EXCEPTQ environment variable.

The Remove Handler (i.e. "R") option is the preferred option, when there is a
choice. The dump will be generated with less chance of affecting the recorded
system state. The Dump option is preferred if the application exception
handler must run to ensure that required cleanup is performed.

-- Z - Report normal terminations --

Exceptq can now optionally generate .trp files for normal thread and process
terminations and signal exceptions.  This is useful if a thread or process
terminates unexpectedly. To enable this feature add "Z" to the InstallExceptq
options string or the EXCEPTQ environment variable.

-- 3 - Force 32-bit stack --

Under some conditions, Exceptq will dump a 32-bit stack in 16-bit format.
This occurs most often for the "Z" option.  If this occurs use the "3"
option to force Exceptq to format the stack in 32-bit format.

== Using UninstallExceptq ==

There have been some questions on when UninstallExceptq is required.  Some of
the existing docs say the it should be called before exiting from main or
from a thread procedure that installs an exception handler.  It is probably
better said that UninstallExceptq must be called before the stack
frame that contains the Exception Registration Record goes out of scope.

The kernel exception handler logic attempts to avoid calling exception
handlers that are no longer in scope, but it can be fooled if the
registration record appears to be in scope.  This can happen if subsequent
function calls use sufficient stack space.

In practice this means that if your function or thread procedure exits with
an explicit or implicit return, you must call UninstallExceptq before
returning.  If your function or thread procedure terminates by calling exit
or _endthread, you should not call UninstallExceptq because the Exception
Registration Record will stay in scope until the runtime calls DosExit.

The benefit of leaving the exception handler installed is that if an
exception does occur during exit or _endthread processing, exceptq will, in
most cases, be able to generate a useful report.

== Using ExceptionInfo with EXCEPTQ_DEBUG_EXCEPTION ==

When using DosRaiseException to signal an EXCEPTQ_DEBUG_EXCEPTION exception,
Exceptq can accept to types of data in the ExceptionInfo array.

If ExceptionInfo[0] is non-zero, Exceptq assumes is a pointer to a printf
style format string and that any additional ExceptionInfo array elements are
arguments for the format string.

If ExceptionInfo[0] is zero, Exceptq assumes that any additional
ExceptionInfo array elements are raw data and they are displayed in decimal
and hexadecimal.

== Configuring exceptq.h ==

The definitive documentation for exceptq.h is in exceptq.h itself.

To support alternate use cases, exceptq.h supports a number of optional macros:

  INCL_LOADEXCEPTQ     Define LoadExceptq() helper function
  INCL_LIBLOADEXCEPTQ  Define LibLoadExceptq() helper function
  INCL_EXCEPTQ_CLASS   Define ScopedExceptqLoader C++ class
  INCL_EXECPTQ_INLINE  Declare LoadExceptq or LibLoadExceptq inline
  INCL_FORKEXCEPTQ     Notify exceptq that gcc fork() will be used
  INCL_EXCEPTQ16       Declare SETEXCEPT() and UNSETEXCEPT() 16-bit entry points

To use one of these macros, #define the macro before the exceptq.h #include.

What follows is a guide to help you decide which if any of these optional macros
is appropriate for your code.

As Rich discusses in his exceptq.txt, all that is required to add exceptq
support to most applications is to add

  #define INCL_LOADEXCEPTQ
  #include "exceptq.h"

after #include <os2.h> and define

  EXCEPTIONREGISTRATIONRECORD exRegRec;

as a local variable in your main() and call

  LoadExceptq(&exRegRec, "I", "MyApp v1.0.2");

to install the exceptq exception handler and call

  UninstallExceptq(&exRegRec);

before returning from the main() function.  If you call exit() before returning
from the main() function, you can omit the UninstallExceptq() call.

If your C language application consists of multiple source files, #define INCL_LOADEXCEPTQ
in only one source file or #define INCL_EXECPTQ_INLINE to define LoadExceptq as inline.
Otherwise, the linker will complain about multiple definitions of LoadExceptq().

If your application is multi-threaded, be sure to call LoadExceptq() in each thread and call
UninstallExceptq() before returning from the thread function.  If you call _endthread()
to terminate the thread, you can omit the UninstallExceptq() call.

As discussed above, INCL_LOADEXCEPTQ defines the LoadExceptq() helper function
which saves you from having to write and debug your own.

If you are adding exceptq support to your DLL, you may wish to define
INCL_LIBLOADEXCEPTQ rather than INCL_LOADEXCEPTQ.  INCL_LIBLOADEXCEPTQ
defines the LibLoadExceptq helper function.  LibLoadExceptq() differs from
LoadExceptq() in that it installs the exceptq exception handler only if the
application has already loaded exceptq for its own exception handling.

Using LibLoadExceptq() is similar to using LoadExceptq(). Add

  #define INCL_LIBLOADEXCEPTQ
  #include "exceptq.h"

after #include <os2.h> and define

  EXCEPTIONREGISTRATIONRECORD exRegRec;

as a local variable in your thread function and call

  LibLoadExceptq(&exRegRec);

to install the exceptq exception handler and call

  UninstallExceptq(&exRegRec);

before returning from the thread function.  If you call _endthread() before returning
from the thread function, you can omit the UninstallExceptq() call.

If are writing C++ code, you should consider defining INCL_EXCEPTQ_CLASS.
This macro will declare either the ScopedExceptqLoader helper class if
INCL_LOADEXCEPTQ is defined or the ScopedExceptqLibLoader helper class if
INCL_LIBLOADEXCEPTQ is defined. These helper classes make adding exceptq
support to a C++ even easier because the class ensures that the exceptq
handler is loaded and uninstalled at the right time.

To use the helper class in your application, define

  ScopedExceptqLoader sel;

in the local variables of your main() function and in any thread functions.

If you want to pass parameters to LoadExceptq from your main() function, pass 
them to the constructor with:

  ScopedExceptqLoader sel(NULL, "Hello world v0.1");

If using INCL_LIBLOADEXCEPTQ, define

  ScopedExceptqLibLoader sel;

in the local variables of your thread functions.

INCL_EXECPTQ_INLINE allows you to define the LoadExceptq or LibLoadExceptq
helper functions as inline functions for our C application.  This is the
default for C++ applications.

You must define INCL_FORKEXCEPTQ if your gcc application is using kLIBC's fork().

If you want to add exceptq support to a 16-bit application, define
INCL_EXCEPTQ16 to declare the 16-bit entry points.

== Known Issues ==

Exceptq is not yet fully SMP capable.  If Exceptq is reentered for an
exception in another thread, the exception address will be reported to
stderr and there will be no trp file generated for the second exception.

== Distributions ==

There are two types of distributions.  Basic and full.  Basic distributions
contain everything needed to use exceptq or to add exceptq support to an
application.  Full distributions add the source code needed to build and test
exceptq and the related applications.

Basic distributions are named exceptq-7.11.2-shl-YYYY-MM-DD.zip where
YYYY-MM-DD is the date the distribtion was assembled.

Full distributions are named exceptq-7.11.2-full-shl-YYYY-MM-DD.zip where
YYYY-MM-DD is the date the distribtion was assembled.

Basic distributions contain the following directories

 \              Contains documentation
   bin          Contains executables useful to developers
   dll          Contains exceptq.dll distorm.dll and associated files
   include      Contains include files used by developers
   lib          Contains lib files used by developers
   tests        Contains exceptq installation validation tests

Full distributions contain the following directories

 \              Contains documentation
   bin          Contains executables useful to developers
   distorm-src  Contains distorm.dll source code and build tools
   dll          Contains exceptq.dll and associated files
   include      Contains include files for developers
   lib          Contains lib files used by developers
   exceptq-src  Contains the exceptq.dll source code and build tools
   mapxql-src   Contains the mapxql.exe source code and build tools
   legacy-src   Contains legacy source code, validation tools and build tools
   tests        Contains exceptq installation validation tests

End users only need to install the .dll and .xqs files in the dll
subdirectory to a directory in the LIBPATH.

Developers will need to install the contents of the include and lib
directories into the appropriate directories in their development
environment.

$Id: exceptq-shl.txt,v 1.2 2015/08/30 04:32:43 Steven Exp $
