From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 17-FEB-1991 09:12:02.90
To:	ARISIA::EVERHART
CC:	
Subj:	LIST_VECTORS.COM - VMS exploration tool

From:	RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP@CRDGW2
To:	Everhart@Arisia@MRGATE

Received:  by crdgw1.ge.com (5.57/GE 1.83)
	 id AA16828; Sun, 17 Feb 91 08:55:45 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Sun, 17 FEB 91 05:39:59 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA04087; Sun, 17 Feb 91 05:34:49 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 17 Feb 91 03:13:14 GMT
From: agate!bionet!uwm.edu!rpi!masscomp!peora!tarpit!osceola.cs.ucf.edu!morris@ucbvax.Berkeley.EDU  (Carl Morris)
Organization: University of Central Florida
Subject: LIST_VECTORS.COM - VMS exploration tool
Message-Id: <morris.666760394@eola.cs.ucf.edu>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


Hi folks,

Whilst exploring the new system calls available with VMS 5.4 I developed
this tool to list the names of the routines in the system service and
executive transfer vector tables.  For each named vector it lists the
S0 address of the vector, an educated guess at the calling mechanism
for the vector (CALL or JSB), and the name of the routine.  

This routine makes it easy to find out what's changed from version to 
version of VMS, just run this on both versions of VMS, then do a DIFF
on the listings produced.  Once you know what's different, you can go
explore it on your CD source listings (if that sort of thing appeals
to you).

I welcome any comments or suggestions for improvement, especially if
someone's got some good ideas for telling how each vector is supposed
to be called.  You can see my approach in the COMfile, but I'm almost
sure there's got to be a better way to do it... maybe some structure 
I'm missing?  Hmmm.

    "Hackers and bugchecks and crashdumps, oh my..." -- Carl Morris

morris@ucf-cs.ucf.edu  (or if that fails)
morris@eola.ucf.edu
------------------------- clip here -----------------------------------
$!
$! LIST_VECTORS.COM is a COMfile which produces lists of all the named
$!                  System Service and Executive Transfer vectors.  Each
$!                  list entry contains: the vector address, an educated
$!                  guess as to how the vector is called (JSB or CALL),
$!                  and the name of the routine.  This routine requires 
$!                  CMKRNL privilege in order to run SDA to gather data.
$!
$! Output:     SS_VECTOR.LIS - list of all System Service vectors.
$!             ET_VECTOR.LIS - list of all Executive Transfer vectors.
$!
$! Author:     Carl Morris
$!
$! Date:       15-Feb-1991
$!
$! Disclaimer: Use at your own risk, I do...
$!
$! Notes:      Tested under VMS 5.3, 5.4, 5.4-1.  Takes ~2 minutes elapsed
$!             time to run on a lightly loaded 8650.  Haven't figured out
$!             a good way to toss out "extra" vectors (e.g. EXE$GETJPIW_2)
$!             yet, so they get classified with all the REAL vectors.
$!
$!     Set offsets           SDA symbols for offsets
$!
$ ss_beg = %x80000000      ! SYS$S0_VECTOR_BASE
$ ss_end = %x80002000      ! SYS$S0_VECTOR_END
$!
$ et_beg = %x80002000      ! EXE$VECTOR_BASE
$ et_end = %x80004000      ! EXE$VECTOR_END
$!
$!     Check for priv required to run SDA
$!
$ if .not. f$privilege( "cmkrnl") then exit 10244
$!
$!     Get list of System Service vector names
$!
$ ss_purge_ok = f$search( "ss_vector.lis;*") .eqs. ""
$ call get_names ss_vector.lis 'ss_beg' 'ss_end'
$ call parse_names ss_vector.lis "System Service Vectors"
$ if ss_purge_ok then purge/nolog ss_vector.lis
$!
$!     Get list of Executive Transfer vector names
$!
$ et_purge_ok = f$search( "et_vector.lis;*") .eqs. ""
$ call get_names et_vector.lis 'et_beg' 'et_end'
$ call parse_names et_vector.lis "Executive Transfer Vectors"
$ if et_purge_ok then purge/nolog et_vector.lis
$!
$ exit
$!
$!
$!
$GET_NAMES: SUBROUTINE
$ output_file = p1                      ! name of output file
$ cur_address = 'p2'                    ! address to start with
$ end_address = 'p3'                    ! address to stop before
$!              
$ write sys$output "Getting ''f$extract( 0, 2, output_file)' vector names..."
$!
$ open/write out 'output_file'          ! make COMfile to run SDA
$ write out "$ assign/user nl: sys$output"
$ write out "$ analyze/system"
$ write out "set output ''output_file'"
$!
$GET_NAMES_LOOP1:                       ! do SDA> EVAL/SYM for each vector
$ write out f$fao( "evaluate/symbol !XL", cur_address)
$ cur_address = cur_address + 8
$ if cur_address .lt. end_address then goto get_names_loop1
$!
$ write out "exit"                      ! leave SDA
$ close out                             ! close COMfile
$!
$ @'output_file'                        ! execute COMfile
$!
$!     Get rid of the stuff we don't want.
$!
$ search 'output_file';-1/output='output_file' "Hex = "
$ search 'output_file';-1/output='output_file'/match=nand "+"
$!
$ open/read in 'output_file'            ! read list of named vectors
$ open/write out 'output_file'          ! make COMfile to run SDA
$ write out "$ assign/user nl: sys$output"
$ write out "$ analyze/system"
$ write out "set output ''output_file'"
$!
$GET_NAMES_LOOP2:                       ! SDA> SHOW SYM for all named vectors
$ read/end=end_get_names_loop2 in rec
$ if f$ext(40,31,rec) .eqs. "" then goto get_names_loop2
$ write out "show symbol ''f$ext(40,31,rec)'"
$ goto get_names_loop2
$END_GET_NAMES_LOOP2:
$!
$ close in                              ! close input
$ close out                             ! close COMfile
$!
$ @'output_file'                        ! execute COMfile
$!
$!     Get rid of the stuff we don't want.
$!
$ search 'output_file';-1/output='output_file' ":","="/match=and
$!
$!     The output file now contains a line with the output of
$!     the SDA> SHOW SYMBOL command for each named vector in the
$!     range specified.
$!
$ ENDSUBROUTINE
$!
$!
$!
$PARSE_NAMES: SUBROUTINE
$ filename = p1                         ! name of input/output file
$ title = p2                            ! title string for output file
$!
$ write sys$output "Parsing ''f$extract( 0, 2, filename)' vector names..."
$!
$ open/read in 'filename'               ! open input
$ open/write out 'filename'             ! open output & write header
$ write out "''title' - VMS ",f$getsyi( "node_swvers")
$ write out ""
$ write out "Vector   Call   Routine"
$ write out "Address  Type   Name"
$ write out "-------- -----  -------"
$!
$PARSE_NAMES_LOOP:                      ! parse each line & output it
$ read/end=end_parse_names_loop in rec  ! read next line of input
$ rec = f$edit( rec, "COMPRESS")        ! get rid of extra spaces
$!
$ vector_name = f$ele( 0, " ", rec)     ! get vector name
$ vector_addr = f$ele( 2, " ", rec)     ! get vector address
$ data = f$ele( 4, " ", rec)            ! get data at vector address
$!
$ opcode1 = f$ext( 6, 2, data)          ! opcode if you JSB to this vector
$ opcode2 = f$ext( 2, 2, data)          ! opcode if you CALL to this vector
$!
$ call = 0                              ! init call flag
$ jsb = 0                               ! init jsb flag
$!
$!     If opcode1 is XFC, then this is NOT a vector we JSB to, assume
$!     it's a CALLed vector and skip all other checks.  Many system
$!     services fit this case.
$!
$ if opcode1 .eqs. "FC" 
$ then 
$        call = 1
$        goto skip_call_checks
$ endif
$!
$!     See if opcode1 matches any of the common instructions we'd expect to
$!     find if we were JSBing to this vector.
$!
$ if opcode1 .eqs. "01" then jsb = 1    ! check for NOP
$ if opcode1 .eqs. "03" then jsb = 1    ! check for BPT
$ if opcode1 .eqs. "05" then jsb = 1    ! check for RSB
$ if opcode1 .eqs. "16" then jsb = 1    ! check for JSB
$ if opcode1 .eqs. "17" then jsb = 1    ! check for JMP
$ if opcode1 .eqs. "BC" then jsb = 1    ! check for CHMK
$ if opcode1 .eqs. "BD" then jsb = 1    ! check for CHME
$ if opcode1 .eqs. "DD" then jsb = 1    ! check for PUSHL
$ if opcode1 .eqs. "FA" then jsb = 1    ! check for CALLG
$ if opcode1 .eqs. "FB" then jsb = 1    ! check for CALLS
$!
$!     Vectors that are CALLed should not include R0 or R1 in the
$!     register save mask.  If either are present, skip the call
$!     checks.
$!
$ if %x'opcode1' .or. ( %x'opcode1' / 2) then goto skip_call_checks
$!
$!     See if opcode2 matches any of the common instructions we'd expect to
$!     find if we were CALLing this vector.
$!
$ if opcode2 .eqs. "01" then call = 1   ! check for NOP
$ if opcode2 .eqs. "01" then call = 1   ! check for NOP
$ if opcode2 .eqs. "04" then call = 1   ! check for RET
$ if opcode2 .eqs. "16" then call = 1   ! check for JSB
$ if opcode2 .eqs. "17" then call = 1   ! check for JMP
$ if opcode2 .eqs. "BC" then call = 1   ! check for CHMK
$ if opcode2 .eqs. "BD" then call = 1   ! check for CHME
$ if opcode2 .eqs. "DD" then call = 1   ! check for PUSHL
$ if opcode2 .eqs. "FA" then call = 1   ! check for CALLG
$ if opcode2 .eqs. "FB" then call = 1   ! check for CALLS
$!
$ if data .eqs. "FEFF0000" then call = 1! check for BUGW entered via CALL
$!
$SKIP_CALL_CHECKS:
$!
$!     Check call and jsb flags to see how we think this vector
$!     is supposed to be called.
$!
$ if (.not. jsb) .and. (.not. call) then call_type = "?     "
$ if (.not. jsb) .and.        call  then call_type = "CALL  "
$ if        jsb  .and. (.not. call) then call_type = "JSB   "
$ if        jsb  .and.        call  then call_type = "Ambig "
$!
$!     Output the address, call type, and routine name.
$!
$ write out "''vector_addr' ''call_type' ''vector_name'"
$!
$ goto parse_names_loop
$END_PARSE_NAMES_LOOP:
$!
$ close in                              ! close input
$ close out                             ! close output
$!
$ write sys$output ""
$ write sys$output "     ''filename' has been created"
$ write sys$output ""
$!
$ ENDSUBROUTINE
$!
---------------------------- yup, you got it all -------------------

