          <<< NOTED::DISK$NOTES7:[NOTES$LIBRARY_7OF4]HACKERS.NOTE;1 >>>
                               -< ** Hackers ** >-
================================================================================
Note 1720.8             Image header layout on AXP needed                 8 of 8
IOSG::PYE "Graham - ALL-IN-1 Sorcerer's Apprentice" 320 lines  24-MAR-1995 05:40
                           -< @IMAGE Your_image.EXE >-
--------------------------------------------------------------------------------
$! Copyright (c) Digital Equipment Corporation 1995 - See end for details.
$ Saved_verify = f$verify( 0 )
$ if P1 .eqs. "" then -
      read sys$command/prompt="File name or Image List: " P1
$!
$! Hide any local symbols that could conflict with our globals, and get rid of
$! any verb definitions to avoid them causing errors with the way we use them.
$!
$ set symbol/general/scope=nolocal
$ set symbol/verb/scope=(nolocal,noglobal)
$ if .not. "''P2'" then -
      write sys$output "Working, please wait..."
$!
$! If we've been given a top level filename, then get its ISDs. Otherwise, we
$! should have been given a "|" separated list of shareable images to
$! sequentially analyse.
$!
$ if f$locate( "|",P1 ) .eq. f$length( P1 )
$ then
$     ISD_List == "|"
$     call Get_ISDs_from_image 'P1' "ISD_List" "" 'P2'
$     if ISD_list .eqs. "|"
$     then
$         write sys$output "No other images referenced!"
$         goto Exit
$     endif
$     Total_list = ISD_List
$   else
$     Total_list = P1
$ endif
$!
$! Now analyse each of the images in the Total_list, that we haven't so far
$! analysed.
$!
$ Total_list_done = 0
$Next_pass:
$ Total_list_index = 1
$ New_in_this_pass = ""
$Next_in_list:
$ File_name = f$element( Total_list_index,"|", -
                         f$extract( Total_list_done,999,Total_list ) )
$ if File_name .eqs. "|" then -
      goto Done_this_pass
$ if File_name .nes. ""
$ then
$     ISD_List == ""
$     call Get_ISDs_from_image 'File_name' "ISD_List" "Total_list" 'P2'
$     if ISD_List .nes. "" then -
          New_in_this_pass = New_in_this_pass + ISD_List
$ endif
$ Total_list_index = Total_list_index + 1
$ goto Next_in_list
$Done_this_pass:
$!
$! Check if we found any new images on this pass. If so, move the pointer
$! showing which images we've done to the current end of the the total list
$! and add the new images to the end of the total list. Then go round again.
$!
$ if New_in_this_pass .nes. ""
$ then
$     Total_list_done = f$length( Total_list ) - 1
$     Total_list = Total_list + New_in_this_pass
$     goto Next_pass
$ endif
$!
$! Now check that all the files in the total list exist and are $INSTALLed.
$!
$ Total_list_index = 1
$ FAO_String = "    !40AS   !AS         !AS"
$ write sys$output ""
$ write sys$output -
    "    File Name                                Exists  $INSTALLed"
$ write sys$output ""
$Next_check:
$ File_name = f$element( Total_list_index,"|",Total_list )
$ if File_name .eqs. "|" then -
      goto Done_check
$ if File_name .nes. ""
$ then
$     File_name = "SYS$SHARE:''File_name'.EXE"
$     if f$search( File_name ) .eqs. ""
$     then
$         Exists = "N"
$         Installed = ""
$       else
$         Exists = "Y"
$         if f$file_attributes( File_name,"KNOWN" )
$         then
$             Installed = "Y"
$           else
$             Installed = "N"
$         endif
$     endif
$     write sys$output f$fao( FAO_String,File_name,Exists,Installed )
$ endif
$ Total_list_index = Total_list_index + 1
$ goto Next_check
$Done_check:
$ write sys$output ""
$!
$Exit:
$ if f$type( ISD_List ) .nes. "" then -
      delete/symbol/global ISD_List
$!
$ Dummy = f$verify( 'Saved_verify' )
$ exit
$!
$!-----------------------------------------------------------------------------
$! Scan through the ISD in the header of an Image. Derived from pictures in VMS
$! Internals Book, VMSINSTAL, .H files in SYS$SHARE:SYS$LIB_C.TLB (apparently
$! only on Alpha) and examination of dumped images...
$!
$Get_ISDs_from_image: SUBROUTINE
$ on warning then goto Get_ISD_exit
$!
$ gosub Set_up_common_symbols
$!
$! The file name passed as P1 is probably in SYS$SHARE, but could also be a
$! logical. Fill in all the missing bits.
$!
$ Image_name = f$trnlnm( P1 )
$ if Image_name .eqs. "" then -
      Image_name = P1
$ if f$parse( Image_name,"MISSING:",,"DEVICE" ) .eqs. "MISSING:" then -
      Image_name = "SYS$SHARE:" + Image_name
$ if f$parse( Image_name,,,"TYPE" ) .eqs. "." then -
      Image_name = Image_name + ".EXE"
$ open/read/share/error=File_not_found Image_file 'Image_name'
$ if "''P4'" then -
      write sys$output "Analysing ''Image_name'"
$ read Image_file Record
$!
$! Decide if this is an Alpha or VAX image, using VMSINSTAL's test.
$!
$ if f$cvui( 0,'Word_bits',Record ) .lt. 48
$ then
$     Alpha_Image = "T"
$   else
$     Alpha_Image = "F"
$ endif
$!
$! Extract the header fields for the appropriate architecture.
$!
$ if Alpha_Image
$ then
$     gosub Set_up_Alpha_symbols
$!
$     ISD_offs = f$cvui( eihd$l_isdoff*'Byte_bits','Long_word_bits',Record )
$   else
$     gosub Set_up_VAX_symbols
$!
$     Header_size = f$cvui( ihd$w_size*'Byte_bits','Word_bits',Record )
$     ISD_offs = Header_size	! VAX ISDs start after Header.
$ endif
$!
$! Chain down the ISDs, starting at the offset specified in Alpha images, or
$! the end of the header on VAX. ISD_Offs is set appropriately earlier.
$!
$Next_ISD:
$ if Alpha_image
$ then
$     ISD_size = -
        f$cvui( (ISD_offs+eisd$l_eisdsize)*'Byte_bits','Long_word_bits',Record )
$   else
$     ISD_size = f$cvui( ISD_offs*'Byte_bits','Byte_bits',Record )
$ endif
$!
$! Check if we've got to the end of the ISDs, which is indicated by an ISD size
$! of zero.
$!
$ if ISD_size .eq. 0 then -
      goto Done_ISDs
$!
$! Now check for falling off the end of the block, which is indicated by an ISD
$! size of %XFF on VAX, and -1 (Really %XFFFFFFFF) on Alpha. If so, read
$! another block from the image. Reset the offset to the start of the new block.
$!
$ if (.not. Alpha_image .and. ISD_size .eq. %XFF) .or. -
     (Alpha_image .and. ISD_size .eq. %XFFFFFFFF)
$ then
$     read/error=Get_ISD_exit Image_file Record
$     ISD_offs = 0
$     goto Next_ISD
$ endif
$!
$! If it's a global ISD (i.e. bottom bit set in quadword ISD_flags), then
$! extract the name. Alpha images include a 'fake' global section called
$! SYS$BASE_IMAGE_001, so ignore that.
$!
$ if Alpha_image
$ then
$     if f$cvui( (ISD_offs+eisd$l_flags)*'Byte_bits',1,Record ) .eq. 1
$     then
$         ISD_name_len = -
            f$cvui( (ISD_offs+eisd$t_gblnam_count)*'Byte_bits', -
                    'Byte_bits',Record )
$         ISD_name = -
            f$extract( ISD_offs+eisd$t_gblnam_string,ISD_name_len,Record )
$         if f$extract( 0,15,ISD_name ) .eqs. "SYS$BASE_IMAGE_" then -
              ISD_name = ""
$       else
$         ISD_name = ""
$     endif
$   else
$     if f$cvui( (ISD_offs+isd$l_flags)*'Byte_bits',1,Record ) .eq. 1
$     then
$         ISD_name_len = -
            f$cvui( (ISD_offs+isd$t_gblnam_count)*'Byte_bits', -
                    'Byte_bits',Record )
$         ISD_name = f$extract( ISD_offs+isd$t_gblnam_string, -
                                ISD_name_len,Record )
$       else
$         ISD_name = ""
$     endif
$ endif
$!
$! If we got an ISD name, remove the "_001' suffix from it. Be careful to scan
$! the name backwards, since some image names contain underscores!
$!
$ if ISD_name .nes. ""
$ then
$     if f$locate( "_",ISD_name ) .ne. f$length( ISD_name )
$     then
$         Ptr = f$length( ISD_name )
$Next_underscore:
$         if f$extract( Ptr,1,ISD_Name ) .nes. "_"
$         then
$             Ptr = Ptr - 1
$             goto Next_underscore
$         endif
$         ISD_name = f$extract( 0,Ptr,ISD_name )
$     endif
$!
$! If we were passed a list of images we've already found, then check this one
$! isn't in that list. Return the new name in the global symbol passed in P2.
$!
$     if "''P3'" .eqs. ""
$     then
$         'P2' == 'P2' + ISD_name + "|"
$         if "''P4'" then -
              write sys$output "    ''ISD_name'"
$       else
$         if f$locate( "|''ISD_name'|",'P3' ) .eq. f$length( 'P3' )
$         then
$             'P2' == 'P2' + ISD_name + "|"
$             if "''P4'" then -
                  write sys$output "    ''ISD_name'"
$           else
$             if "''P4'" then -
                  write sys$output "    ''ISD_name'*"
$         endif
$     endif
$ endif
$!
$ ISD_offs = ISD_offs + ISD_size
$ goto Next_ISD
$Done_ISDs:
$!
$! Tidy up.
$!
$Get_ISD_exit:
$ if f$trnlnm( "Image_file" ) .nes. "" then close Image_file
$ exit
$File_not_found:
$ write sys$output "File ''Image_name' not found"
$ goto Get_ISD_exit
$!
$! GOSUB Subroutines
$!
$Set_up_common_symbols:
$!
$ Word_bytes = 2
$!
$ Byte_bits = 8
$ Word_bits = Word_bytes*Byte_bits
$ Long_word_bits = 32
$!
$ return
$!
$Set_up_Alpha_symbols:
$!
$! Alpha EIHD (Extended Image Header) symbols from EIHDDEF.H
$!
$ eihd$l_size = %X8		! Size in bytes of image header
$ eihd$l_isdoff = %XC		! Byte offset to ISD list
$!
$! Alpha EISD (Extended Image Section Descriptor) symbols from EISDDEF.H.
$!
$ eisd$l_eisdsize = %X8		! Size in bytes of this EISD.
$ eisd$l_flags = %X18		! Flags and ISD type.
$ eisd$t_gblnam_count = %X28	! Global name { counted
$ eisd$t_gblnam_string = %X29	!             {   string [44]
$!
$ return
$!
$Set_up_VAX_symbols:
$!
$! VAX IHD (Image Header) symbols from IHDDEF.H
$!
$ ihd$w_size = %X0		! Size in bytes of Image Header record.
$!
$! VAX EISD (Image Section Descriptor) symbols from ISDDEF.H.
$!
$ isd$w_size = %X0		! Size in bytes of this ISD.
$ isd$l_flags = %X8		! Flags and ISD type.
$ isd$t_gblnam_count = %X14	! Global name { counted
$ isd$t_gblnam_string = %X15	!             {   string [44]
$!
$ return
$ endsubroutine
$!
$! This procedure takes an image file name as a parameter, and analyses the
$! image to determine all the shareable images that it is linked against, and
$! all the images they link against, etc. It then checks that all the images
$! referenced exist in SYS$SHARE, and are $INSTALLed.
$!
$! Written by Graham Pye @REO
$!            ALL-IN-1 Engineering, Reading, England
$! March 1995.
$!
