From:	CSBVAX::CSBVAX::MRGATE::"SMTP::VAXMFG.TECH.NWU.EDU::CHOJNACKI"  2-MAR-1989 21:54
To:	MRGATE::"ARISIA::EVERHART"
Subj:	March 2 UNMACRO source 1/8


Received: from vaxmfg.tech.nwu.edu by accuvax.nwu.edu id aa11007;
          2 Mar 89 9:59 CST
Date: Thu, 2 Mar 89 10:11 CST
From: Bob Chojnacki <CHOJNACKI@vaxmfg.tech.nwu.edu>
Subject: March 2 UNMACRO source 1/8
To: EVERHART%ARISIA.decnet@ge-crd.arpa
X-VMS-To: IN%"EVERHART%ARISIA.decnet@ge-crd.arpa"
Message-ID:  <8903020959.aa11007@accuvax.nwu.edu>

$! ...................... Cut between dotted lines and save. .....................
$!.............................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.03 20-Oct-1988.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user CHOJNACKI
$! on  2-MAR-1989 09:54:01.63.
$!
$! ATTENTION: To keep each article below 31 blocks (15872 bytes), this
$!            program has been transmitted in 8 parts.  You should
$!            concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 29 files:
$!        AAAREADME.TXT
$!        BUGS.TXT
$!        COMMANDS.C
$!        COMMANDS.H
$!        DEBUG.H
$!        DISASSEMBLE.C
$!        DISPLACEMENTS.C
$!        GETDATA.C
$!        GETDATA.H
$!        CHECK_PORTABILITY.COM
$!        HEADER.C
$!        HEADER.H
$!        INSTALL.DOC
$!        INSTRUCTIONS.C
$!        I_TYPE.C
$!        MAKE_UNMACRO.COM
$!        MASKS.C
$!        OPERANDS.C
$!        POSNEG.C
$!        POSNEG.H
$!        SYMTAB.C
$!        SYMTAB.H
$!        UNDATA.C
$!        UNMACRO.C
$!        UNMACRO.CMP
$!        UNMACRO.COM
$!        UNMACRO.DOC
$!        UNMACRO.H
$!        UNMACRO.HLP
$!
$!==============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.03 20-Oct-1988 requires VMS V4.4 or higher."
$ EXIT 44 
$VERSION_OK:
$ GOTO START
$
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY

b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) );
s_file_spec := GET_INFO( COMMAND_LINE, "output_file" );SET( OUTPUT_FILE, b_part
, s_file_spec ); 
b_errors := CREATE_BUFFER( "{Errors}" );i_errors := 0; 
pat_beg_1 := ANCHOR & "-+-+-+ Beginning";
pat_beg_2 := LINE_BEGIN & "+-+-+-+ Beginning";
pat_end := ANCHOR & "+-+-+-+-+ End";
pat_trail := " " & LINE_END;POSITION( BEGINNING_OF( b_part ) ); LOOP b 
:= SEARCH( pat_trail, FORWARD); EXITIF b=0; POSITION( END_OF( b ) )
; LOOP MOVE_HORIZONTAL( -1 ); EXITIF CURRENT_CHARACTER <> ' '; ERASE_CHARACTER
( 1 ); EXITIF CURRENT_OFFSET=0; ENDLOOP; ENDLOOP; POSITION( BEGINNING_OF
( b_part ) ); i_append_line := 0; LOOP EXITIF MARK( NONE ) = END_OF( b_part )
; s_x := ERASE_CHARACTER( 1 ); 
  IF s_x = "+" THEN r_skip := SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip <
> 0 THEN 
      s_x := ""; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF; ENDIF; 
  IF s_x = "-" THEN r_skip := SEARCH( pat_end, FORWARD, EXACT ); IF r_skip <
> 0 THEN 
      s_x := ""; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip := MARK( NONE )
; r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip <> 0 THEN POSITION
( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET ); MOVE_VERTICAL( 1 )
; MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part ) ); ENDIF; ERASE
( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF; 
  IF s_x = "V" THEN 
    s_x := ""; IF i_append_line <> 0 THEN APPEND_LINE; MOVE_HORIZONTAL
( -CURRENT_OFFSET ); ENDIF; i_append_line := 1; MOVE_VERTICAL( 1 ); ENDIF; 
  IF s_x = "X" THEN 
    s_x := ""; IF i_append_line <> 0 THEN APPEND_LINE; MOVE_HORIZONTAL
( -CURRENT_OFFSET ); ENDIF; i_append_line := 0; MOVE_VERTICAL( 1 ); ENDIF; 
  IF s_x <> "" THEN i_errors := i_errors + 1; s_text := CURRENT_LINE; POSITION
( b_errors ); 
    COPY_TEXT( "The following line could not be unpacked properly:" )
; SPLIT_LINE; COPY_TEXT( s_x ); COPY_TEXT( s_text ); POSITION( b_part )
; MOVE_VERTICAL( 1 ); ENDIF; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP 
  r_x := SEARCH( "`", FORWARD, EXACT ); EXITIF r_x = 0; POSITION( r_x )
; ERASE_CHARACTER( 1 ); 
  IF CURRENT_CHARACTER = "`" THEN MOVE_HORIZONTAL( 1 ); ELSE COPY_TEXT( ASCII
( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDIF; ENDLOOP; IF i_errors = 0 THEN SET
( NO_WRITE, b_errors, ON ); ELSE POSITION( BEGINNING_OF( b_errors ) ); 
  COPY_TEXT( FAO( "The following !UL errors were detected while unpacking !AS"
, i_errors, s_file_spec ) ); SPLIT_LINE; 
  SET( OUTPUT_FILE, b_errors, "SYS$COMMAND" );ENDIF; EXIT; 
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!,passed." )
$ RETURN
$
$START:
$ FILE_IS = "AAAREADME.TXT"
$ CHECKSUM_IS = 808411816
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
XName:
X`009UNMACRO
X
XAuthor:
X`009Robert Thomas Chojnacki
X`009Center for Manufacturing Engineering
X`009Northwestern University
X`009chojnacki@vaxmfg.tech.nwu.edu
X
XOperating System:
X`009VAX/VMS
X
XSource Language:
X`009VAX C
X
XKeywords:
X`009Disassemblers
X
XAbstract:
X`009Please also read INSTALL.DOC and UNMACRO.DOC.
X
X`009UNMACRO is an interactive disassembler that keeps track of what each
X`009byte of the program is (i.e. an instruction, .ENTRY, .QUAD, etcetera).
X`009You may leave a session and continue where you left off later by the
X`009SAVE and UNSAVE instructions.  Features include automatic labeling
X`009(for JMP, BR, etc. instructions), automatic .ENTRY (for CALLG, CALLS,
X`009transfer address); ability to write the disassembled code to a file; a
X`009"DISASSEMBLE UNTIL" that allows disassembly until a data byte, end of
X`009the image, or until a specified PC; ability to display any part of the
X`009image in DUMP format, ability to display the image header in DUMP
X`009format; easily jump from one part of the image to another; SEARCH the
X`009image for a byte string; displays important information such as
X`009transfer addresses, image base, etcetera.  Also knows the P1 system
X`009vectors.  User defineable symbols for CALLx instructions is included.
X
X`009Commands may be abbreviated and the user may specify that there is no
X`009image header, as in the case of boot blocks, etcetera.
X
X`009UNMACRO is not finished but functional.  Unfinished parts include most
X`009of the .ASCIx directives.  A help-format file is included.
$ GOSUB UNPACK_FILE
$ FILE_IS = "BUGS.TXT"
$ CHECKSUM_IS = 89651605
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
XBugs, ideas, suggestions???  Send them to chojnacki@vaxmfg.tech.nwu.edu.
XI ask only one thing, that this program be as portable as possible.
X
XThings to be fixed:
X
X`009o  automatic labeled .byte, .word, ... on addresses in image
X`009   that instruction references
X
X`009o  RMS$ should be SYS$ in symbol table
X
X`009o  ASCIx directives should handle control chars, "/".
X
X`009o  ASCID directive should check address
X
X`009o  See "suggestions" below
X
XNon-portable things:
X
X`009o  HELP command
X
XFixes:
X
X16-FEB-1989 (all) #include's now have <xxxxx.h> rather than just xxxxx
X16-FEB-1989 (header.c) #include <stdlib.h>
X16-FEB-1989 (unmacro.c) automatic .ENTRY on transfer addresses in image
X17-FEB-1989 (disassemble.c) CASEx instructions fixed to go from 0 to limit
X            rather than 0 to limit-1
X21-FEB-1989 (unmacro.c) help file now referenced by UNMACRO_DIR
X21-FEB-1989 (unmacro.c) unmacro now accepts image file (optional .exe) on
X            command line
X21-FEB-1989 (unmacro.c, commands.h) EXIT command added
X21-FEB-1989 (unmacro.c, commands.c, commands.h, unmacro.hlp) HELP now accepts
X            arguments
X21-FEB-1989 (unmacro.c) SAVE/UNSAVE/WRITE can now take a file name as an
X            argument
X21-FEB-1989 (unmacro.c) long disassemblies (DIS ALL, etc) now can be
X            interrupted via control-c
X22-FEB-1989 (unmacro.c, header.c) image header default.  use "unmacro -h"
X            to specify no header
X22-FEB-1989 (symtab.h) added symbols up to and including SYS$LOOKUP_LICENCE
X23-FEB-1989 (header.h) set maximum isd's to 256 (just an array of pointers)
X23-FEB-1989 (header.c) changed %i's to %d's in two printf statements
X23-FEB-1989 (many, if not all) made everything uppercase
X24-FEB-1989 (commands.h) C1x2_UPPER had a double quote mark on it
X24-FEB-1989 (unmacro.c, header.c, header.h) Correctly handle demand-zero ISD's
X24-FEB-1989 (unmacro.c, header.c, header.h) Correctly calculate base address
X24-FEB-1989 (many, if not all) fix references to variable "top"
X
XPossible incompatabilities:
X
X`009VMS 4.7/VAX C 2.3`009SEEK_END should be replaced by SEEK_EOF
X
X
XSuggestions to think about:
X
XFrom Dave Shepperd 23-FEB-1989:
X
X>I'd like to suggest that you move all terminal I/O to a seperate file
X>where you can convert it to use LIB$GET_INPUT/OUTPUT or something similar so
X>it'll work much better with terminals and workstations (and allow for
X>command line editing, recall, command files, etc). Single character I/O
X>to the terminal just brings the system to its knees.
X
XI'll have to think of a portable way of doing this
X
X>I'd like to suggest that a .PSECT directive be issued for each isd with the
X>appropriate flags set and an optional section name. Also setting
X>the location pointer to an area that can't be handled with meaning (such
X>as DZRO or shared global sections) be greeted with a warning or some such.
X>You could disassemble DZRO sections with .BLKB n directives.
X
XGood suggestion.  More for next week.
X
X>We're out of
X>luck with disassembly of global sections (which will make re-assembly a
X>real pain in the ass) unless you want to get REAL fancy and read the shareable
X>image file(s) and assign symbol names to the entry points in the global
X>section(s). (I bet you didn't intend in making the writing of this code into
X>a career.)
X
XI thought about finding what names went with which of the "standard" global
Xsections, shareable images, libraries, etcetera (I.E the LIB$, MTH$, etc in
XLIBRTL and possibly the other language RTL's).  I think this would be better
Xdone via a "dynamic look-up", but then again, time consuming.  But the idea
Xinterests me enough to do some passive looking into it.  Any ideas?
X
X>The ENTRY mask decode should do some more checking. MACRO-32 won't let you
X>set bits 0 and 1 (for R0 and R1) without generating an error. UNMACRO should
X>so indicate with some kind of message that it is producing a non-standard
X>mask or non-acceptable mask. Also bits 15 and 14 of the entry mask are for
X>integer and numeric overflow exception enable/disable respectively; bits 13
X>and 12 must always be 0. They don't represent registers ap,fp,sp and pc.
X>Also I think that UNMACRO should try to disassemble the first word of
X>a section (as identified by an isd) as a .ENTRY, and failing that, then
X>disassemble it as data.
X
XMore for next week.
X
X>I'd also like to see it read .STB files into the symbol table, so when we are
X>fortunate enough to have them (or can create them by other means), unmacro
X>can use them. You could default to reading in SYS$SYSTEM:SYS.STB to get all
X>the SYS$xxx entry points and EXE$xxx names.
X
XThe SYS$ entry points are not in SYS.STB.  I do not know where they are.  I
Xtook the system services vector names (EXE$ and RMS$) from the 8000000 vector
Xand used that as a template for the 7ffede00 vector (P1 SYSVEC).
$ GOSUB UNPACK_FILE
$ FILE_IS = "COMMANDS.C"
$ CHECKSUM_IS = 172756576
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X  interpret commands
X
X  Copyright (c) 1988 By Robert Thomas Chojnacki, All rights reserved.
X*/
X#define`009commandsfile
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include "unmacro.h"
X#include "commands.h"
X#include "debug.h"
Xcommands(command)
Xint command[8];
X`123
X  char cmdline[128];
X  int i, cmd, cmd2, cmd3, cmd4;
X
X  debmsg("<commands>");
X  command[1] = -1;
X  command[2] = -1;
X  command[3] = -1;
X/*
X  read in command
X*/
X  fprintf(stderr, prompt, pc);
X  if (scanf("%128[`094\n]s", cmdline) == EOF)
X    exit(1);
X  do `123`125 while (getchar() != '\n');
X  for (i = 0; i < strlen(cmdline); i++)
X    cmdline[i] = toupper(cmdline[i]);
X/*
X  parse line
X*/
X  if (!strlen(cmdline)) `123
X    command[0] = C_DISASSEMBLE;
X    return(0);
X  `125
X  sscanf(cmdline, "%128s", arg1);
X  sscanf(cmdline, "%*s%128s", arg2);
X  sscanf(cmdline, "%*s%*s%128s", arg3);
X  sscanf(cmdline, "%*s%*s%*s%128s", arg4);
X#ifdef`009debug
X  fprintf(stderr, "cmdline = %s\n", cmdline);
X  fprintf(stderr, "arg1 = %s\n", arg1);
X  fprintf(stderr, "arg2 = %s\n", arg2);
X  fprintf(stderr, "arg3 = %s\n", arg3);
X  fprintf(stderr, "arg4 = %s\n", arg4);
X#endif
X  for (cmd = 0; cmd < sizeof(unmacrocommands)/4; cmd++)
X    if (!strncmp(arg1, unmacrocommands[cmd], strlen(arg1)))
X      break;
X  if (cmd < sizeof(unmacrocommands)/4) `123
X    command[0] = cmd;
X    switch (cmd) `123
X/*
X  DISASSEMBLE - get sub-commands
X*/
X     case C_DISASSEMBLE:
X      if (!strlen(arg2))
X`009return(0);
X      for (cmd2 = 0; cmd2 < sizeof(disassembl)/4; cmd2++)
X`009if (!strncmp(arg2, disassembl[cmd2], strlen(arg2)))
X`009  break;
X      command[1] = cmd2;
X      if (cmd2 == sizeof(disassembl)/4) `123
X        comderr("DISASSEMBLE", 1, disassembl, sizeof(disassembl)/4);
X`009command[0] = -1;
X      `125 else  if (cmd2 == C0_UNTIL) `123
X`009for (cmd3 = 0; cmd3 < sizeof(disassembleuntil)/4; cmd3++)
X`009  if (!strncmp(arg3, disassembleuntil[cmd3], strlen(arg3)))
X`009    break;
X`009  command[2] = cmd3;
X`009  if (cmd3 == sizeof(disassembleuntil)/4) `123
X`009    command[0] = -1;
X`009    comderr("DISASSEMBLE UNTIL", 1, disassembleuntil,
X`009     sizeof(disassembleuntil)/4);
X`009  `125 else if (cmd3 == C0x22_PC) `123
X`009    if (!sscanf(arg4, "%x", &command[3])) `123
X`009      fprintf(stderr, "bad address for DISASSEMBLE UNTIL PC\n");
X              command[3] = 0;
X`009    `125
X`009  `125
X      `125
X      break;
X/*
X  SET - get sub-commands
X*/
X     case C_SET:`009`009/* SET */
X      for (cmd2 = 0; cmd2 < sizeof(setshow)/4; cmd2++)
X`009if (!strncmp(arg2, setshow[cmd2], strlen(arg2)))
X`009  break;
X      if (cmd2 == sizeof(setshow)/4) `123
X        comderr("SET", 1, setshow, sizeof(setshow)/4);
X`009command[0] = -1;
X      `125 else `123
X`009command[1] = cmd2;
X`009switch(cmd2) `123
X/*
X  SET BYTE/WORD/LONG/QUAD/OCTA/RANGE subcommands
X*/
X`009 case C1_RANGE:
X`009  if (!sscanf(arg4, "%x", &command[3])) `123
X`009    fprintf(stderr, "SET RANGE has invalid address\n");
X`009    command[0] = -1;
X`009    return(0);
X`009  `125
X`009 case C1_BYTE:
X`009 case C1_WORD:
X`009 case C1_LONG:
X`009 case C1_QUAD:
X`009 case C1_OCTA:
X`009  for (cmd3 = 0; cmd3 < sizeof(setshowbyte)/4; cmd3++)
X`009    if (!strncmp(arg3, setshowbyte[cmd3], strlen(arg3)))
X`009      break;
X`009  if (cmd3 == sizeof(setshowbyte)/4) `123
X`009    command[0] = -1;
X            comderr("SET BYTE/LONG...", 1, setshowbyte, sizeof(setshowbyte)/4);
X`009      break;
X`009  `125 else `123
X`009    command[2] = cmd3;
X`009  `125
X`009  break;
X/*
X  SET MODE subcommands
X*/
X`009 case C1_MODE:
-+-+-+-+-+ End of part 1 +-+-+-+-+-
