home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
pcresorc
/
pcr8807.arc
/
LISTING1.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-22
|
9KB
|
374 lines
comment |
This program unravels DOS's memory control blocks (MCB's) and prints
the information it finds. If it is run under DOS 3.0 or later, it
will also print the name of each program in memory when it can find
the name.
Written for MASM 5.0
Save as MEMLIST.ASM
Compile: MASM MEMLIST;
LINK MEMLIST;
|
LF equ 0ah ;Linefeed character
CR equ 0dh ;Carriage return character
STDOUT equ 1
PRINT macro text
mov ah,40h ;Write to file/device
mov bx,STDOUT ;Message to standard output
lea dx,&text&msg ;DS:DX ==> message
mov cx,&text&len ;CX = message length
int 21h
endm
EXIT macro val
mov ah,4ch ;Exit from program
mov al,val ;Return value
int 21h
endm
.MODEL SMALL
.STACK
.DATA
ourpid dw ?
maxmem dw ?
basepsp dw ?
DosVer dw ?
DosV3 db 0
NoV1msg db 'This program cannot be used with DOS v. 1.x',CR,LF
NoV1len equ $-NoV1msg
VERmsg db "Unknown DOS version -- can't find start of memory chain."
db CR,LF
VERlen equ $-VERmsg
LERRmsg db "There is an apparent error in this program's MCB",CR,LF
LERRlen equ $-LERRmsg
ERRmsg db 'Memory Allocation Error. Illegal MCB found.',CR,LF
ERRlen equ $-ERRmsg
HDRmsg db CR,LF,CR,LF
db ' MCB Block Block Block Block Process',CR,LF
db ' Seg Seg Owner Size Type Name ',CR,LF
db ' -----------------------------------------------',CR,LF
HDRlen equ $-HDRmsg
mcbmsg db ' '
mcbadr db '0000 '
blkadr db '0000 '
blkown db '0000 '
blksiz db '0000 '
mcblen equ $-mcbmsg
CRLFmsg db CR,LF
CRLFlen equ $-CRLFmsg
PRGmsg db 'Prog '
PRGlen equ $-PRGmsg
ENVmsg db 'Envr. '
ENVlen equ $-ENVmsg
OTHmsg db 'Data? '
OTHlen equ $-OTHmsg
hexlist db '0123456789ABCDEF'
memMSG db CR,LF
db 'Top of memory: '
memSIZ db '0000',CR,LF
db 'Next program will load at '
memLOC db '0000',CR,LF
db 'Memory available: '
memAVL db '00000h bytes.',CR,LF
memlen equ $-memMSG
.CODE
start: cld
mov ax,@data
mov ds,ax ;Bring DS to our data segment
mov ah,30h ;DOS function: GetVersion
int 21h ;Call DOS
mov DosVer,ax ;Save full version number
cmp al,2 ;At least version 2?
jae verOK ;Go if okay
PRINT noV1 ;Else print error
EXIT -1
verOK: sub al,2 ;Test if version 3
mov DosV3,al ;Save result (0 or 1)
mov bx,2 ;PSP:2 contains maxmem
mov ax,es:[bx]
mov maxmem,ax
push es
mov ax,es ;Get addr. of our PSP
mov ourpid,ax ;Save it
dec ax ;Point to our MCB
mov es,ax ;Now ES ==> our MCB
mov bx,1 ;Offset to PID in our MCB
inc ax ;AX contains our PID again
cmp ax,word ptr es:[bx]
jz okay ;If not the same, something's wrong!
PRINT LErr
EXIT -1
okay: pop es ;ES ==> our PSP
call FindStart ;Find head of list
;----------
; ES now points to lowest PSP in memory,
; which should belong to the first (and possibly only)
; copy of command.com. We'll use its MCB to start the
; trek through memory
;----------
PRINT HDR ;Table headers
rB1: push es ;Save ES
call printMCB ;Print block info
mov ax,es ;MCB segment in AX
inc ax ;AX has block segment
mov es,ax ;ES ==> memory block
call printType ;Print block type
jc rB2 ;Go if not ENV
test DosV3,-1 ;Using version 3 or later?
jz rB2 ;Go if not
call printCmd ;Yes -- look for proc. name
rB2: print CRLF ;Terminate info line
pop es ;ES ==> current MCB
mov bx,0 ;ES:BX ==> block type (M or Z)
cmp byte ptr es:[bx],'Z' ;At an end?
jz rB3 ;Yes -- go
mov ax,es ;Get this MCB segment
inc ax ;AX has block segment
mov bx,3 ;ES:BX ==> block size
add ax,es:[bx] ;Add block size
mov es,ax ;ES ==> next MCB
jmp rB1 ;Loop back
rb3: call printMEM ;Print memory info
EXIT 0
;---------
; Find the start of the MCB list.
; This is the trickiest part of the program, since it is
; rarely documented.
;---------
findStart proc near
mov ax,0 ;Start with segment 0
mov es,ax ; in ES
mov bx,0c3h ;Find segment of resident DOS
mov ax,es:[bx] ; and put in AX
mov es,ax ;ES ==> resident DOS segment
mov ax,DosVer ;Get DOS version again
xchg ah,al ;Major version in AH, minor in Al
mov bx,10ah ;Offset for 2.0
cmp ax,0209h ;Version 2.0?
jbe fS2 ;Yes -- BX has right offset
mov bx,0F6h ;Offset for 2.1
cmp ax,0213h ;Version 2.10 - 2.19 ?
jbe fS2 ;Yes -- BX is correct, go
cmp al,2 ;Is it version 2?
jne fS1 ;No -- go
PRINT VER ;Else print error
EXIT -1 ; and exit
fs1: mov bx,128h ;Offset for 3.0
cmp ax,0309h ;Version 3.0?
jbe fS2 ;Yes -- go
mov bx,22h ;Offset for 3.1 to 3.3
fS2: les bx,es:[bx] ;Get first memory block
ret
findStart endp
comment |
;---------
; This is an alternate method of finding the start of the MCB list.
; This method will only trace back to the last copy of Command.Com
; installed in memory, but otherwise should work if the above method
; doesn't agree with your version of MS-DOS
;---------
findStart proc near
mov bx,16h ;PSP:16h ==> parent's PSP
fS1: mov ax,es:[bx] ;Get parent's PSP addr.
cmp ax,0 ;At end of chain? (1st test)
jz fS2 ;Yes -- go
cmp ax,basepsp ;At end of chain? (2nd test)
jz fS2 ;Yes -- go
mov basepsp,ax ;Else save this value
mov es,ax ;ES ==> parent PSP
jmp fS1 ;And loop back
fS2: mov ax,es ;Get PSP segment
dec ax ;AX = segment of MCB
mov es,ax ;ES ==> 1st MCB
ret
findStart endp
|
;---------
; ES ==> an MCB. Print info contained in MCB
;---------
printMCB proc near
mov ax,es ;AX = MCB segment
lea di,mcbadr ;DI => message area
call hextoasc ;Convert AX to ASCII
inc ax ;AX = block address
lea di,blkadr
call hextoasc
mov bx,0 ;Is this really a block?
mov al,es:[bx] ;Get first byte
cmp al,'M' ;In the chain?
je pM1 ;Yes -- go
cmp al,'Z' ;Last of chain?
je pM1 ;Yes -- go
PRINT ERR ;Else report error
EXIT -1 ;End immediately
pM1: mov bx,1 ;ES:BX ==> block PID
mov ax,es:[bx] ;Get PID
lea di,blkown
call hextoasc
mov bx,3 ;ES:BX ==> Block size
mov ax,es:[bx] ;Get size in AX
lea di,blksiz
call hextoasc
PRINT mcb
ret
printMCB endp
;---------
; ES ==> a memory block. Is it a PSP, an ENV, or ??? block?
; Notice that the test for PSP is whether the 1st 4 bytes are ASCII,
; so a data block may show up as a PSP
;---------
printTYPE proc near
mov bx,0 ;ES:BX ==> beginning of block
cmp byte ptr es:[bx],0CDh ;PSPs always start CD hex
jnz typ1 ;Not here -- go
PRINT PRG
stc ;Set carry as flag
ret
typ1: mov cx,4 ;Try 4 characters
typ2: mov al,es:[bx] ;Get a byte
cmp al,' ' ;Control code?
jb typ3 ;Yes -- go
cmp al,'a' ;Lowercase?
jae typ3 ;Yes -- go
inc bx ;Else point to next
loop typ2 ;And try again
PRINT ENV ;It must be an ENV
clc ;Clear carry as flag
ret
typ3: PRINT OTH ;Can't tell what it is
stc ;Set carry as flag
ret
printTYPE endp
;---------
; ES==> a environment segment. Scan the segment and print the
; name of the program that owns this environment. This will only work
; with DOS version 3.0 and later.
;---------
printCMD proc near
push ds ;Save data segment
push es ;Copy ES
pop ds ; to DS
mov si,0 ;DS:SI ==> environment text
mov cx,8000h ;Maximum len. of environment
mov ax,0 ;Initialize register for search
pC1: lodsb ;Get a byte in AL, incr. SI
or ax,ax ;Anything in AX?
jz pC2 ;No -- found beginning of CMD
mov ah,al ;Else keep byte
loop pC1 ;And look at the next
pC1a: pop ds ;Not found
ret ; -- return
pC2: lodsw ;Get next word in AX
cmp ax,1 ;Should be 0001
jne pC1a ;No -- go
mov dx,si ;Keep addr. of beginning
mov cx,0 ;Ready to count length
pC3: lodsb ;Get next byte, incr SI
inc cx ;Count the byte
cmp al,' ' ;End of string?
ja pC3 ;No -- keep looking
mov bx,STDOUT ;Else we're ready to print
mov ah,40h ;Write to file/device
int 21h ;Print the command
pop ds ;Recover data pointer
ret
printCMD endp
;---------
; Print memory information
;---------
printMEM proc near
mov ax,maxmem
lea di,memSIZ
call hextoasc
mov ax,ourpid
lea di,memLOC
call hextoasc
mov ax,maxmem
sub ax,ourpid
lea di,memAVL
call hextoasc
PRINT mem
ret
printMEM endp
;---------
; Transfer the value in AX as ASCII-Hex to the location at DS:DI
; Only DI can be altered
;---------
hextoasc proc near
push ax ;Save registers
push bx
push cx
push es ;Save ES register
push ds ;Copy DS
pop es ; to ES
lea bx,hexlist ;DS:BX ==> list of Hex characters
xchg ah,al ;Swap bytes
call hexbyte ;Do one byte
xchg ah,al ;Put bytes back
call hexbyte ;Do the next
pop es ;Restore registers
pop cx
pop bx
pop ax
ret
hexbyte proc near
push ax ;Save AL
and al,0F0h ;Mask off low nibble
mov cl,4 ;bits to shift
shr al,cl ;Move high bit low
xlat ;Get HEX byte in AL
stosb ;Put it at ES:DI, incr DI
pop ax ;Recover AL
push ax ;Save AX again
and al,0Fh ;Mask off high nibble
xlat ;Get hex byte in AL
stosb ;Put in string
pop ax
ret
hexbyte endp
hextoasc endp
end start