DST SCANNER 

Chris Chiesa (lvt-cfc@servtech.com) (formerly Chris_F_Chiesa@cup.portal.com)

    The collection of files accompanying this text, make up the "DST
Scanner" utility: when built, they produce three executable images whose
function is to scan an executable image and display, if the information
is available, the names of the source files which were compiled/assembled
and linked to form the image being scanned.  The baseline utility scans
a VAX or Alpha AXP VMS image and displays source file specifications only;
a modified, "details" version scans a VAX image (no corresponding Alpha AXP 
"details" version currently exists) and displays source file specifications
PLUS some RMS information (record/file organization, EOF position) associated 
with the source files.

    This utility does its job by reading the "target" executable image 
(.EXE) file, following the image's internal structure (Image Header, 
Debugger Symbol Table (DST), etc.), and extracting the desired information 
from one particular small subset of the information contained in the 
image's Debugger Symbol Table, or "DST," records.  Note that an image will 
contain DST records _only_ for those contributing source files which were 
compiled (or assembled) with the /DEBUG qualifier, and only if the image 
itself was linked with the /DEBUG qualifier.  

    Note that other software utilities exist which may interfere, or which 
you might worry MIGHT interfere, with the operation of the DST Scanner.  
The STABACCOP program used in creation of Standalone Backup sets on those 
systems which still support them, can be used to copy an executable image 
WITHOUT its Debug Symbol Table records; therefore, the DST Scanner will 
produce NO output upon scanning an image that was copied with STABACCOP.
On the other hand, numerous public-domain utilities exist which clear the
IHD$V_LNKDEBUG bit, and/or modify the transfer-vector array, in an image's 
header, in order to "disable" invocation of the VMS Debugger when executing 
an image which was compiled and linked with /DEBUG.  Use of such utilities 
will NOT prevent the DST Scanner from finding, and emitting, the desired 
information if it was present in the "original" form of the image.

   The format of DST records is "undocumented" by Digital, in addition to
being intricate and subject to change.  It is, however, explained fairly
thoroughly in the comments in the relevant section (DSTRECRDS.REQ) of the
VMS Source Listing, allowing the intrepid programmer to write DST Scanners
and such.  Just don't expect Digital to help you fix it if it breaks at the
next release of VMS! 

    This particular DST Scanner is actually quite minimal, compared to what 
it could be "in theory."  DST records embed a huge amount of information: 
routine names, other symbol names, sufficient information (file specification, 
RMS attributes, creation date, exact EOF position, and ODS-2 File ID) to 
uniquely identify each source file, and the complete source-line-to-instruc-
tion-address table necessary for the VMS Debugger to support source-level
Debugging -- just to name a few.  There are at least a dozen (maybe more) 
types of DST record, and several subrecord types within most of those!  From 
this wealth of information, this particular DST Scanner extracts *ONLY* the 
"source-file-specification strings" and, in the "details" version, RMS 
file-and-record type and EOF-position values.  It should be pretty clear from 
the source code for the "details" version, how to extend it to emit what YOU 
want it to emit -- at least from the "source-file correlation" type of DST 
record this code is designed to find-and-process
    
   There are a couple of other "limitations" -- if you want to call them 
that -- to this utility.  

   First, the DST Scanner outputs to SYS$OUTPUT -only-.  It would be fairly 
simple to add an /OUTPUT qualifier, but I've never gotten around to doing it; 
sorry again!  Fortunately, you can easily get around this limitation by 
defining logical name SYS$OUTPUT to a file _before_ invoking the DST Scanner. 
This comes in very handy as you'll see.

   Second, my experience shows that an image contains a "source-file 
correllation" DST record for EVERY instance of a source file which 
contributed to a /DEBUG compilation at some point in the building of the 
image.  For example, if you compiled several C source files, each of which 
included "hoohah.h," or included something else which included "hoohah.h," 
and then linked the resulting objects into a single executable image, then 
the DST Scanner would find, and display, "HOOHAH.H" several times, not just 
once.  HOOHAH.H would appear at least once for each object whose compilation 
involved "hoohah.h" at ANY point.  This can be a little annoying when 
trying to cross-reference the "raw" DST Scanner output stream to a minimal 
list of source files.  On the plus side, the multiple-occurrence behavior 
makes it easy to notice, for instance, that two different C modules used
two DIFFERENT versions of "hoohah.h" -- perhaps as a result of having been 
compiled at different times, across modifications of "hoohah.h" -- alerting 
you to a potential run-time problem without having to actually execute the 
image!  

   Third, the DST Scanner emits source file specifications in the order it 
encounters source-file-correlation DST records in the image, which seems to 
be a combination of the order in which the compiler encountered the source 
files, and the order in which the linker encountered the objects.  It is NOT 
alphabetical, and multiple appearances of a particular source file do NOT, 
as a rule, occur "in a row" but, rather, "scattered" throughout the image.  
This can make it tricky to find a particular source file you're looking for, 
but can be useful in determining the order in which the compilers and 
linker "put the image together," if you have reason to be concerned about 
it.

   Fourth -- and there's nothing I can do about this -- the DST Scanner can 
*only* find source file specifications if they're actually present, i.e. if 
DST records were generated at compilation/assembly time, and were preserved 
at link time.  It is not necessary that all objects linked into an image be 
compiled with the same /DEBUG (or /NODEBUG) state.  If any object contributing 
to the image was compiled without /DEBUG, no DST records were generated for 
that object, and thus the DST Scanner will NOT find any source-file 
information for that object.  And of course if the image was LINKED without 
/DEBUG, you won't see ANY source file specifications AT ALL because all DST 
records have been omitted from the image!

   The second and third limitations can both be overcome by first directing 
SYS$OUTPUT to a file, then invoking the DST Scanner, and then sorting the 
output file with SORT /NODUPLICATES.  That will give you a nice, tidy,
listing, in alphabetical order with each unique source file specification 
appearing exactly ONCE.

   But enough about that.  How do you build it, and then how do you USE it?

   To build the DST Scanner, first make sure all the files supplied with 
this package reside in the same directory.  Set your default directory to 
that directory and invoke the command procedure file BUILD_DST_SCANNERS.COM:

   $ @BUILD_DST_SCANNERS

This procedure will perform three essential operations:

   1) Define the logical name DSTDIR to point to the directory where the 
      DST Scanner package's files reside;

   2) Build a Macro library containing assembly-time macros necessary for 
      step 3, below;

   3) Assemble the Macro-32 source code for the DST Scanner, and link it to 
      form the DST Scanner executable images;

   4) Add a new DCL command, "DST", to the then-current process.

Note several things.

   First, the logical name DSTDIR must point, at assembly time, to the 
directory where the Macro LIBRARY (created in step 2) resides.  At run-time 
it must point to the directory where the DST Scanner executable images 
reside.  These NEED NOT be the SAME directory, but things will probably go
more smoothly if they ARE.

   Second, you'll note that I keep saying "DST Scanner executable IMAGES,"
plural.  The DST Scanner package "as shipped" consists of three executable 
images:

   VAX_DST_SCANNER.EXE - reads a VAX image, emits source filespecs ONLY

   VAX_DST_SCANNER_DETAILS - reads a VAX image, emits source filespecs AND
       "other details" -- RMS attributes and EOF position, as shipped, but
       is easily modified to emit, say, source-file creation date...

   AXP_DST_SCANNER - reads an Alpha AXP image, emits source filespecs ONLY

Which program gets run, depends on how you invoke the DST Scanner, which
depends on how you issue the DST command.  We'll get to that momentarily.
Note that ALL THREE of these programs can be built, and will run and do
what they're supposed to, under VAX/VMS (built/tested under V5.4-3) and
OpenVMS AXP (built/tested under (cringe) V1.5-1H1).  I -expect- them to be
buildable, executable, and usable under "all" versions of VMS, but like any
sane person I DON'T GUARANTEE it. 

   Third, logical name DSTDIR gets defined, and the DST command verb added 
to your DCL environment, automatically, _only_ when you invoke 
BUILD_DST_SCANNERS.COM.  Thereafter it's up to YOU to define the logical 
and add the DST command verb.  I'll discuss this further in a moment.

   So now that you've built the DST Scanner and have the command verb all 
ready to use, HOW do you USE it?  Like this:

   $ DST [qualifiers] image_filespec

   Qualifiers:

      /VAX

          Scan a VAX/VMS (OpenVMS VAX) executable image

      /AXP

          Scan an OpenVMS Alpha (AXP) executable image

      /DETAILS

          Display source-file RMS attributes and EOF position in addition
          to file specifications.   The /DETAILS qualifier is allowed only
          when scanning a VAX image.

   You can set up either /VAX or /AXP to be the default, as discussed 
below.

   The build-procedure BUILD_DST_SCANNERS.COM will define the logical name 
DSTDIR, and will add the DST command to your DCL environment.  However, the 
next time you log in you will have to define the logical name, and add the 
command verb, yourself.  

   Defining the logical name is done by using either the DEFINE or ASSIGN
command, like so:

       $ DEFINE DSTDIR directory_where_DST_Scanner_executables_reside
or

       $ ASSIGN directory_where_DST_Scanner_executables_reside DSTDIR

   Adding the DCL command verb is done by using either of the two .CLD 
files provided by this package, with the SET COMMAND command.  Assuming the 
.CLD files reside in the directory pointed to by the DSTDIR logical name, 
the command is either:

       $ SET COMMAND DSTDIR:VAX_DST.CLD
or

       $ SET COMMAND DSTDIR:AXP_DST.CLD

The only difference is that VAX_DST.CLD defines the DST command so that 
when no qualifiers are specified the default is /VAX, and that AXP_DST.CLD 
defines the command so that the default is /AXP.

   Consult your system documentation for information on how to provide the 
DST command on a system-wide basis, or to yourself automatically at login 
or in all processes.  

   This should be enough information for you to build and use the DST 
Scanner.  If it is not, you may contact me (at the time of this writing) on 
the Internet at lvt-cfc@servtech.com .  If that address ever ceases to work, 
hopefully you'll still be able to search the Usenet newsgroups for "Chris 
Chiesa" and find me.  :-)

    Chris Chiesa (lvt-cfc@servtech.com)
     September 19, 1996