home *** CD-ROM | disk | FTP | other *** search
- 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
-
-