There are 3 other files named facerr.mac in the archive. Click here to see a list.
TITLE FACERR -- Facility error handling information for the RTL
; COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984, 1986.
; ALL RIGHTS RESERVED.
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND
; COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
; THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR
; ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
; AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE
; SOFTWARE IS HEREBY TRANSFERRED.
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT
; NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL
; EQUIPMENT CORPORATION.
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF
; ITS SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
; Edit History
; Version 1.0
; Version 1.1
;.EDIT 50 Formally go to version 1.1, update copyright, insert V1.1
; development changes (formally V2)
SEARCH DYNSYM, DDBSYM, MONSYM, MACSYM
EXTERNAL ME$ALM, SG$DLG, RL$FAO, SG.LER, SG$SIG
; Data and code for handling error message generation in the RTL
; The RTL must contain several different facilities; their facility
; numbers may not all be assigned together.
; Therefore a table indexed by facility number is a Bad Idea.
; Facility table
.FTCOD==0 ;The facility code
.FTNAM==1 ;A local or 1-word global BP to the name string
.FTMSG==2 ;xFIW address of message table for this facility
.FTLEN==3 ;Number of words per entry in this table
; The table is terminated with a .FTCOD < 0
DEFINE FACDEF (code, number, name) <
EXP number, <POINT 7, [ASCIZ name]>, <IFIW!'code'MSG>
; Message tables.
; There is one message table for each facility. It is indexed by message
.MGLNG==0 ;Max expanded length of FAO string (0 if empty)
;(this is obnoxious, but we must allocate fixed
;space in the signal block for FAO to expand
;into and I don't want it to come out too
.MGSTR==1 ;One-word byte pointer to FAO string for message
.MGNAM==2 ;One-word byte pointer to 3-character name
;for this message
.MGLEN==3 ;Length of this block
; Macro for building message table entries:
DEFINE MSGDEF (fac, mnam, sev, length, msg) <
IRPC msg, <
EXP <POINT 7, [ASCIZ msg]>
EXP <POINT 7, [ASCIZ /mnam/]>
SUBTTL RTLERR -- Signal an RTL error with a clean stack
; This routine essentially performs an RTLERS followed by an RTLSER.
; That is, it takes arguments on the stack, makes a signal block, and
; passes that signal block to RTLSER. The only difference is that you
; are not given the opportunity to clean up your stack between the calls.
; This is suitable for use in simple routines that have no cleanup to do.
SUBTTL RTLERS -- Make signal block for error
; This routine produces a signal block for an RTL error. The expected sequence
; of events for handling a complicated error is as follows:
; 1. Call RTLERS to make an appropriate signal block
; 2. Clean up your stack
; 3. Call RTLSER to signal the error
; If you don't need to clean up your stack, there is a routine RTLERR which
; combines the functions of RTLERS and RTLSER.
; Note that this only works for RTL errors, which can be described as a
; condition code and a sequence of FAO args. This is not a general purpose
; error reporter by any stretch of the imagination.
; Args pushed on the stack for RTLERS are as follows:
; FAO args in normal order order (that is, write the pushes in normal order)
; Extra words,,Number of args pushed
; Condition code
; These args have been removed from the stack on return.
; RTLERS preserves registers 6-17.
; On return, T1 contains the address of the signal block (a dynamic signal
; block is built using space from the error processing chunk).
; The SG block built looks like this:
; SIG block (fixed fields)
; Extra space (number of words specified in LH of next-to-last arg)
; Args (the FAO args, in the same order) .SGDAT points to here
; Message string. .SGMSG points to here (byte pointer)
; Stack setup:
; First arg pushed, many args pushed in middle, then...
ERRLRG==-15 ;Last argument pushed onto stack
ERRACN==-14 ;Count of FAO args pushed
ERRCC==-13 ;Condition code to signal
; Return address
ERRPC==-12 ;PC of our caller (plus 1, really)
; Saved registers
ERRSG==0 ;SG block address
ERRSPC==12 ;Amount of stack space to allocate
;for registers plus locals
; Register use:
; P1 SG block address
; P2 Address of facility table entry
; P3 Address of message table
; P4 Address of ARG words in SG block
; P5 Address of MSG string in SG block
ADJSP P, ERRSPC ;Allocate register and local space
; Save registers
DMOVEM 6, ERRAC6(P)
DMOVEM 10, ERRA10(P)
DMOVEM 12, ERRA12(P)
DMOVEM 14, ERRA14(P)
MOVEM 16, ERRA16(P)
; First we must determine the size SG block to allocate (it must contain
; the message string for this error after FAO expansion). To do this we
; need to find the message block, which gives the message length. To do
; this we need to find the facility block, which points to the message block.
; The facility block may be found from the facility code part of the
; condition word.
MOVE T1, ERRCC(P) ;Get condition code
CALL FNDFAC ;Find the facility entry in FACTBL
JRST ERRDIE ;Lose seriously -- invalid facility
MOVE P2, T1 ;Save facility table entry address
XMOVEI P3, @.FTMSG(P2) ;Get address of message table
LDB T2, [POINTR ERRCC(P), SG%MSG] ;Get message code
;What about customer-defined bit? This causes trouble?
SUBI T2, 1 ;Subtract min subscript
IMULI T2, .MGLEN ;Multiply by entry size
ADD P3, T2 ;Get address of entry for this message
MOVE T2, .MGLNG(P3) ;Get string length (max)
IDIVI T2, 4 ;Convert to words
AOS T2 ;Round up always
ADDI T2, .SGLEN+1 ;Total length we want to allocate
;The +1 is for the count word in the list of
HRRZ P5, ERRACN(P) ;FAO arg count
AOS P5 ;Plus one for vector count
HLRZ P4, ERRACN(P) ;Extra words count
ADD T2, P4
ADD T2, P5 ;Sum them all
MOVX T1, .MEERR ;Chunk reserved for error processing
CALL ME$ALM ;Allocate us a signal block
;This infinite-loops if it fails
MOVEM T2, ERRSG(P) ;Address returned in T2
MOVE P1, T2 ;Preserve SG adr
ADDI T2, .SGLEN
ADD P5, P4
ADD P4, T2 ;Address, as promised
ADD P5, T2 ;Ditto
; Now fill in the signal block we have allocated
MOVE T1, ERRCC(P) ;Get condition code
MOVEM T1, .SGCC(P1) ;Condition code into SG
;SETZM .SGNXT(P1) ;No next pointer in SG
;The SG block was zeroed by the allocator
GETBP T0, .FTNAM(P2), T4
MOVEM T0, .SGFAC(P1) ;OWGBP to static facility string into SG
GETBP T0, .MGNAM(P3), T4
MOVEM T0, .SGCND(P1) ;OWGBP to static condition name string into SG
MOVE T1, P5 ;Get address of message string
TXO T1, 67B5 ;Use 9-bit OWGBP here to cause confusion
;and make the code Much simpler (don't have
;to figure out byte size of source BP)
MOVEM T1, .SGMSG(P1) ;OWGBP to message string (at end of SG block)
MOVE T0, ERRPC(P) ;Get our caller's PC
MOVEM T0, .SGPC(P1) ;PC into SG
MOVX T0, SG%SOF
MOVEM T0, .SGCLS(P1) ;Class flags into SG
MOVX T0, SG%DYN
MOVEM T0, .SGFLG(P1) ;General flags into SG
MOVEM P4, .SGDAT(P1) ;Put in address of data section
MOVE T2, .MGLNG(P3) ;Maximum length of destination string
GETBP T3, .MGSTR(P3), T4
XMOVEI T4, ERRLRG+1(P) ;Address of last FAO arg PLUS ONE
HRRZ T5, ERRACN(P) ;Count of FAO args
SUB T4, T5 ;Address of first FAO arg
ERJMP .+1 ;We can't afford to screw up now!
; Move args to data field of block
HRRZ T0, ERRACN(P) ;Get count of args
MOVEM T0, 0(P4) ;Put away the count
AOS 0(P4) ;Count includes this count word
XMOVEI T1, ERRLRG+1(P) ;Get address of last arg on stack +1
SUB T1, T0 ;Compute address of first arg
XMOVEI T2, 1(P4) ;Place to start putting args
EXTEND 0, [XBLT] ;Copy all args
; Restore registers
DMOVE 6, ERRAC6(P)
DMOVE 10, ERRA10(P)
DMOVE 12, ERRA12(P)
DMOVE 14, ERRA14(P)
MOVE 16, ERRA16(P)
; Clean up stack and return
XMOVEI T0, ERRLRG+1(P) ;Address of last FAO arg PLUS ONE
HRRZ T1, ERRACN(P)
SUB T0, T1 ;Minus count = address of first fao arg
MOVE T1, ERRPC(P) ;Our return address
MOVEM T1, @T0 ;Onto first word of our stack frame
MOVE T1, ERRSG(P) ;Must leave address of sig block in T1
MOVE P, T0 ;Remove our stack frame
; THE SKY IS FALLING
?? Severe error in error processing routine
? Please submit an SPR
?? Program terminated due to previous error
SUBTTL RTLSER -- Signal an RTL error
; This routine accepts a signal block and signals it, or returns
; it to its caller's caller if that caller has an ERJMP/ERCAL after the
; t1/ Address of signal block
; RTLSER must be called only after the stack has been cleaned up -- the
; top item must be the return address of RTLSER's caller.
; RTLSER is reached via a JRST, N O T A C A L L ! ! ! !
; RTLSER does not return.
; RTLSER preserves registers 2-16
SERSPC==5 ;Space used on stack
ADJSP P,SERSPC ;Make space to save things
DMOVEM 1, SERAC1(P) ;Note that this saves our arg
DMOVEM 3, SERAC3(P)
MOVEM 5, SERAC5(P)
; Make this the LER
;First free any existing block
SKIPE T1, SG.LER ;Skip if no error stored yet, load T1
CALL SG$DLG ;Deallocate signal block chain
ERJMP .+1 ;NOP if reached by SKIPE
MOVE T1, SERAC1(P) ;Get our arg back
MOVEM T1, SG.LER ;Set this error as last error found
; Restore registers
DMOVE 2, SERAC2(P)
DMOVE 4, SERAC4(P)
ADJSP P, -SERSPC
JRST RTLCER ;Continue the error -- upwards away!
SUBTTL RTLCER -- Continue error upwards
; This routine is for internal RTL use only. It is used for passing an
; error on up to the next highest level with RTL-style error handling.
; T1/ Address of SG block
; This routine is invoked with a JRST, N O T A C A L L !
; This first item on the stack must be the return address of our invoker's
; caller. For example, if RTLFOO called some routine RTLBAR that returned RTL-
; style errors, and FOO didn't want to use a condition handler, it could
; put an ERJMP/ERCAL after the call to RTLBAR which transferred control to a
; routine which restored registers (if necessary), cleaned up the stack, and
; then came here. Now, any caller to RTLFOO will see the error from RTLBAR
; as a normal RTL-style error (either signal or ERJMP/ERCAL).
; This routine must preserve registers 2-16.
; If control is transferred to an ERJMP/ERCAL, T1 must contain the address
; of the signal block being passed.
CERRAD==0 ;Stack offset to return address
MOVE T0, @CERRAD(P) ;Get our caller's return instruction
TXZ T0, MASKB(13,35) ;Leave only instruction and register
CAMN T0, [ERJMP]
CAMN T0, [ERCAL]
; No magic, we need a signal
; RTL errors signalled cannot be continued
?? RTL errors can't be continued
? Program terminated due to previous error
HALTF% ;Is there any graceful alternative?
; User wants us to jump to a routine
ERRJMP: XMOVEI T0, @CERRAD(P) ;Get section to jump into
HRR T0, @CERRAD(P) ;Get in-section address to go to
MOVEM T0, CERRAD(P) ;Heh, heh. Return will be to where WE specify
; User wants us to call a routine for him
; In this case, store desired return address for call in ERRINS
ERRCAL: XMOVEI T0, @CERRAD(P) ;Get section to call into
HRR T0, @CERRAD(P) ;Get in-section address to call
AOS CERRAD(P) ;Increment return for fake CALL
PUSH P, T0 ;Push address to go to
;Fall through to ERRDOI
; Clean up and do user return as specified
SUBTTL FNDFAC -- Find facility table entry
; Given a condition code in T1, return the facility table entry address
; in T1, and skip return. If no such facility, normal return. This is
; a really disastrous situation normally...
; Trashes T2
FNDFAC: LDB T2, [POINTR T1, SG%FAC]
XMOVEI T1, FACTBL-.FTLEN ;Set up global index into FACTBL
FND001: ADDI T1, .FTLEN ;Step to next (first) entry
SKIPGE .FTCOD(T1) ;Skip if not yet at end of table
JRST FNDLOS ;Lose, lose
CAME T2, .FTCOD(T1) ;Skip if found
JRST FND001 ;Loop
; Found it
AOS 0(P) ;Skip return
FNDLOS: SETZ T1, ;Indicate lossage
SUBTTL RTLJER -- Make JSYS signal error block for last JSYS error
; This routine makes a SG block for the last jsys error (including
; the message text).
; Arguments: None
; Returns block address in T1
; Registers 6-17 are preserved
; If errors are detected, participates in normal RTL error handling.
PUSH P, P1 ;Save
MOVX T1, .FHSLF
HRRZ P1, T2 ;Clear process handle and save
PUSH P, P1
PUSH P, 
PUSH P, [DY$JER]
CALL RTLERS ;Make error block
MOVX T0, 2
MOVEM T0, .SGLEN+JERWRD(T1) ;Count of user words
MOVEM P1, .SGLEN+JERWRD+1(T1) ;Value: the jsys error
XMOVEI T0, .SGLEN+JERWRD(T1) ;Set user word to point to counted vector
MOVEM T0, .SGDAT(T1)
POP P, P1