Trailing-Edge
-
PDP-10 Archives
-
bb-x130a-sb
-
snup.mac
There are 6 other files named snup.mac in the archive. Click here to see a list.
UNIVERSAL SNUP
;COPYRIGHT (C) 1979,1980 BY DIGITAL EQUIPMENT CORPORATION,
;MAYNARD, MASS.
;
;
;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 WHICH IS NOT SUPPLIED BY DIGITAL.
; Revision history:
;Edit #5
;13/OCT/83/TARL Add version number V.SNUP to help us keep track of SNUP
; programs which are loaded with which version of SNUP. We
; will need this in the beginning of 7.03 to track which programs
; are loaded with old and new sets of ACs.
; 4/06/80/JCH Do multiply defined symbols right. Take the global
; definition over the local, watch for multiply
; defined locals or globals, and like that.
;
; Have LOKSEG chuck any high page number returned in
; T1 so CNVADR will work if the snooper has a high
; segment. (LOCK always returns pages of both segments
; even if only one is LOCKed).
; 10/23/79/JCH Fancy up DMN's stuff. Also add the following entries:
; (All replacements for XCTSNP)
; XWRSNP - XCTSNP without reducing core
; REDEFP - Redefine and reinsert user's breakpoints
; REINSP - Reinsert user's breakpoints
; 10/19/79/DMN Add symbol offsets to BRKPNT macro. Also find
; multiple occurences of a symbol in BRKPNT list.
; (Can happen when user invokes offset feature).
; 09/28/79/JCH Do the right thing with multiply-defined symbols.
; This fixes a number of bugs involving collections
; of symbols some of which were undefined and some
; of which were multiply-defined.
; In REDSYM use P3 to track symbol table location in
; the monitor .EXE file rather than T2, obeying the
; conventions about preserved/temporary ACs.
; Allow multiply-defined symbols if the values
; are equal.
; Also handle the obscure but possible case where
; a symbol is RADIX-50ed in the last word of a page
; so its value is in the next page, which wasn't
; in core when it was referenced. This happens
; because the program expects INBUFF+1(T1) to be
; valid whenever INBUFF(T1) is.
; Fix error messages to use upper and lower case.
; Do GETTABs and appropriate stuff to find monitor
; even if it was loaded from an SFD.
; Fix the loop at CNVADR to use the correct value
; in P2, so as not to cream the user's code.
; Add monitor register names with "%" prefix. Thus,
; F becomes %F, P is %P, etc.
; Fix up a number of comments.
; The net effect of this revision is to increase
; the size of the locked segment by at most one
; page. It also prevents crashes that could have
; happened because this code wasn't sufficiently
; defensive.
COMMENT &
---- KNOWN BUGS AND DEFICIENCIES ----
1. SNUP will not handle the case where one symbol exists in
several different modules, but is not gloabal; or when you
want to use a local symbol which conflicts with a global symbol
in a different module. Module specification is not
yet supported. It may never be.
2. Not all possible symbol errors are detected at once. It may
require several runs before all errors are detected.
---- Fixes are possible but not deemed worth the effort. ----
&
SUBTTL SNUP -- Subroutines for using the SNOOP. UUO
; USING THIS PACKAGE
;
; There are two general modes of operation which for lack of a better
;vocabulary we can call:
; 1. Fault
; 2. Advanced
;The fault mode is easiest to use but is restricted in that breakpoints
;and monitor references are defined at compile-time by the MONREF and
;BRKPNT macros. All you have to do is issue a MONREF for every monitor
;symbol you want to reference and a BRKPNT for every breakpoint you
;want to insert. Following are the instructions for this mode:
;
; 1. Calling program must search UUOSYM and SNUP
;
; 2. If your breakpoint code needs to look at monitor locations,
; use the MONREF macro for every desired reference other than
; breakpoint symbols. You may specify more than one symbol in
; a MONREF if you enclose them in angle-brackets.
; (THIS MUST BE DONE BEFORE USING THE BRKPNT MACRO)
; MONREF monitor symbol
;
; example-MONREF <APRCK0,.CPDWD> ;LOOK AT APRCK0 AND .CPDWD
;
; 3. Tell SNUP where to breakpoint and where to find your code
; by using the BRKPNT macro.
; BRKPNT monitor symbol,address of your code
;
; example-BRKPNT APRCK0,KAFTST ;KAFTST IS BREAKPOINT CODE
;
;
; 4. Your breakpoint code can be inserted anywhere. If you want
; to reference the monitor locations you specified in
; MONREF or BRKPNT, you simply go indirect off the symbol.
; The breakpoint code must also index all
; memory references by AC3 (containing relocation value).
;
; example-MOVE 17,@APRCK0(3) ;GET CONTENTS OF APRCK0
;
; 5. Your program must set up P to a push down stack and it should
; do a RESET
;
; 6. You may then do PUSHJ P,GETINF## to let SNUP define your
; breakpoints.
;
; 7. Do PUSHJ P,XCTSNP## to insert the breakpoints
;
; 8. Execute the REMBRK macro to remove the breakpoints
;
; 9. Execute the UNDBRK macro to undefine the breakpoints
; EXAMPLE PROGRAM -- KEEP-ALIVE FAILED FAULT INSERTION
;
REPEAT 0,<
TITLE KAF
SEARCH UUOSYM,SNUP
BRKPNT APRCK0,KAFTST
PDL: BLOCK 50
START: MOVE P,[-50,PDL]
TELL KEEP-ALIVE TEST
PUSHJ P,GETINF## ;DEFINE BREAKPOINTS
PUSHJ P,XCTSNP## ;INSERT BREAKPOINTS
TELL BREAKPOINTS INSERTED -- TYPE CR TO REMOVE
INCHWL T1 ;WAIT FOR USER TO REMOVE
REMBRK ;REMOVE THE BREAKPOINTS
UNDBRK ;AND UNDEFINE THEM
EXIT ;LEAVE
;ACTUAL BREAKPOINT CODE
KAFTST: JRST KAFTST(3) ;JUMP TO SELF (3 HOLDS RELOCATION)
POPJ 1, ;NEVER EXECUTED BUT FOLLOWS CONVENTION
>;END REPEAT 0
;Advanced mode is for those who want a more generalized method of
;inserting breakpoints. In this mode, breakpoints and monitor references
;are defined at run-time with calls to SETBRK (for setting breaks) and
;GETADR (for finding monitor addresses). To use this mode:
;
; 1. Calling program must search UUOSYM and SNUP
;
; 2. The ADVANC macro must appear somewhere in the calling program.
; (ADVANC # possible references, # possible breakpoints)
; You must not use MONREF or BRKPNT in this mode since either would
; multiply-define some symbols.
; Private symbols are BRKBEG,CHKSUM,BRKLST,REFCNT,REFLST.
; 3. To get addresses of monitor locations, call GETADR with
; T1 -- positive word count,,address of symbol list
; GETADR returns list of addresses corresponding to
; symbols (replaces all symbols with addresses).
;
; 4. To set breakpoints, call SETBRK with
; T1 -- positive word count,,address of breakpoint list
; (breakpoint list is a list of two-word entries)
; RADIX50 0,symbol
; Address of breakpoint code
;
; SETBRK returns with breaks inserted and caller's list
; unchanged (also locked in core).
;EXAMPLE PROGRAM USING ADVANCED MODE
REPEAT 0, <
.REQUIRE SNUP
SEARCH UUOSYM,SNUP
ADVANC 5,^D64 ;MAX 5 REFERENCES, 64 BREAKPOINTS
REFS: RADIX50 0,.CPDWD ;LIST OF REFERENCES NEEDED
RADIX50 0,.CPCDB
BRKS: RADIX50 0,APRCK0 ;BREAKPOINT LIST (SYMBOL)
KAFTST ;MY CODE
RADIX50 0,DIE
DIETST
RADIX50 0,PAT
PATTST
PDL: BLOCK 50
START: MOVE P,[-50,,PDL]
MOVSI T1,2 ;WORD COUNT
HRRI T1,REFS ;ADDRESS OF MY SYMBOLS
PUSHJ P,GETADR## ;GO TRANSLATE SYMBOLS TO ADDRESSES
MOVSI T1,6 ;WORD COUNT
HRRI T1,BRKS ;ADDRESS OF MY BREAKPOINT LIST
PUSHJ P,SETBRK## ;INSERT MY BREAKPOINTS
HALT
KAFTST: JFCL ;MY BREAKPOINT CODE FOR BREAKPOINT 1
POPJ 1,
DIETST: JFCL ;FOR BREAKPOINT 2
POPJ 1,
PATTST: JFCL ;FOR BREAKPOINT 3
POPJ 1,
END START
>;END REPEAT 0
;RULES FOR BREAKPOINT CODE
;
;All memory references must be relocated by AC3. The breakpoint dispatch
;routine in SNUP saves AC 3 and puts the relocation value in it.
;
;All breakpoint routines must end in a POPJ 1, since the dispatch routine
;must restore the original contents of AC3
;
;Don't expect the pushdown stack to be exactly what it was at the time of
;the breakpoint -- The breakpoint dispatch routine is called by a PUSHJ
;and it uses the stack for saving certain things.
;
;Don't insert breakpoints where the monitor may be very deep in a stack
;or doesn't have one set up or is depending on information deeper on
;the stack than where it is.
;
;All monitor memory references must be indirect and indexed by AC3
;and must have been specified via the MONREF or BRKPNT macro.
;
;Don't use monitor AC symbols unless you define them in your calling
;program since they are different from those in SNUP (P in monitor is AC1).
; INTERNAL DESCRIPTION
;
;This module has five entry points: GETADR, SETBRK, GETINF, XCTBRK,
;and SNPFAL.
;
;GETADR accepts a list of monitor symbols and returns corresponding
;monitor addresses. It does this by calling GETINF. This entry point is
;for advanced mode (not needed for most fault insertion).
;
;SETBRK accepts a breakpoint list and inserts them by calling GETINF and
;XCTBRK. It does not reduce core before locking. This is also an "advanced"
;function.
;
;GETINF converts caller symbols into exec virtual addresses, stores
;the checksum needed in the SNOOP. UUO argument list, and returns
;to the caller. Any errors detected by this routine will result in
;an EXIT.
;
;XCTBRK locks the job in core (low seg only), defines and inserts
;breakpoints, and returns to the caller. Again, any errors
;result in an EXIT.
;
;SNPFAL is just a print-out routine for SNOOP. failures. It is
;automatically called by the REMBRK and UNDBRK macros found
;here in SNUP.
;
;Removing and undefining breakpoints are the responsibility of
;the caller (using REMBRK and UNDBRK).
;GETINF depends on information being in the following form:
;
; INTERN BRKBEG,CHKSUM,BRKLST,REFCNT,REFLST
;BRKBEG: n -- where n is the number of breakpoints
;CHKSUM: Z -- will be filled in by GETINF (checksum of monitor symbols)
;BRKLST: RADIX50 abc -- where abc is the symbol where caller wants break
; routine -- Address of user breakpoint code
; ........
; ........ (2 word entry for every breakpoint)
;
;Also needed, is the count and list of symbols needed for reference
;purposes by the breakpoint code. This can be anywhere in the caller's
;program.
;
;REFCNT: x -- where x is count of reference symbols
;REFLST: RADIX50 def -- where def is a reference symbol
; .........
; .........
;
;These things can be set up automatically by the caller using the
;BRKPNT and MONREF macros.
;When GETINF returns, all RADIX50 symbols will have been converted to
;exec virtual addresses, BRKBEG will have become an argument count for
;the SNOOP. UUO, and CHKSUM will contain the required monitor symbol
;checksum for snooping.
;
;Now the caller need only call XCTSNP to define and insert the
;breakpoints. Once inserted, the subroutine returns to the caller who
;must then decide when to remove the breakpoints using the .SORBP
;function of SNOOP. Bear in mind that upon return from XCTSNP the job
;is locked in core.
; DEFINITIONS AND SEARCHES
SALL
SEARCH JOBDAT,MACTEN,SCNMAC,UUOSYM
;VERSION DEFINITION
V.SNUP==:5
;AC DEFINITIONS
F=0 ;FLAG REGISTER
T1=1
T2=2
T3=3
T4=4
P1=5
P2=6
P3=7 ; Keeps track of where we are while reading symbols
P4=10
B=11 ; Byte pointers
C=12 ; Accumulater
ARG=16
P=17
; Monitor registers used -
%S=0
%P=1
%J=2
%R=3 ; Set up by XCTSNP when a breakpoint is hit
%F=4
%U=5
%T1=6
%T2=7
%T3=10
%T4=11
%W=12
%M=13
%P1=14
%P2=15
%P3=16
%P4=17
PLEN==100
; Definitions
; Flags
SYMBEG==400000 ; Flag symbols start at odd or even loc
RETRY==1 ; Retry for LOCKUUO
; Local maxima
M.BRKN==^D64 ; Max # breakpoints we can handle
M.REFN==^D64 ; Max # references we can handle
; Other stuff (used in symbol translation)
BP.DEF==1B0 ; This symbol has been defined
BP.MUL==1B1 ; This symbol is multiply (differently) defined
BP.GLB==1B2 ; This value is for a global definition
BP.ALL=17B3 ; All flag bits
R50GLB==1B3 ; RADIX-50 version of global bit
; Macros used by SNUP and calling program
; MONREF -- defines list of monitor references needed by caller in
;fault mode. This macro generates storage for the count of references and
;all the symbols requested by it. The funny IF2 is necessary because the
;count of symbols changes during pass 1 and doesn't get reset in
;the calling program.
REPAS2==0 ; Pass 2 flag for REFNUM
REFNUM==0
DEFINE MONREF (A),<
IRP A,<
IF2,<IFE REPAS2 <
REFNUM==0
REPAS2==1>> ;; This allows REFCNT to compile at beginning
IFE REFNUM,<
ZZ=.
REFCNT:: REFNUM
REFLST::
>
A:RADIX50 0,'A
REFNUM=REFNUM+1
RELOC ZZ
REFNUM
RELOC
>>
; BRKPNT -- defines a list of breakpoints at compile-time for
;fault mode. Allocates storage for the count of breakpoints, the checksum
;word(required by SNOOP.), and the list of two-word breakpoint entries.
;The funny IF2 is required for the same reason MONREF has it.
BRPAS2==0 ; This allows BRKCNT,CHKSUM to compile
BRKCNT==0
DEFINE BRKPNT(A,B,C),<
IF2 <IFE BRPAS2 <
BRKCNT==0
BRPAS2=1>>
IFE BRKCNT,<
IFE REFNUM,< ;; If no monitor references
REFCNT::Z ;; define so no undefineds.
REFLST::Z
>
ZZ=.
BRKBEG:: BRKCNT
CHKSUM:: Z
BRKLST::
>
IFB <C>,<
A: RADIX50 0,'A
BYTE(9)0(9)0(18)B
>
IFNB <C>,<
IF2,<
ZZZ==C
IFL <ZZZ>,<ZZZ==-ZZZ>
IFG <ZZZ-777>,<PRINTX ? Offset too large for BRKPNT macro
PRINTX ? -- with arguments A,B,C
>
>
ZZZ==C&777
RADIX50 0,A
BYTE(9)0(9)ZZZ(18)B
>
BRKCNT=BRKCNT+1
RELOC ZZ
BRKCNT
RELOC
>
; ADVANC -- Used instead of MONREF and BRKPNT when caller wants
;to control breakpoint and reference functions at run-time. This macro
;simply allocates storage for those functions to avoid undefined
;globals and extra switches in the code.
DEFINE ADVANC (A,B),<
REFCNT::A ;; Never used really
REFLST:: BLOCK A ;; Maximum number of references
BRKBEG:: B
CHKSUM:: Z
BRKLST:: BLOCK B ;; Maximum number of breakpoints
>
; Internally called macros
; Macro to generate table of error messages
DEFINE E (A), <
[ASCIZ/A/]
>
; Macro to generate error message and exit on fatal errors
DEFINE FATL (A), <
JRST [OUTSTR [ASCIZ\? A\]
EXIT]
>
; Macro to send message to TTY with CR/LF
DEFINE TELL (A), <
OUTSTR [ASCIZ\A
\]
>
; Macros to easily remove breakpoints (called by main program)
DEFINE REMBRK <
MOVSI T1,.SORBP
SNOOP. T1,
JRST [OUTSTR [ASCIZ/? Couldn't remove breakpoints/]
JRST SNPFAL##]
>
DEFINE UNDBRK <
MOVSI T1,.SOUBP
SNOOP. T1,
JRST [OUTSTR [ASCIZ/? Couldn't undefine breakpoints/]
JRST SNPFAL##]
>
; Variable storage
OPNBLK: 16 ; Open block for disk copy of running monitor
OPNDEV: BLOCK 3
FILNAM: Z ; Lookup block for disk copy of monitor
FILEXT: Z
FILNUL: Z
FILPPN: Z
FILPTH: BLOCK 11
BRKMAX: Z ; Maximum breakpoints allowed (from GETTAB)
SYMST: Z ; Start of symbol table in disk copy of monitor
SYMLEN: Z ; Length of symbol table in disk copy of monitor
BSYMOK: Z ; Count of breakpoint symbols found in monitor
RSYMOK: Z ; Count of reference symbols found in monitor
; Symbols required in main program are defined here.
EXTERN BRKBEG,CHKSUM,BRKLST,REFCNT,REFLST
; GETADR -- Finds addresses for monitor symbols. Use this if
;you want to control breakpoint insertion at run-time (advanced mode)
;rather than at compile-time(fault mode).
;Symbols to be converted must be in RADIX50 format.
;CALL WITH:
; T1 -- positive word count,,address of symbol list
;RETURNS:
; Symbols in specified list converted to addresses
GETADR::HLREM T1,T3 ; Save word count
JUMPL T3,[FATL Called GETADR with negative count]
HRL T2,T1 ; Make BLT pointer
HRRI T2,REFLST ; To REFLST
BLT T2,REFLST-1(T3) ; Move list of symbols
MOVEM T3,REFCNT ; Store count
SETZM BRKBEG ; Indicate don't do breaks
SETZM BSYMOK ; Bypass that test in GETINF
PUSH P,T1 ; Save symbol addresses
PUSHJ P,GETINF ; Go convert symbols
POP P,T1 ; Get addresses back
ADDM T1,REFCNT ; Make BLT back to caller's area
HRLI T1,REFLST
HRRZ T2,REFCNT
BLT T1,-1(T2) ; Move addresses to caller
POPJ P, ; Return to him
; SETBRK -- Called by main program to insert breakpoints from
;arguments supplied by it. Like GETADR use this entry point only when you
;must control breakpoint initiation at run-time rather than at compile-time.
;
;CALLED WITH:
; T1 -- positive word count,,address of breakpoint arguments
;RETURNS:
; Breakpoints inserted
SETBRK::HLREM T1,T3 ; Save word count
JUMPL T3,[FATL Called SETBRK with negative word count]
HRL T2,T1 ; Make BLT pointer to BRKLST
HRRI T2,BRKLST
BLT T2,BRKLST-1(T3)
LSH T3,-1 ; Make T3 = # of breakpoints
MOVEM T3,BRKBEG
SETZM REFCNT ; Prohibit reference symbol finding
SETZM RSYMOK ; Bypass that test in GETINF
PUSHJ P,GETINF ; Set up SNOOP. UUO info
PJRST XWRSNP ; Execute breakpoints without
; Reducing core.
; GETINF -- Reads monitor specified by GETTAB as being the
;disk copy of the currently running monitor. Since SNOOP. requires
;the checksum of the symbol table, we do the checksumming while
;finding the virtual addresses for all the breakpoints.
;CALL WITH:
; No arguments
;RETURNS:
; Symbol table checksummed
; Symbols converted to exec virtual addresses
;ERRORS:(ALL FATAL)
; Too many breakpoints requested
; Requested symbols not found
; Too many symbols found (used a local?)
GETINF::PUSHJ P,FNDFIL ; Read disk copy of mon
PUSHJ P,SETSYM ; Get our own copy of BRKLST and REFLST
PUSHJ P,REDSYM ; Read and checksum symbols
PUSHJ P,FORMIT ; Form the dispatch vector
MOVE T1,BRKBEG ; Then check for too many breaks
CAMLE T1,BRKMAX
FATL Too many breakpoints for this monitor
LSH T1,1 ; Multiply by 2 (words in entry)
AOS T1 ; Set to include checksum
EXCH T1,BRKBEG ; And save it, get old value to
PUSHJ P,INFCHK ; Validate symbols translated OK
RELEASE ; Don't need .EXE file anymore
POPJ P,
; Copy the symbols from user space to our space
SETSYM: MOVE T1,BRKBEG ; How many breakpoints
CAILE T1,M.BRKN ; Too many?
FATL Too many breakpoints for SNUP subroutines
MOVNS T1 ; -How many breakpoints
HRLZS T1 ; -N,,0
SKIPN T2,T1 ; A copy for outputting
JRST SETREF ; No breakpoints (unusual)
SBLOOP: MOVE T3,BRKLST(T1) ; Get a symbol
TLZ T3,(74B5) ; No Flags (we have our own)
MOVEM T3,B.OURS(T2) ; Copy over
ADDI T1,2 ; Past subroutine to call (forget LH)
AOBJN T2,SBLOOP ; Continue until done
SETREF: SKIPN T1,REFCNT ; Get # of references
POPJ P,
CAILE T1,M.REFN ; Too many?
FATL Too many reference symbols for SNUP subroutine
MOVNS T1
HRLZS T1
SRLOOP: MOVE T2,REFLST(T1) ; Get a symbol
TLZ T2,(74B5) ; No flags again
MOVEM T2,R.OURS(T1) ; Ship it out
AOBJN T1,SRLOOP ; Go thru the list
POPJ P, ; Done
; Check consistency of symbols. All must be found and not
; multiply-defined.
INFCHK: JUMPE T1,INFREF ; Jump if no breakpoints supplied
; (for real)
IBLOOP: SKIPL T2,B.OURS-1(T1) ; Is it defined?
FATL Undefined breakpoint symbol(s)
TXNE T2,BP.MUL ; Multiply-defined?
FATL Multiply-defined breakpoint symbol(s)
SOJG T1,IBLOOP ; Go thru them all
; Same treatment for reference symbols
INFREF: SKIPN T1,REFCNT ; Any references ?
POPJ P, ; No references, no work for you
IRLOOP: SKIPL T2,R.OURS-1(T1) ; This reference defined?
FATL Undefined MONREF symbol(s)
TXNE T2,BP.MUL ; Multiply-defined?
FATL Multiply-defined MONREF symbols
SOJG T1,IRLOOP ; Loop until done
POPJ P, ; Then return
; XCTSNP -- Defines and inserts breakpoints according to BRKLST
; Called by main program with no arguments but with
; BRKLST set up by a previous call to GETINF.
; (Entered at XWRSNP in advanced mode)
XCTSNP::MOVEI T1,LOKEND ; Reduce core
CORE T1,
TELL Unable to reduce core but continuing
XWRSNP::PUSHJ P,LOKSEG ; LOCK in core
PUSHJ P,CNVADR ; Go relocate breakpoint code
REDEFP::MOVE T1,[.SODBP,,BRKBEG]
SNOOP. T1, ; Define breakpoints
JRST SNPFAL
REINSP::MOVSI T1,.SOIBP ; Execute the fault
SNOOP. T1,
JRST SNPFAL ; Failed
POPJ P, ; Return to caller
;Routine to print an error message corresponding to code in T1
;Called after a SNOOP. error return.
SNPFAL::OUTSTR [ASCIZ/?SNOOP. failed -- /]
MOVE T1,SNPERR(T1)
OUTSTR @T1
EXIT
SNPERR: E Not an error
E Illegal argument
E Not privileged
E Someone else snooping
E Exceeded max breakpoints
E Function illegal when breaks already inserted
E No monitor free core
E Address check
E Illegal if not LOCKed
E Checksum of running monitor doesn't match disk copy
; FNDFIL -- Find disk copy of currently running monitor
;CALL WITH:
; No arguments
;RETURNS:
; Monitor .EXE file open and directory page in INBUFF
;ERRORS:
; GETTAB failures (EXIT)
; Can't OPEN device
; Can't find file
; I/O errors
FNDFIL: MOVX T1,%CNMBS ; Get structure
GETTAB T1,
JRST GTBFAL
MOVEM T1,OPNDEV ; Save in OPEN block
MOVX T1,%CNMBF ; Get monitor file name
GETTAB T1,
JRST GTBFAL
MOVEM T1,FILNAM ; Save in LOOKUP block
MOVX T1,%CNMBX ; Get file extension
GETTAB T1,
JRST GTBFAL
MOVEM T1,FILEXT
MOVEI T1,FILPTH
MOVEM T1,FILPPN
SETZM FILPTH
SETZM FILPTH+1
MOVX T1,%CNMBD ; Get PPN
GETTAB T1,
JRST GTBFAL
MOVEM T1,FILPTH+2
DEFINE GSFD(ARG)<IRPC ARG,< ;; Go thru all SFDs that the
MOVX T1,%CNSF'ARG ;; monitor may have come from
GETTAB T1,
SETZM T1
MOVEM T1,FILPTH+2+ARG>
>
GSFD <12345>
SETZM FILPTH+2+6
MOVX T1,%CNBPM ; Get maximum breakpoints
GETTAB T1,
JRST GTBFAL
MOVEM T1,BRKMAX ; Save for later
OPEN OPNBLK ; See if we can OPEN device
FATL Can't open device where monitor lives
LOOKUP FILNAM ; Now LOOKUP the file
FATL Can't find monitor on the disk
PJRST REDDIR ; Go read directory and return
GTBFAL: FATL GETTAB failed (trying to find disk copy of monitor)
; REDDIR -- Reads EXE directory for selected monitor
; Won't work if directory gets bigger than one block
;CALL WITH:
; No arguments
; .EXE file open on channel zero
;RETURNS:
; Directory in DIRECT
;ERRORS:(ALL FATAL)
; I/O errors
; Not an .EXE file
; Directory bigger than one disk block
REDDIR: USETI 1 ; Set to block 1
IN [IOWD ^D128,DIRECT
0]
SKIPA T1,DIRECT ; Success -- get header.
FATL Error reading directory of monitor
HLRZ T2,T1 ; Get directory header code
CAIE T2,1776 ; Is it good?
FATL Bad .EXE file -- header code not good
HRRZS T1 ; Get rid of code
CAILE T1,^D128 ; Is directory too big for program?
FATL .EXE directory too big for program
MOVEM T1,DIRECT ; No, save it without code
POPJ P, ; and return
; REDSYM -- Reads entire symbol table from the disk and, while
;checksumming it, searches for matching symbols.
;CALL WITH:
; Directory in DIRECT
; File open
;RETURNS:
; CHKSUM (should match monitor's computation)
; Symbolic breakpoints converted to virtual addresses
REDSYM: PUSHJ P,GETSYM ; Get symbol table
SETZM CHKSUM ; Clear checksum
CHKTBL: ANDI T1,777 ; Use offset for index
MOVEI P3,^D512 ; Set length of page
SUB P3,T1
MOVNS P3 ; - # of words to read this page
CAMG P3,SYMLEN ; unless not full page of syms
MOVE P3,SYMLEN
HRL T1,P3 ; Make an AOBJN pointer
PUSHJ P,SUMSYM ; Checksum the table
MOVNS P3 ; How many done?
ADDM P3,SYMLEN
SKIPL SYMLEN ; Done?
POPJ P, ; Yes. Return
PUSHJ P,NXTSYM ; No. Get another page
JRST CHKTBL ; and process it
; GETSYM -- reads the first symbol table page
;CALL WITH:
; No arguments
;RETURNS:
; First symbol table page in INBUFF
; odd/even start flag set (so we know which is symbol in pair)
; Start address of symbol table
; Length of symbol table
GETSYM: MOVEI T1,.JBSYM ; Get pointer from file
PUSHJ P,FNDVIR
HLREM T2,SYMLEN ; Save length
HRRZM T2,SYMST ; and start of table
TRNN T2,1 ; Starting at odd location?
TLZA F,SYMBEG ; No. Flag start at even
TLO F,SYMBEG ; Yes. Flag odd
HRRZ T1,SYMST
PJRST FNDVIR ; Read first symbol table page
; NXTSYM -- reads next symbol table page
;CALL WITH:
; SYMST pointing to last page read (virtual)
;RETURNS:
; Next page in INBUFF
; Symst pointing to new page (virtual address)
NXTSYM: MOVE T1,SYMST ; Get last page
ADDI T1,1000 ; Increment it
TRZ T1,777 ; Get rid of any offset
MOVEM T1,SYMST ; Save for next time
;;; PJRST FNDVIR ; Read it and return
; FNDVIR -- Find a word in an .EXE file
;CALL WITH:
; T1 -- Virtual address you want the contents of
; -- Channel 0 open to the disk file
; -- Directory for file in DIRECT
;RETURNS:
; T1 -- -1 if page was not read because it was allocated but zero
; or the virtual address if the page was read into INBUFF
; T2 -- Contains the contents of the desired virtual address
;ERRORS:
; (ALL FATAL)
; 1. EOF while reading directory page
; 2. Bad .EXE file (directory wrong)
; 3. Desired address not in the directory
; 4. EOF reached before desired address found
FNDVIR: PUSH P,T1 ; Save virtual address desired
LSH T1,-^D9 ; Just look at page
MOVEI T4,1 ; Initialize buffer index
MOVE C,DIRECT ; Get word count of directory
FNDLUP: SUBI C,2 ; Decrement directory count
SKIPG C ; Still have entries?
FATL Desired address not in .EXE file
AOS T4 ; Point to virtual page
LDB T2,[POINT 9,DIRECT(T4),8] ; Get repeat count
HRRZ T3,DIRECT(T4) ; and first page in group
ADD T2,T3 ; Make last page in range
CAMG T1,T2 ; Desired page in range?
CAMGE T1,T3
AOJA T4,FNDLUP ; No. Keep trying.
SUB T1,T3 ; Yes. Find offset from page 1
HRRZ T2,DIRECT-1(T4) ; Now get file page #
JUMPE T2,NOTALC ; Return zero if not allocated
ADD T1,T2 ; Find file page to read
PUSHJ P,RDPAGE ; Go read it
FATL EOF before address found ;If directory is wrong
MOVE T1,(P) ; Get desired address back
ANDI T1,777 ; Just the offset
SKIPA T2,INBUFF(T1) ; Get desired word
NOTALC: SETOM (P) ; Flag page not in file
POP P,T1 ; Get virtual address back
POPJ P, ; and go away
; RDPAGE -- Read a selected page from an .EXE file
;CALL:
; T1 -- CONTAINS PAGE NUMBER TO READ
; -- CHANNEL 0 OPEN TO AN EXE FILE
;RETURNS:
; T1 -- FIRST BLOCK READ
; INBUFF -- THE PAGE READ FROM DISK
; NON-SKIP -- EOF WAS ENCOUNTERED
; SKIP -- PAGE WAS SUCCESSFULLY READ
;ERRORS:
; FATAL -- ANY I/O ERROR DURING THE READ
RDPAGE: LSH T1,2 ;MAKE PAGE A BLOCK #
USETI 1(T1) ;SET TO FIRST BLOCK IN PAGE
IN [IOWD ^D<512+128>,INBUFF
0]
AOSA (P) ;SUCCESSFULLY READ A PAGE
STATZ IO.EOF ;GET AN EOF?
POPJ P, ;YES. NON-SKIP RETURN
FATL I/O error reading .EXE file
; SUMSYM -- Checksums monitor symbol table and calls CMPCHK to see
; if each symbol may be one we're looking for.
; Call with:
; Symbol table page in INBUFF
; T1 containing AOBJ pointer to symbols in INBUFF
; Returns:
; Current page checksummed
; Symbols in BRKLST and REFLST converted to addresses
SUMSYM: MOVE T3,INBUFF(T1) ; Get a symbol table word
EXCH T3,CHKSUM ; Checksum it
ROT T3,1
ADD T3,CHKSUM
EXCH T3,CHKSUM
PUSHJ P,CMPCHK ; See if time to compare syms
AOBJN T1,SUMSYM ; Loop thru page
POPJ P, ; Then get out
CMPCHK: TRNE T1,1 ; Odd location?
JUMPL F,COMSYM ; Yes. if odd first,compare sym
TRNN T1,1 ; Even location?
JUMPGE F,COMSYM ; Yes. if even first, compare sym
POPJ P, ; Not a symbol. no compare.
COMSYM: MOVE C,INBUFF(T1) ; Save symbol for compare
MOVE T2,C ; in case of multiple defns.
TXZ T2,BP.ALL ; This symbol is nothing (yet)
TXNE C,R50GLB ; Is it global?
TXO T2,BP.GLB ; Yes, light magic bit
MOVEM T2,NEWSYM ; Save that symbol!
MOVE P1,BRKBEG ; Prepare to check breaks
COMLUP: MOVE P2,P1
LSH P2,1
MOVE T3,B.OURS-1(P1) ; Get the symbol
MOVEM T3,OLDSYM ; Save as OLDSYM
XOR T3,C ; Compare versus this one
TXZ T3,BP.ALL ; Skip flag bits
JUMPN T3,NOMTCH ; No match
; Match !
MOVE T2,INBUFF+1(T1) ; Get the value
MOVEM T2,NEWVAL ; Call it NEWVAL
SKIPL B.OURS-1(P1) ; Already defined?
JRST SETNEW ; No, just set it up
; Falls thru to next page ...
; Falls in from last page ...
; Symbol is already defined! See about conflicts, etc.
MOVE T2,BRKLST-2(P2) ; Get what will now be
MOVEM T2,OLDVAL ; OLDVAL, too
PUSHJ P,MULTCH ; See about multiples
SETNEW: MOVE T2,NEWVAL ; Get new value
MOVEM T2,BRKLST-2(P2) ; Save it
MOVE T2,NEWSYM ; Get new symbol
TXO T2,BP.DEF ; It is now defined
MOVEM T2,B.OURS-1(P1) ; Save it, too
NOMTCH: SOJG P1,COMLUP ; Loop until done
SKIPN P1,REFCNT ; Any references?
POPJ P, ; No references, no work
RXLOOP: MOVE T3,R.OURS-1(P1) ; Get a symbol
MOVEM T3,OLDSYM ; Save as OLDSYM
XOR T3,C ; Mix it up a little
TXZ T3,BP.ALL ; Skip flag bits
JUMPN T3,RXCONT ; Found a match?
MOVE T3,INBUFF+1(T1) ; Yes -- get the value and
MOVEM T3,NEWVAL ; Save it as NEWVAL for now
SKIPL R.OURS-1(P1) ; Already defined?
JRST REFNEW ; No, use this value
; Symbol is already defined! See about conflicts, etc.
MOVE T2,REFLST-1(P1) ; Get the old value and
MOVEM T2,OLDVAL ; save for comparison
PUSHJ P,MULTCH ; Set up [NEWSYM,NEWVAL]
REFNEW: MOVE T2,NEWVAL ; Take returned stuff (even if
MOVEM T2,REFLST-1(P1) ; same value as before)
MOVE T2,NEWSYM ; Get the symbol (NEW or OLD)
TXO T2,BP.DEF ; Make it defined
MOVEM T2,R.OURS-1(P1) ; in our flag area
RXCONT: SOJG P1,RXLOOP ; Loop thru our symbols
POPJ P, ; Done scanning symbols, return
; Special logic to see what to do with multiply-defined symbols.
; Enter with [OLDSYM,OLDVAL] containing (our) symbol+flags, value
; pair and likewise for [NEWSYM,NEWVAL]. To be honest, this is
; an edit and rather than polish every machine cycle I'm just
; going to come up with a usable interface. You other hackers
; out there can do it right yourselves.
; Returns information to use in [NEWSYM,NEWVAL]
MULTCH: PUSH P,T1 ; T1 points to disk buffer (!)
PUSHJ P,BMNOIL ; Go check it out
POP P,T1 ; Restore "preserved temporary"
POPJ P, ; and return
BMNOIL: MOVX T2,BP.GLB ; A useful flag
MOVE T1,OLDVAL ; Get OLDVAL
CAMN T1,NEWVAL ; Are values same?
JRST CHKGLB ; Yes, see if its now global
TDNN T2,OLDSYM ; Different values. Is old global?
JRST OLDLOC ; Old is local. Check new.
TDNE T2,NEWSYM ; Old is global. Is new too?
JRST SETMUL ; Yep--some jerk has a muldefglb!
MOVEM T1,NEWVAL ; Nope. Use old value-its global
MOVE T1,OLDSYM ; Return value (OLDSYM) in NEWSYM
MOVEM T1,NEWSYM ; ...
POPJ P, ; And finally return
OLDLOC: TDNN T2,NEWSYM ; Old is local. Is new?
JRST SETMUL ; Yep. Multiply-defined locals
JRST SETOKG ; New is global. Use [NEWVAL,NEWSYM]
CHKGLB: TDNN T2,OLDSYM ; Values equal. Old one global?
POPJ P, ; No-use [NEWSYM,NEWVAL]
SETOKG: MOVX T2,BP.DEF!BP.GLB; Set new symbol to be global
IORM T2,NEWSYM ; and defined.
MOVX T2,BP.MUL ; and clear any multiples that
ANDCAM T2,NEWSYM ; happen to be around
POPJ P, ; happy, return
SETMUL: MOVX T2,BP.DEF!BP.MUL; Make this multiply-defined
IORM T2,NEWSYM ; in NEWSYM
POPJ P, ; Unhappy, return
; FORMIT -- After symbols have been translated, come here
; to convert breakpoint symbol to virtual address, and set up
; breakpoint dispatch table.
; Call with:
; BRKLST values set up
; Returns:
; BRKLST dispatch instructions set up
FORMIT: SKIPN P1,BRKBEG ; Number of breakpoints in P1
POPJ P, ; ??? No breakpoints, no work
FORMLP: MOVE P2,P1 ; For indexing into BRKLST
LSH P2,1 ; we count P2 = P1 pairs
HLRZ C,BRKLST-1(P2) ; Get offset in bits 27-35
LSH C,^D27 ; Allow for negative offsets
ASH C,-^D27 ; There we go
ADDM C,BRKLST-2(P2) ; Form monitor virtual address
HRRZ C,BRKLST-1(P2) ; Get code to execute
MOVEM C,BRKDSP(P1) ; Save it in dispatch list
MOVEI C,DSPIDX(P1) ; Pick up dispatch address
HRLI C,(PUSHJ %P,0) ; Form instruction
MOVEM C,BRKLST-1(P2) ; And save it for SNOOP.
SOJG P1,FORMLP ; Go do next one
POPJ P, ; And return
; LOKSEG -- LOCKs low segment into contiguous EVM
;Call: (no arguments)
;Returns:
; -- Low segment LOCKed in core
;Errors: (all fatal)
LOKERR: E LOCK not implemented
E no LOCK privilege
E If LOCKed couldn't run largest existing job
E If LOCKed couldn't guarantee cormin
E No room in EVM
E Illegal subfunction
E Page unavailable
E Tried to LOCK again in an illegal way
LOKSEG: TRZ F,RETRY ; Init retry flag
LOKSE1: MOVEI T1,LK.LNP+LK.LLS; Set up LOCK bits
LOCK T1, ; Attempt to lock
SKIPA T2,LOKERR(T1) ; Failed. Get message
POPJ P, ; Success. Exit.
CAIL T1,2 ; Possible to recover?
CAILE T1,4
SKIPA ; No.
TRCE F,RETRY
JRST [OUTSTR @T2 ; Can't recover
EXIT]
MOVEI T1,5 ; Try again after 5 seconds
SLEEP T1,
JRST LOKSE1
; CNVADR -- Relocates breakpoint dispatch code and addresses
;This is necessary because when a breakpoint happens, mapping is through
;the EBR and the code is still user virtual memory.
;CALL WITH:
; T1 -- Exec virtual page of our program
;Returns:
; All necessary locations relocated to exec virtual addresses
CNVADR: TLZ T1,-1 ; Ignore any high seg page number
LSH T1,^D9 ; Make page an address
MOVEM T1,EVBASE ; Save it for breakpoint dispatch code
MOVEI T2,<2*M.BRKN> ; Set to relocate tables
CNVLUP: ADDM T1,DSPADR(T2) ; Relocate a table word
SOJGE T2,CNVLUP ; Until done
ADDM T1,IDXCHG ; Relocate reference instruction
ADDM T1,EVGET ; Reloc get-EVA-base instruction
MOVE P1,BRKBEG ; Now change breakpoint instructions
SUBI P1,1 ; Convert back from SNOOP. argument
LSH P1,-1 ; length to number of breakpoints.
CNVBRK: MOVE P2,P1 ; Next breakpoint
LSH P2,1 ; Account for 2-word entry
ADDM T1,BRKLST-1(P2) ; Relocate
SOJG P1,CNVBRK ; Do all breakpoints
POPJ P, ; and return
; BREAKPOINT DISPATCH AREA -- ALL BREAKPOINTS COME HERE FIRST
EVBASE: Z ;RELOCATION SAVED BY LOCK RETURN
;The following list of PUSHJs are to tell GETREL where to go.
;Relocate DSPADR to end of DSPIDX plus IDXCHG and EVGET.
DSPADR: BRKDSP
BRKDSP: BLOCK M.BRKN ;BREAKPOINT CODE DISPATCH TABLE
DSPIDX: REPEAT M.BRKN,<
PUSHJ 1,GETREL
>
; GETREL -- The breakpoint dispatch routine executed first by all
;breakpoints. It saves AC3 and sets it to the relocation value
;before going off to the user breakpoint code. When
;the fault code returns, AC3 is restored and a skip-return from
;the user code will be propagated back to the monitor.
GETREL: EXCH 3,(1) ;GET CALL. SAVE AC
IDXCHG: SUBI 3,DSPIDX+1 ;GET ADDRESS TABLE INDEX
HRLI 3,20 ;SET INDIRECT BIT
EVGET: PUSH 1,EVBASE ;SAVE RELOCATION
EXCH 3,(1) ;GET RELOCATION. SAVE INDEX
PUSH 1,DSPADR(3) ;SAVE RELOCATED DISPATCH ADDRESS
EXCH 3,(1) ;SAVE BASE. GET DISPATCH
ADDM 3,-1(1) ;ADD RELOCATED DISPATCH TO INDEX
POP 1,3 ;GET BASE FOR USER CODE
PUSHJ 1,@(1) ;GO TO USER CODE
CAIA ;NON-SKIP RETURN
AOS -2(1) ;PROPAGATE SKIP-RETURN
POP 1,(1) ;REMOVE DISPATCH
POP 1,3 ;RESTORE ORIGINAL MONITOR AC
POPJ 1, ;RETURN TO MONTIOR
XLIST
LIT
LIST
LOKEND: Z ;LAST LOCATION BEFORE CORE REDUCTION
; Storage for symbols supplied by user (MONREF/BRKPNT).
B.OURS: BLOCK M.BRKN ; Breakpoints
R.OURS: BLOCK M.REFN ; References
OLDSYM: BLOCK 1
OLDVAL: BLOCK 1
NEWSYM: BLOCK 1
NEWVAL: BLOCK 1
ENDCAM==. ; End of our symbol area
;Page buffer and directory buffer for disk copy of monitor. This
;portion is given up prior to locking the job in core since it is
;only used to get the symbol table.
;(In advanced mode, core not given up since caller may need it)
DIRECT: BLOCK ^D128 ; Directory goes here
INBUFF: BLOCK ^D512 ; EXE file pages go here
BLOCK ^D128 ; What a crock. See revision
; history for the explanation.
END