.TITLE Memory dump .IDENT /0.01/ ;======================================================================== ;= = ;= Programmer: Hunter Goatley = ;= Program: MEMDUMP.MAR = ;= Language: VAX-11 MACRO32 assembly language = ;= Purpose: Dumps memory locations in both HEX and ASCII. = ;= System: VAX 11/785 VAX/VMS v4.4 = ;= Date: October 7, 1986 = ;= = ;======================================================================== ;= = ;= To use MEMDUMP, a foreign command can be set up: = ;= = ;= $ MEM :== $DJA2:[DECUS]MEMDUMP.EXE = ;= $ MEM 7FFE3500:7FFE3910 = ;= = ;= MEMDUMP was written to dump memory in DUMP format rather than = ;= the ugly, cumbersome DCL EXAMINE format. It does not check = ;= to see if only one address is specified for the range -- if = ;= the range is not "addr1:addr2", the program simply exits = ;= without any message. MEMDUMP also does not check to see if = ;= the memory is protected from the user. Since the program runs = ;= in user mode, any attempt to read memory protected from user = ;= mode results in an ugly access violation program abort. = ;= = ;= MEMDUMP was quickly written to do a quick job. = ;= = ;======================================================================== ; .PSECT MEMDUMP_DATA,NOEXE,LONG,WRT ; BUFFER_D: .LONG 68 .ADDRESS .+4 BUFFER: .BYTE ^A/ /[80] ADDR: .LONG 0 ADDR_LEN: ; The length of the ASCII ADDR entered .WORD 0 ; ADDR_D: ; Descriptor for ADDR buffer for .LONG 8 ; ... LIB$GET_INPUT .ADDRESS .+4 ; ... .BLKB 8 ; ... PROMPT1_D: .ASCID /Enter the starting address: / PROMPT2_D: .ASCID /Enter the ending address: / FOR_PROMPT: .ASCID /Enter address range (start:end): / FOR_BUFF_D: ; Descriptor for FOR_BUFF buffer for .LONG 17 ; ... LIB$GET_FOREIGN .ADDRESS .+4 ; ... FOR_BUFF: .BLKB 17 ; ... FOR_LEN: .LONG 0 .PSECT MEMDUMP,EXE,NOWRT,LONG .ENTRY MEMDUMP1,^M ; PUSHAW FOR_LEN ; Address to receive length PUSHAQ FOR_PROMPT ; ...returned by LIB$GET_FOREIGN PUSHAQ FOR_BUFF_D ; ... Buffer descriptor CALLS #3,G^LIB$GET_FOREIGN ; Get the foreign command string TSTW FOR_LEN ; Was nothing returned? BEQLU ERROR1 ; No -- go handle it MOVAB FOR_BUFF,R6 ; Get the address of the buffer LOCC #^A/:/,#10,(R6) ; Find the ":" separating addrs BEQLU ERROR1 ; If not found, assume only one MOVL R6,R0 ; Copy start of 1st addr for cnv MOVL R1,R6 ; Copy ":" addr (begin of 2nd) SUBL2 R0,R1 ; Get length of starting addr SUBW2 R1,FOR_LEN ; Subtract this from FOR_LEN BSBW ASCTOHEX ; Convert the ASCII addr to hex BLBC R0,ERROR ; Error converting it? MOVL ADDR,R9 ; Move hex address to R9 ADDL3 #1,R6,R0 ; Address of ASCII ending addr ; ... (+1 to bump over ":") MOVZWL FOR_LEN,R1 ; Move remaining length to R1 DECW R1 ; Don't include ":" in length BSBW ASCTOHEX ; Convert the ASCII addr to hex BLBC R0,ERROR ; Error converting it? MOVL ADDR,R8 ; Move hex address to R8 ; CMPL R9,R8 ; Check order (End > start?) BLEQ MAIN ; OK -- go to MAIN XORL2 R9,R8 ; No -- exchange the beginning XORL2 R8,R9 ; ... and ending addresses XORL2 R9,R8 ; ... MAIN: ; MOVZBL #4,R1 ; Print four longwords per line MOVAB BUFFER+35,R11 ; Beginning of ASCII HEX MOVAB BUFFER+37,R10 ; Beginning of ASCII BSBB MOVADDR ; Move the address to buffer 10$: BSBW HEXNASC ; Move the first longword (both ; ... its HEX and ASCII) DECL R11 ; " " between each longword SOBGTR R1,10$ ; Loop until four longwords done PUSHAQ BUFFER_D ; Print the buffer to SYS$OUTPUT CALLS #1,G^LIB$PUT_OUTPUT ; ... CMPL R9,R8 ; Have we moved past the end? BLEQ MAIN ; No -- loop again ERROR1: MOVL #SS$_NORMAL,R0 ERROR: RET ; Return to caller ; MOVADDR: PUSHR #^M ; Save registers destroyed MOVAB BUFFER+57,R4 MOVL R9,R0 ; Get the longword to convert MOVZBL #8,R1 ; Put # of nybbles to convert in R1 10$: ROTL #4,R0,R0 ; Rotate the hex number to process next MOVL R0,R3 ; Make a copy to work with BICL2 #^XFFFFFFFF0,R3 ; Clear all but last 4 bits (1 digit) ADDB2 #^X30,R3 ; Add x'30' to make it ASCII SUBL3 #^X39,R3,R2 ; Subtract x'39' from digit (> ^A"9"?) BLEQ 20$ ; If ASCII ~> than 9, go put in OUTBUF ADDL3 #^X40,R2,R3 ; Make the digit (A-F) an ASCII "A-F" 20$: MOVB R3,(R4)+ ; Move the ASCII char to OUTBUF & bump SOBGTR R1,10$ ; Finished with longword value? no, 10$ POPR #^M ; Restore registers RSB ; Return to calling routine HEXNASC: PUSHR #^M ; Save registers destroyed MOVL (R9)+,R0 ; Get the longword to convert MOVZBL #4,R1 ; Set our loop counter 10$: MOVL R0,R3 ; Copy the longword to work with BICL2 #^XFFFFFF00,R3 ; Clear out all but last byte CMPB #^X7F,R3 ; Is it a non-printable DEL? BEQLU 15$ ; Yes -- move a "." instead CMPB #^A/ /,R3 ; Is it a non-printable character? BLEQ 20$ ; No - go move it to buffer 15$: MOVB #^A/./,(R10)+ ; Move a "." to indicate non-printable BRB 25$ 20$: MOVB R3,(R10)+ ; Move the character 25$: MOVL R3,R2 ; Copy the byte to R2 BICB2 #^XF0,R2 ; Clear high nibble of low byte of R2 BSBB HEX2ASC ; Make it ASCII and put in buffer ASHL #-4,R3,R2 ; BSBB HEX2ASC ; Convert the high nibble ASHL #-8,R0,R0 SOBGTR R1,10$ ; Loop until done with longword POPR #^M ; Restore registers RSB ; Return to calling routine ; HEX2ASC: CMPB #^XA,R2 ; Is it greater than 10.? BLEQ 10$ ; Yes -- go move "A" or "B" or .... ADDB3 #^X30,R2,-(R11) ; Convert to ASCII and move it BRB 20$ 10$: ADDB3 #^X37,R2,-(R11) ; Convert to ASCII and move it 20$: RSB .PAGE .SUBTITLE ASCTOHEX and KRNL_ACC_HANDLER ;======================================================================== ;= = ;= ASCTOHEX -- This subroutine converts an 8-digit or less ASCII = ;= string and converts it to a hexadecimal longword, = ;= which is placed in ADDR. = ;= = ;= Inputs: Address of string in R0 = ;= Length of string in R1 = ;= = ;======================================================================== ASCTOHEX: PUSHR #^M ; Save registers destroyed by routine CLRL R2 ; Clear a work register (will hold ADDR) CLRL R3 ; Clear a work register 10$: MOVZBL (R0)+,R3 ; Get the ASCII char to convert CMPB #^A/9/,R3 ; Is it > ASCII '9'? BLSSU 20$ ; Yes -- go handle it (A thru F) SUBB2 #^X30,R3 ; Strip off ASCII, leaving digit BLSS 40$ ; If result is negative, not a digit BRB 30$ ; Go move it into the hex longword 20$: BICB2 #^X20,R3 ; Convert to uppercase (in case lower) SUBB2 #^A/A/,R3 ; Subtract ^X41 from the char BLSS 40$ ; If negative result, '9' ^XF? BLSS 40$ ; Yes -- some letter > "F" 30$: ROTL #4,R2,R2 ; Shift HEX ADDR to make room for digit BISL2 R3,R2 ; Copy the digit to the hex ADDR SOBGTR R1,10$ ; Loop until all chars entered are done ; MOVL R2,ADDR ; Copy the hex ADDR to ADDR MOVL #SS$_NORMAL,R0 ; Set normal return status BRB 50$ ; Return to caller 40$: MOVL #SS$_IVCHAR,R0 ; No -- return an error to main 50$: POPR #^M ; Restore the saved registers RSB ; Return to caller ; ;=============================================================================== .END MEMDUMP1