emigh@ecsvax.UUCP (09/26/84)
: Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting finderr.doc' sed 's/^X//' <<'//go.sysin dd *' >finderr.doc FINDERR VERSION 1.0 Ted H. Emigh Departments of Genetics and Statistics North Carolina State University Raleigh, NC 27695 usenet: emigh@ecsvax One of the major advantages of ZCPR3 is the passing of messages from one utility to the next. Unfortunately, almost all commercial packages do not have this mechanism. This program was developed to help in the passing of messages from commercial programs to ZCPR3 utilities. As an example: We may wish to have a compilation/assembly stop if there are errors. Otherwise, we may wish to link the program with a library to an executable program. Microsoft's Macro-80 assembler (M80) and FORTRAN-80 compiler (F80) give a summary of the number of fatal and warning errors just before the assembler/compiler stops execution. FINDERR looks at the fatal and warning errors from M80/F80 and sets the ZCPR3 registers if there have been any errors. Although it was designed for M80/F80, it should be relatively simple to add this type of error messages for any program that gives a summary of errors (or a total number of errors). ZCPR3 MESSAGES: ZCPR3 allows the passing and testing of messages using the IF # construct, where # is a number between 0 and 9. If a particular register is 0, then an error did not occur, if it is nonzero, then an error occured during assembly/compilation, and the specific value designates whether the error was fatal or a warning error. In this version of FINDERR, ZCPR3 Register 0 reflects the error status of a prior M80 assembly, and ZCPR3 Register 1 reflects the error status of a prior F80 compilation. FINDERR will check memory locations for both M80 and F80 -- but will be valid only ONE AT A TIME, and must be executed immediately after M80/F80. THE NATURE OF SUMMARY MESSAGES: If a program gives a summary message, it must have locations to keep track of the errors (or summary data). As the program exits, it will check these locations and print a message if it is appropriate. You need to find these locations in order to make use of the summary information. To find these locations, you need a good disassembler (RES, ZDASM, etc). FINDING SUMMARY LOCATIONS: The first thing you must look for is the message that is printed out when there is an error, say, "Errors Detected". Dump memory from 100H until you have found the message. The message, typically will end with a '$', or 0, or with the 80H bit set, or will have a single byte at the beginning which contains the number of characters to display: db 'Errors Detected',0DH,0AH,'$' ;ending in '$' db 'Errors Detected',0DH,0AH,0 ;ending in 0 db 'Errors Detected',0DH,0AH+80H ;ending with 80H bit set db 17,'Errors Detected',0DH,0AH ;character count at the start Normally, there are two ways for the program to print an error message: 1) Loading the address of the summary message into a register (e.g., LXI H,ERRMSG), then calling a routine that prints the message; or 2) Having a CALL just before the summary message (the address of the summary message is then put on the stack). The first is the most common situation. Once you have found the summary message, use your disassembler's 'FIND' function to find where the beginning location of the message has been referenced. In this area, you will find the code that checks for the error count. The following is an example (from Microsoft's M80 macro assembler, version 3.44). 2EAD LDHL 3CEDH ;Location for number of fatal errors 2EB0 MOV A,H ;See if there are errors 2EB1 ORA L 2EB2 JZ 2ECBH ;No errors, print 'No' 2EB5 PUSH H ;These next 2EB6 CALL 1ADFH ; statements 2EB9 POP H ; print the number 2EBA LDA 40B4H ; of errors 2EBD INR A 2EBE STA 3F5BH 2EC1 CNZ 1ADFH 2EC4 XRA A 2EC5 STA 3F5BH 2EC8 JMP 2ED1H ;Now print ' Fatal error(s)' 2ECB LXI H,2F4CH ;Point to 'No' message 2ECE CALL 2FD0H ;Print it 2ED1 LXI H,2F4FH ;Point to ' Fatal error(s)' message 2ED4 CALL 2FD0H ;Print it . . . 2F4C DB 'No',0 2F4F DB ' Fatal error(s)',0 In this case, I searched for 2F4CH (the 'No' message), and found it referenced at 2ECBH. The instruction just before this is an unconditional jump (JMP 2ED1H), so we need to 'FIND' 2ECBH as well. This search leads to 2EB2H, and the instructions just prior to it. We can see now that location 3CEDH is the 2-byte location for the number of errors (actually, from this segment all we know is that the word at 3CEDH is zero if there are no errors, and nonzero if there are errors). Once you understand what to look for, it is not too difficult to find these locations. Unfortunately, not all programs do this. For example, neither ASM nor MAC keep track of the number of errors, so this will not work for those assemblers. When you have found the locations, and how many bytes each takes, you can add them to this program by changing the system equates at the beginning of the program. For the distribution version, register 0 is zero if M80 found no errors, is one if M80 found at least one fatal error, and is two if M80 found no fatal errors but did find at least one warning error. In addition, register 1 is zero if F80 found no errors, is one if F80 found at least one fatal error, and is two if F80 found no fatal errors, but did find at least one warning error. USING FINDERR: FINDERR MUST be executed immediately following the termination of the program that it is checking, so that no memory locations are changed. Note that this means that FINDERR should lie in the path, don't use CMDRUN to get it out of a library, as this may change the memory locations you wish to test. The ZCPR3 registers are set IN CONTEXT WITH the program executed prior to FINDERR. Hence, Register 0 is a valid test with FINDERR after M80, but is invalid if FINDERR is executed after F80. The following ZEX file will assemble an M80 file and link/load it if there are no errors. If there are warning errors, it will wait for programmer intervention, and if there are any fatal errors it will abort the assembly. EXAMPLE: ; ; M80.ZEX -- MACRO-80 Assembler and Linker ; ; ^& Suppress FALSE IF Printout if nul $1 ;note Print Error Message echo ^G**** No Parameter Specified **** else ;note Perform Assembly if ~empty $1.MAC ;note Print File Not Found echo **** File Not Found **** else M80 =$1 FINDERR if 0 ;note No errors found, link file ERA $1.BAK ERA $1.COM L80 /P:100,$1,$1/N,SYSLIB/S,/E else ;note on IF REG 0 if 0 2 ;note see if the errors are warnings echo ^G***WARNING ERROR*** if input Type T to Continue or F to Abort (Warning Errors) ERA $1.BAK ERA $1.COM L80 /P:100,$1,$1/N,SYSLIB/S,/E fi ;note on IF INPUT else ;note error is fatal echo ^G***FATAL ERROR IN ASSEMBLY*** fi ;note IF REG 0 2 ERA $1.REL fi;fi ;note on IF NUL and IF EMPTY ; ; Assembly Complete ; //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 finderr.doc /bin/echo -n ' '; /bin/ls -ld finderr.doc fi /bin/echo 'Extracting finderr.mac' sed 's/^X//' <<'//go.sysin dd *' >finderr.mac ; ; PROGRAM: FINDERR ; AUTHOR: TED H. EMIGH ; VERSION: 1.0 ; DATE: 11 SEPT 84 ; PREVIOUS VERSIONS: 0.1, 7 SEPT 84 ; VERSION EQU 10 EXTENV EQU 1 ; 1 for External Environ, 0 for Internal Environ ; ; FINDERR is a program to set the ZCPR3 message registers if various ; memory locations are nonzero ; ; ZCPR3 Header ; MACLIB Z3BASE.LIB ; ; These Locations Assume the use of M80/F80, Version 3.44 ; m80f equ 03cedh ;location of number of fatal errors (M80) m80fb equ 2 ;--16 bits (2 bytes) m80w equ 03cefh ;location of number of warning errors (M80) m80wb equ 2 ;--16 bits (2 bytes) f80f equ 01c1h ;location of number of fatal errors (F80) f80fb equ 2 ;--16 bits (2 bytes) f80w equ 02adh ;location of number of warning errors (F80) f80wb equ 2 ;--16 bits (2 bytes) ; ; System Equates ; Add the location of the error indicator, and the number of byte ; for the indicator for each indicator desired. If the number of ; bytes is zero, that particular memory location is ignored. ; fatal0 equ m80f ;location of number of fatal errors bytesf0 equ m80fb ;number of bytes warn0 equ m80w ;location of number of warning errors bytesw0 equ m80wb ;number of bytes fnderr0 equ bytesf0 or bytesw0 ;register 0 used for these errors fatal1 equ f80f ;location of number of fatal errors bytesf1 equ f80fb ;number of bytes warn1 equ f80w ;location of number of warning errors bytesw1 equ f80wb ;number of bytes fnderr1 equ bytesf1 or bytesw1 ;register 1 used for these errors ; ; The rest of the registers are not used at this time ; (if bytes = 0, then the memory address is not checked) ; fatal2 equ 0 ;location of number of fatal errors bytesf2 equ 0 ;number of bytes warn2 equ 0 ;location of number of warning errors bytesw2 equ 0 ;number of bytes fnderr2 equ bytesf2 or bytesw2 ;register 2 used for these errors ; fatal3 equ 0 ;location of number of fatal errors bytesf3 equ 0 ;number of bytes warn3 equ 0 ;location of number of warning errors bytesw3 equ 0 ;number of bytes fnderr3 equ bytesf3 or bytesw3 ;register 3 used for these errors ; fatal4 equ 0 ;location of number of fatal errors bytesf4 equ 0 ;number of bytes warn4 equ 0 ;location of number of warning errors bytesw4 equ 0 ;number of bytes fnderr4 equ bytesf4 or bytesw4 ;register 4 used for these errors ; fatal5 equ 0 ;location of number of fatal errors bytesf5 equ 0 ;number of bytes warn5 equ 0 ;location of number of warning errors bytesw5 equ 0 ;number of bytes fnderr5 equ bytesf5 or bytesw5 ;register 5 used for these errors ; fatal6 equ 0 ;location of number of fatal errors bytesf6 equ 0 ;number of bytes warn6 equ 0 ;location of number of warning errors bytesw6 equ 0 ;number of bytes fnderr6 equ bytesf6 or bytesw6 ;register 6 used for these errors ; fatal7 equ 0 ;location of number of fatal errors bytesf7 equ 0 ;number of bytes warn7 equ 0 ;location of number of warning errors bytesw7 equ 0 ;number of bytes fnderr7 equ bytesf7 or bytesw7 ;register 7 used for these errors ; fatal8 equ 0 ;location of number of fatal errors bytesf8 equ 0 ;number of bytes warn8 equ 0 ;location of number of warning errors bytesw8 equ 0 ;number of bytes fnderr8 equ bytesf8 or bytesw8 ;register 8 used for these errors ; fatal9 equ 0 ;location of number of fatal errors bytesf9 equ 0 ;number of bytes warn9 equ 0 ;location of number of warning errors bytesw9 equ 0 ;number of bytes fnderr9 equ bytesf9 or bytesw9 ;register 9 used for these errors ; ; ; MACROS TO PROVIDE Z80 EXTENSIONS ; MACROS INCLUDE: ; ; jrnz - Jump Relative if No Zero ; djnz - Decrement B and Jump Relative if No Zero ; ; @gendd Macro used for Checking and Generating ; 8-Bit Jump Relative Displacements ; @gendd macro ?dd ;;Used for checking range of 8-bit displacements if2 ;;M80 if (?dd gt 7FH) and (?dd lt 0FF80H) db 100H,?dd ;Displacement Range Error else db ?dd endif ;;Range Error else ;;M80 db ?dd ;;M80 endif ;;M80 endm ; ; ; Z80 MACRO EXTENSIONS ; jrnz macro ?n ;;Jump Relative on No Zero if i8080 ;;8080/8085 jnz ?n else ;;Z80 db 20H @gendd ?n-$-1 endif ;;I8080 endm ; djnz macro ?n ;;Decrement B and Jump Relative on No Zero if i8080 ;;8080/8085 dcr B jnz ?n else ;;Z80 db 10H @gendd ?n-$-1 endif ;;I8080 endm ; ; Macros to do most of the work ; ; SETBYT will set B register to 'value' if the any of the bytes ; at location 'loc' to 'loc'+'bytes'-1 are nonzero ; ('bytes' is the number of bytes to check) ; If no error, then B=0. errno is the error number ; setbyt macro loc,bytes,errno,value local nxtbyt if bytes ne 0 ;; if bytes eq 1 lda loc ;;get byte ora a ;;see if zero endif ;;bytes eq 1 if bytes eq 2 lxi h,loc mov a,m ;;get lower byte inx h ;;point to higher byte ora m ;;see if 16 bit number is zero endif ;;bytes eq 2 if bytes gt 2 lxi h,loc mov a,m ;;get first byte mvi b,bytes-1 ;;number of bytes nxtbyt: inx h ;;point to next byte ora m ;;see if number is zero djnz nxtbyt ;;more bytes? if i8080 ora a ;;set flags for a again endif ;;I8080 endif ;;bytes gt 2 mvi b,value jrnz err&errno ;; endif ;;bytes ne 0 endm ; ; SETBYT will set register number errno to the value in ; B if entered at err&errno, else it will reset the value ; at register number errno. This routine MUST follow the ; last setbyt for that error number. ; finish macro errno mvi b,0 ;;set for zero err&errno: lxi h,30h+errno ;;point to register number dad d mov m,b ;;save the error code ; endm ; ; Environments ; origin: ; if extenv ; if external environment ... ; ; External Environment Definition ; jmp finderr db 'Z3ENV' ; this is an environment db 1 ; class 1 environment (external) envloc: dw z3env ; ptr to environment finderr: lhld envloc ; HL pts to environment else ; if internal environment ... ; ; Internal Environment Definition ; envloc: jmp finderr db 'Z3ENV' ; this is an environment MACLIB SYSENV.LIB SYSENV ; define environment finderr: lxi h,envloc ; HL pts to environment endif ; ; Beginning of FINDERR ; lxi d,34 ;message address offset in environment dad d ;point to location of message address mov a,m ;get message address inx h mov h,m mov l,a ;HL now points to the message buffer ora h ;see if message buffers supported rz ;messages not supported, abort xchg ;save pointer to message buffer irp errno,<0,1,2,3,4,5,6,7,8,9> if fnderr&errno setbyt fatal&errno,bytesf&errno,errno,1 setbyt warn&errno,bytesw&errno,errno,2 finish errno endif endm ; ret end //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 finderr.mac /bin/echo -n ' '; /bin/ls -ld finderr.mac fi