	.TITLE	TSKIMG
	.IDENT	"V1.1"
	.NLIST	BEX,CND
;
;   Author:	D. Mischler	02-FEB-89
;
;   This module replaces DBG modules EXECUTE, INIT, SIM11 and
;   TSKCOM.  It causes DBG to operate on a task image file instead
;   of an active task.  The resulting utility manipulates task
;   image files like ZAP (except overlays are not supported).
;   This module must be assembled with the executive macro
;   library (LB:[1,1]EXEMC.MLB) and the DBG prefix file.
;
IMGLUN	=	TI+1		; Task image file LUN.

	.MCALL	DIR$,EXIT$S,GMCR$,GTSK$S,QIOW$,QIOW$S
	.MCALL	CLOSE$,FDBDF$,FDOP$A,FDRC$A,NMBLK$,OPEN$
	.MCALL	CSI$,CSI$1,CSI$2,CSI$ND,CSI$SW
	.MCALL	HDRDF$,LBLDF$
	CSI$
	HDRDF$
	LBLDF$

	.ASECT
;
;   Mapping table format.
;
	.=0
M.IVBN:	.BLKW	1	; Image virtual block number.
M.VBAS:	.BLKW	1	; Virtual base address.
M.VMAX:	.BLKW	1	; Virtual maximum address.
M.LEN:
	.PAGE
	.PSECT	DATA,D,RW
;
;   Address mapping tables and pointers.
;
ASPTBL:	.WORD	ISMTBL,ISMTBL,0	; Address space table.
DSMTBL:	.BLKW	M.LEN+1		; D space mapping tables.
ISMTBL:	.BLKW	M.LEN+1		; I space mapping tables.
;
;   Data definitions.
;
CURBLK:	.WORD	0		; VBN of buffered task image file block.
GETMCR:	GMCR$			; Get MCR command line DPB.
IMGBUF:	.BLKW	256.		; Image file buffer.
IMGCSI:	.BLKB	C.SIZE		; Image file CSI control block.
IMGDFN:	NMBLK$	,TSK,0,SY,0	; Default filename block for image file.
IMGFDB:	FDBDF$			; Image file FDB.
	FDOP$A	IMGLUN,IMGCSI+C.DSDS,IMGDFN,FO.MFY
	FDRC$A	FD.RWM
IMGRVB:	QIOW$	IO.RVB,IMGLUN,IOEFN,,IMGSTS,,<IMGBUF,512.,,0,1>
IMGSTS:	.BLKW	2		; Image file I/O status block.
RDONLY:	.WORD	0		; Read-only access flag.
SWITBL:	CSI$SW	RO,1,RDONLY	; Switch table entry for /RO switch.
	CSI$ND

ERRBUF:	.ASCIZ	"177777"
EXCERR:	.ASCIZ	"Not executable"
FILERR:	.ASCIZ	"FCS error % on task image file"
IMGERR:	.ASCIZ	<LF>"Task image file is bogus - exiting"

INIMSG:	.ASCII	<LF>"Kludge-o-matic Task Zapper "
VRSION:	.ASCIZ	"vrsion - tsknam"

TSKPRM:	.ASCII	<CR><LF>"Task image file? "
TSKPRL	=	.-TSKPRM
	.EVEN
	.PAGE
	.PSECT	CODE,I,RO
;
;   Perform one-time initialization.
;   On entry:	R3 & R4 contain task version.
;   On exit:	Carry will always be clear.
;
INIT::	MOV	#VRSION,R0		; Point to version number.
	MOV	R3,R1			; Get first version word.
	CALL	$C5TA			; Make it ASCII.
	MOV	R4,R1			; Get second version word.
	CALL	$C5TA			; Make it ASCII too.
	CALL	U$RMTB			; Remove trailing blanks.
	MOV	R0,-(SP)		; Save message pointer for later.
	GTSK$S	#TRMBUF			; Get task parameters.
	MOV	#LOGPRM,R0		; Point to log file prompt.
	MOV	TRMBUF,R1		; Get hi word of task name.
	CALL	$C5TA			; Convert it to ASCII.
	MOV	#TRMPRM,R0		; Point to terminal prompt.
	MOV	TRMBUF,R1		; Get hi word of task name.
	CALL	$C5TA			; Convert it to ASCII.
GETSKN:	MOV	#GETMCR,R0		; Point to GMCR$ DPB.
	DIR$	R0			; Get MCR command line, OK?
	BCC	10$			; Yes, get target task name.
	MOV	#<"D >,G.MCRB(R0)	; Set up a dummy command.
	MOV	#TSKPRM,TRMOUT+Q.IOPL	; Stuff message address
	MOV	#TSKPRL,TRMOUT+Q.IOPL+2	;  and length in DPB.
	DIR$	#TRMOUT			; Prompt for task name.
	SUB	#4,SP			; Make room for an I/O status block.
	MOV	SP,R5			; Point to it.
	QIOW$S	#IO.RLB,#TI,#IOEFN,,R5,,<#GETMCR+G.MCRB+2,#40.>
	MOV	(SP)+,R0		; Get completion status.
	ADD	#2,(SP)			; Add extra characters to length.
	MOV	(SP)+,$DSW		; Make it look like GMCR$ result.
	CMPB	#IS.SUC,R0		; Did any driver errors occur?
	BEQ	10$			; No, parse result.
	CMPB	#IE.EOF,R0		; Did the user type ^Z?
	BNE	GETSKN			; No, try again.
	EXIT$S				; Terminate.
;   Parse command line for task image file name.
10$:	MOV	#GETMCR+G.MCRB,R0	; Point to command line buffer.
	MOV	$DSW,R1			; Get command line length.
	ADD	R0,R1			; Point to end of buffer.
	CLRB	(R1)			; Terminate buffer.
	CALL	U$CLFX			; Fix up command line.
	CALL	U$FNXT			; Point to task name, OK?
	BCS	GETSKN			; No, try again.
	.PAGE
;
;   Call CSI to parse file name.
;
	MOV	R0,-(SP)		; Save filename string base address.
20$:	TSTB	(R0)+			; Found end of string yet?
	BNE	20$			; No, keep looking.
	DEC	R0			; Back up to terminator.
	SUB	(SP),R0			; Get filename string length.
	MOV	R0,IMGCSI+C.CMLD	; Save length in CSI block.
	MOV	#IMGCSI,R0		; Point to CSI control block.
	MOV	(SP)+,C.CMLD+2(R0)	; Save filename string address too.
	CSI$1				; Perform syntax analysis, OK?
	BCS	GETSKN			; No, complain.
	CSI$2	,OUTPUT,#SWITBL		; Build data-set descriptor, OK?
	BCS	GETSKN			; No, complain.
	MOVB	#FO.MFY,IMGFDB+F.FACC	; Assume modify access.
	TST	RDONLY			; Should file be read only?
	BEQ	30$			; No, allow modify access to stand.
	MOVB	#FO.RD,IMGFDB+F.FACC	; Set file access to read only.
;
;   Attempt to open task image file.
;
30$:	OPEN$	#IMGFDB			; Open the task image file, OK?
	BCC	40$			; Yes, go on...
	MOV	#ERRBUF,R0		; Point to error code buffer.
	MOV	IMGFDB+F.ERR,R1		; Get error code.
	CLR	R2			; Suppress leading zeroes.
	CALL	$CBOMG			; Convert code to octal.
	CLRB	(R0)			; Terminate error code.
	MOV	#ERRBUF,R0		; Point to error code buffer.
	MOV	#FILERR,R1		; Point to file error message.
	CALL	ERROR			; Display error.
	BR	GETSKN			; Try again.
;
;   The task image file looks OK.
;
40$:	CALL	IMGSET			; Set up image file handling, OK?
	BCS	110$			; No, forget all about it.
	MOV	(SP)+,R0		; Pop initialization message pointer.
	MOVB	#' ,(R0)+		; Delimit version and file name.
	MOVB	#'-,(R0)+
	MOVB	#' ,(R0)+
	MOV	IMGFDB+F.FNB+N.FNAM,R1	; Get high word of task image name.
	CALL	$C5TA			; Convert it to ASCII.
	MOV	IMGFDB+F.FNB+N.FNAM+2,R1; Get next word of task image name.
	CALL	$C5TA			; Convert it too.
	MOV	IMGFDB+F.FNB+N.FNAM+4,R1; Get last word of task image name.
	CALL	$C5TA			; Convert it.
	CLRB	(R0)			; Terminate message.
	MOV	#INIMSG,R1		; Point to startup message.
	CALL	LINOUT			; Display it.
	.PAGE
;
;   Display task image virtual addresses.
;
	MOV	#ISMTBL,R5		; Point to I-space mapping table.
	MOV	#TRMBUF,R0		; Point to terminal buffer.
	MOVB	#'I,(R0)+		; Indicate this is I-space.
	CALL	DSPADR			; Display I-space addresses.
	MOV	#DSMTBL,R5		; Point to D-space mapping table.
	TST	(R5)			; Is D-space mapped over I-space?
	BEQ	50$			; Yes, ignore it.
	MOV	#TRMBUF,R0		; Point to terminal buffer.
	MOVB	#'D,(R0)+		; Indicate this is D-space.
	CALL	DSPADR			; Display D-space addresses.
;
;   Modify DBGAID address violation SST vectors to catch illegal accesses.
;
50$:	MOV	$DBG$V,AIDOAV		; Save DBGAID odd address vector.
	MOV	#OAVSST,$DBG$V		; Set up special vector.
	MOV	$DBG$V+2,AIDMPV		; Save DBGAID memory protect vector.
	MOV	#MPVSST,$DBG$V+2	; Set up special vector.
;   Initialize the free memory list.
	MOV	#FREMEM,R0	; Point to free memory list head.
	CLR	(R0)		; Empty the free memory list.
	MOV	2(R0),R2	; Get address of possible free memory.
	MOV	R2,R1		; Copy it.
	ADD	#63.,R1		; Adjust to next multiple of 64 bytes.
	BIC	#63.,R1
	MOV	R1,2(R0)	; Save next free address.
	SUB	R2,R1		; Calculate size of free memory.
	CMP	R1,#4		; Is it usable?
	BLO	100$		; No, throw it away.
	CALL	$RLCB		; Put initial free memory on free list.
100$:	CLC			; Indicate normal startup.
	RETURN
;
;   Here if image file setup fails.
;
110$:	MOV	#IMGERR,R1
	CALL	ERROR
	JMP	ABORT
	.PAGE
;
;   Routine to initialize image file handling.
;   On exit:	Carry set if an error is detected.
;
IMGSET:	DIR$	#IMGRVB			; Read label block 0, OK?
	BCS	1$			; No, can it.
	TSTB	IMGSTS			; Success?
	BPL	2$			; Yes, go ahead and look at it.
1$:	JMP	120$			; Exit with failure.
2$:	MOV	#IMGBUF,R0		; Point to image file label block.
	MOV	#ISMTBL,R2		; Point to I-space mapping table.
	MOV	L$BSA(R0),M.VBAS(R2)	; Save virtual base address.
	MOV	L$BHGV(R0),M.VMAX(R2)	; Save I-space virtual maximum.
	MOV	L$BHRB(R0),M.IVBN(R2)	; Set up I-space header VBN.
	INC	M.IVBN(R2)
	CMPB	L$BSYS(R0),#4		; Does this task use M-PLUS features?
	BNE	100$			; No, set up registers, etc.
;
;   Here for a task which uses RSX-11M-PLUS features.
;
	MOV	R0,R1			; Copy label block pointer.
	ADD	#340,R1			; Skip over extra M-PLUS info.
	MOV	L$BHRB(R1),M.IVBN(R2)	; Set up I-space header VBN.
	INC	M.IVBN(R2)
	TST	L$BHDB(R1)		; Does task have separate I/D space?
	BEQ	10$			; No, skip over I/D space code.
;   Set up data space mapping.
	MOV	#DSMTBL,R3		; Point to D-space mapping table.
	MOV	R3,ASPTBL		; Enable I/D space separation.
	MOV	L$BHDB(R1),M.IVBN(R3)	; Set up D-space header VBN.
	INC	M.IVBN(R3)
	MOV	M.VBAS(R2),M.VBAS(R3)	; Copy base virtual D-space address.
	MOV	L$BDMV(R1),M.VMAX(R3)	; Set up maximum D-space address.
	ADD	#M.LEN,R3		; Point to D-space RO mapping section.
;   Check for a multi-user task.
10$:	ADD	#M.LEN,R2		; Point to I-space RO mapping section.
	MOV	L$BROB(R1),M.IVBN(R2)	; Does task have a multi-user section?
	BEQ	20$			; No, skip over multi-user code.
;   Set up mapping for read-only task section.
	ADD	#L$BLIB,R0		; Point to library data.
	MOV	R$LSA(R0),M.VBAS(R2)	; Set up RO section base address.
	MOV	R$LHGV(R0),M.VMAX(R2)	; Set up RO section maximum address.
	TST	L$BRDL(R1)		; Is there an RO data section?
	BEQ	20$			; No, all done.
	ADD	#28.,R0			; Point to D-space RO description.
	TST	(R0)			; Is name word empty?
	BNE	120$			; No, something is wrong...
	MOV	L$BROL(R1),R4		; Get length of RO I-space.
	ASH	#-3,R4			; Get length in disk blocks.
	ADD	M.IVBN(R2),R4		; Get RO data section block number.
	MOV	R4,M.IVBN(R3)		; Save block number.
	MOV	R$LSA(R0),M.VBAS(R3)	; Set up RO D section base address.
	MOV	R$LHGV(R0),M.VMAX(R3)	; Set up RO D section maximum address.
20$:
	.PAGE
;
;   Read header block and set up register symbol addresses.
;
100$:	MOV	ASPTBL,R0		; Point to D-space mapping table.
	MOV	M.VBAS(R0),R5		; Get task header address.
	CLR	R0			; Specify data access required.
	CALL	T$MAP			; Point to start of task header, OK?
	BCS	120$			; No, complain.
	MOV	REGSYM,R2		; Point to register symbols.
	MOV	#<^rPS >,S.NAME(R2)	; PS is always lowest in a task.
	MOV	R5,S.VALU(R2)		; Copy header base address.
	ADD	#H.IPS,S.VALU(R2)	; Construct PS address.
	MOV	(R2),R2			; Point to next symbol.
	MOV	#<^rPC >,S.NAME(R2)	; PC follows PS in task image.
	MOV	R5,S.VALU(R2)		; Copy header base address.
	ADD	#H.IPC,S.VALU(R2)	; Construct PC address.
	MOV	(R2),R2			; Point to next symbol.
	MOV	#<^rSP >,S.NAME(R2)	; SP follows PC in task image.
	MOV	R5,S.VALU(R2)		; Copy header base address.
	ADD	#H.ISP,S.VALU(R2)	; Construct SP address.
	ADD	H.HDLN(R1),R5		; Get lowest address above header.
	SUB	#16,R5			; Get virtual address of R5.
	MOV	#<^rR5 >,R4		; Get register name in RAD50.
	MOV	#6,R3			; Get number of registers left.
110$:	MOV	(R2),R2			; Point to next symbol.
	MOV	R4,S.NAME(R2)		; Set up register name.
	MOV	R5,S.VALU(R2)		; Set up value.
	SUB	#<<^rR5 >-<^rR4 >>,R4	; Set up next name.
	ADD	#2,R5			; Set up next address.
	SOB	R3,110$			; Do all registers.
	CLR	(R2)			; Break off $DSW symbol.
	RETURN
;   Here if problems are encountered.
120$:	SEC
	RETURN
;
;   Subroutine to display virtual addresses for an address space.
;
DSPADR:	MOVB	#' ,(R0)+		; Buffer a space.
	MOV	M.VBAS(R5),R1		; Get base virtual address.
	MOV	OCTFMT,R2		; Get format word.
	CALL	$CBTA			; Convert value to octal.
	MOVB	#'-,(R0)+		; Buffer a hyphen.
	MOV	M.VMAX(R5),R1		; Get maximum virtual address.
	MOV	OCTFMT,R2		; Get format word.
	CALL	$CBTA			; Convert value to octal.
	ADD	#M.LEN,R5		; Point to next section.
	TST	(R5)			; End of address space?
	BNE	DSPADR			; No, buffer next address range.
	CLRB	(R0)			; Terminate buffer.
	MOV	#TRMBUF,R1		; Point to output buffer.
	CALLR	LINOUT			; Dump line and return.
	.PAGE
;
;   Subroutine to map a specified address in the target task.
;   On entry:	R0 contains desired address space.
;		R5 contains desired target address.
;   On exit:	R1 contains debugger virtual address, carry set if error.
;		R0 is destroyed by this routine.
;
T$MAP::	MOV	ASPTBL(R0),R0		; Point to appropriate mapping info.
10$:	CMP	R5,M.VBAS(R0)		; Is virtual address too low?
	BLO	20$			; Yes, try next address range.
	CMP	R5,M.VMAX(R0)		; Is virtual address too high?
	BLOS	30$			; No, map specified address.
20$:	ADD	#M.LEN,R0		; Point to next address range.
	TST	M.IVBN(R0)		; End of address range list?
	BNE	10$			; No, see if it will map address.
	BR	60$			; Exit with failure.
;   Address is known to be mappable.
30$:	MOV	M.IVBN(R0),-(SP)	; Push appropriate header VBN.
	MOV	R5,R1			; Copy virtual address.
	SUB	M.VBAS(R0),R1		; Get block offset.
	CLR	R0			; Zero extend it.
	DIV	#512.,R0		; Get block number and offset.
	ADD	(SP)+,R0		; Correct virtual block number.
	CMP	CURBLK,R0		; Is correct block already in memory?
	BEQ	50$			; Yes, just point to it.
	TST	RDONLY			; Is file opened for reading only?
	BNE	40$			; Yes, forget about writing.
	TST	CURBLK			; Has a virtual block been loaded?
	BEQ	40$			; No, no write is needed.
	MOV	IMGRVB+Q.IOFN,-(SP)	; Preserve original I/O function.
	MOV	#IO.WVB,IMGRVB+Q.IOFN	; Make DPB perform virtual write.
	DIR$	#IMGRVB			; Issue IO.WVB request.
	MOV	(SP)+,IMGRVB+Q.IOFN	; Recover I/O function code.
40$:	MOV	R0,IMGRVB+Q.IOPL+10	; Stuff VBN in QIO DPB.
	DIR$	#IMGRVB			; Issue IO.RVB, OK?
	BCS	60$			; No, complain.
	TSTB	IMGSTS			; Success?
	BMI	60$			; No, complain.
	MOV	R0,CURBLK		; Remember what block is in memory.
50$:	ADD	#IMGBUF,R1		; Point to specified address.
	CLC				; Indicate success.
	RETURN
;   Here if T$MAP fails.
60$:	SEC
	RETURN
	.PAGE
;
;   Routines that don't do anything to a file.
;
GO::
SIMABO::
STEP::
X$STRT::
	MOV	#EXCERR,R1	; Point to error message.
	CALLR	ERROR		; DIsplay it and leave.

;
;   Close the (possibly modified) task image file.
;
T$EXIT::
	TST	RDONLY			; Is file opened for reading only?
	BNE	10$			; Yes, forget about writing.
	TST	CURBLK			; Is a virtual block buffered?
	BEQ	10$			; No, just leave.
	MOV	#IO.WVB,IMGRVB+Q.IOFN	; Set up for final write.
	DIR$	#IMGRVB			; Do it.
10$:	CLOSE$	#IMGFDB			; Close up the file.
	RETURN

	.END
