StackWalker 1.0:  Delphi 2.0 debugger helper.
Copyright (c) 1996, D.J. Murdoch


  These units (STAKWALK and STAKLOW) help with the problem of exceptions
  occurring in the run-time library in Borland's Delphi 2.0:  the
  debugger often can't find where in your code the error was triggered.

  The problem is that when an exception occurs, the debugger tries to
  walk up the stack until it finds a return address in your source code.
  However, sometimes it can't walk up the stack, and so it can't find
  the error.  (This might be related to whether you have stack frames
  turned on, but sometimes doing that is not enough.)

  What I did to fix this in StackWalker was to install an exception
  handler that would look at *every* value on the stack, trying to find
  one that appears to be a return address to code with source.  It does
  this by reading the .MAP file to figure out source addresses, and then
  just comparing everything on the stack to those until it turns
  something up.

  This procedure is definitely not bulletproof.  There are lots of
  reasons to have addresses on the stack that aren't return addresses;
  if you do, StackWalker will give false messages.  However, getting a
  few false addresses mixed in with the real ones is better than getting no
  information at all.

  To use it:

  1. Set the detailed map file linker option on.  This is in the
     Project|Options|Linker page.  StackWalker uses the .MAP file to
     figure out what return addresses correspond to code. If it can't
     find the .MAP file in the same directory as the executable, or
     can't find the line number records in the .MAP file, it gives a
     warning and makes wild guesses, which give so many false alarms
     that it'll soon convince you to generate the .MAP file.

  2. Set the $D+ option on for every unit where you want to see the
     errors.  StackWalker won't show addresses in units compiled $D-
     (unless you forgot to make the .MAP file).

  3. Link one of the StackWalker units into your code.  There are 2 ways
     to do this:
     a) If you've got a regular Delphi application, then add
        StakWalk to the project.  It will automatically install all the
        hooks to get things working.
  OR b) In a console mode application or other application that doesn't
        use VCL, add StakLow to the project or to a Uses clause
        somewhere. It will install itself as the default exception
        handler.  (This doesn't work in a VCL application, because the
        default handler never gets called.) You won't get the helpful
        dialog that StakWalk gives you, but it should still give you the
        same information.

        If you have your own default exception handler, you might find
        that StakLow messes it up, or doesn't get activated.  But if
        you've got your own exception handler, you're probably clever
        enough to figure out how to fix this kind of problem.

  4. Compile and run your program and do whatever it is that triggers
     the exception.  After the usual unhelpful message pops up telling
     you that an exception happened somewhere (but not telling you
     where), hit F9 to continue running.  At this point StackWalker will
     examine the stack and trigger an exception at every place it thinks
     might be in the call stack.  (You'll likely get a few false alarms.
     If there was a foolproof way to do this, Delphi would do it
     itself).

  5. When you've found the place that really caused the trouble, click
     Cancel in the StackWalker dialog (or manually change the value of
     the global variable StopWalker to True) to stop it from walking
     all the way back up the stack.  If you don't do this and let it go
     too far, it'll eventually trigger an exception at the
     "Application.Run" line.  If you keep going past that, you may find
     weird behaviour (e.g. I found once that StackWalker got turned off
     for no apparent reason); I think by that point your program may be
     messed up, so be careful.

  You can have a little more control over the behaviour by manually
  setting some of the global variables in the StakLow unit:

    WalkerActive: set this to False when you don't need the
     special handling for future exceptions.

    StopWalker:  set this to True to stop the current walk.

    ContinueFunc:  assign a boolean function to this variable, to
     replace StakWalk's dialog.  It will be called just before the
     exception is triggered, and should return true if you want
     another debug exception generated.


  You can also make a call to WalkStack at any time to trigger a walk
  through the stack.

BUGS:

  For reasons I don't understand and don't know how to fix, floating
  point exceptions sometimes mess up StackWalker.  You'll just get the
  regular exception message over and over again, and never find out
  where it was triggered.  If you know how to fix this, please tell me.

FILES:

  This package contains the following files:

    STAKWALK.TXT:   This doc file.
    STAKWALK.PAS:   The high level unit to use to turn on StackWalker.
    STAKWALK.DFM:   The form file for the StackWalker dialog.
    STAKLOW.PAS:    The low level unit used by STAKWALK, or directly if
                    you don't use VCL.
    PROJECT1.DPR, UNIT1.PAS, UNIT1.DFM:   A simple demonstration project.

RELEASE HISTORY:

  Version 0.1:  Initial release
          0.2:  Forced optimization off in StakLow, so test for stack
                doesn't get optimized away
          0.3:  Added check for debugger, so you can distribute code to
                testers but not have the dialog pop up except when they're
                debugging.
          1.0:  First public release; same as 0.3.

LICENSE:

  StackWalker is not public domain code.  Its copyright belongs to
  Duncan Murdoch.  You are licensed to use it at no charge, but may not
  sell it or incorporate it into another product without prior written
  permission.  You may not charge more than $1 for the distribution of
  StackWalker.  You may include it in a CDROM compilation provided you
  charge no more than $1 per package in the compilation.  As a courtesy,
  I would appreciate receiving a copy of any CDROM that includes it, but
  this is not a legal requirement.

  I do not offer any guarantee or support for StackWalker.  It works at
  a low level, and there may well be conditions that cause it to crash
  your program, Delphi, or Windows.

  If StackWalker helps you so much that you want to show your
  appreciation in a monetary way, you may send a contribution in any
  amount to

    D.J. Murdoch
    337 Willingdon Ave.
    Kingston, Ontario, Canada
    K7L 4J3

  For contributions of $20 (US or Canadian) or more, I'll send you a
  diskette containing the latest version of StackWalker and a collection
  of other utilities that I've written.  Please make payments by US
  dollar cheque drawn on a US bank, Canadian dollar cheque drawn on a
  Canadian bank, or pounds Stirling cheque drawn on a UK bank
  (equivalent to $20 US, if you want the diskette). Unfortunately, I
  can't accept credit cards to handle payments from people from other
  countries.  However, I do have an arrangement with the Public Software
  Library to accept shareware registrations for various programs by
  credit card, and some of those will get you the disk;  write to me for
  details.

    Duncan Murdoch
    dmurdoch@mast.queensu.ca
