Category : Files from Magazines
Archive   : VOL9N11.ZIP
Filename : MEMMAP.PAS

 
Output of file : MEMMAP.PAS contained in archive : VOL9N11.ZIP
{$M 4000,0,0}
PROGRAM MemMap;

{MemMap shows a Memory Map of all programs and environment blocks.

Usage: MEMMAP to show all Memory Control Blocks (MCBs)
or
MEMMAP /V to show MCBs and all environment variables
(the /V option is ignored in DOS 2.X or lower)

(C) Copyright 1989, Earl F. Glynn, Overland Park, KS.
All Rights Reserved.

This program may be freely distributed for non-commercial use.

MemMap is based on PCMAP from PC Magazine, SHOWMEM from "The
Waite's Group MS-DOS Developer's Guide" (Second Edition), and
the DOS 4.0 MEM /DEBUG command.

Version 1.0 -- 27 February 1989.

Version 2.0 -- 17 May 1989.
Modifications were made to handle IBM's INDCIPL program (part of
the 3270 Workstation Program). Memory with it has a large number
of contiguous MCBs each pointing to a zero-length block. Termination
conditions were modified to avoid possible problems when an MCB
is not tagged "correctly".}


USES DOS; {DOSVersion,Intr,Registers}

CONST
EnvironmentBlock: STRING[12] = 'Environment ';
ProgramBlock : STRING[12] = 'Program ';

TYPE
MemoryControlBlock = {MCB -- only needed fields are shown}
RECORD
Blocktag : BYTE; {tag is M ($4D) except last is Z ($5A)}
BlockOwner : WORD; {if nonzero, process identifier, usually PID}
BlockSize : WORD; {size in 16-byte paragraphs (excludes MCB)}
misc : ARRAY[1..3] OF BYTE; {placeholder}
ProgramName: ARRAY[1..8] OF CHAR {only used by DOS 4.0; ASCIIZ}
END; {PID normally taken from PSP}
ProgramSegmentPrefix = {PSP -- only needed fields are shown}
RECORD { offset }
PSPtag : WORD; { $20CD or $27CD if PSP} { 00 $00 }
misc : ARRAY[1..21] OF WORD; { 02 $02 }
Environment: WORD { 44 $2C }
END;

VAR
DOSVerNum: BYTE; {major version number, e.g., 3 for 3.X}
LastSize : WORD; {used to detect multiple null MCBs}
MCB : ^MemoryControlBlock;
NullMCB : WORD; {counter of MCBs pointing to 0-length blocks}
r : Registers; {TYPE defined in DOS unit}
segment : WORD;
vflag : BOOLEAN; {Verify flag TRUE when /V specified}

FUNCTION W2X(w: WORD): STRING; {binary word to hex character string}
CONST HexDigit: ARRAY[0..15] OF CHAR = '0123456789ABCDEF';
BEGIN {similar to REXX standard D2X function}
W2X := HexDigit[Hi(w) SHR 4] + HexDigit[Hi(w) AND $0F] +
HexDigit[Lo(w) SHR 4] + HexDigit[Lo(w) AND $0F];
END {W2X}; {change in CONST above suggested by Neil J. Rubenking}

PROCEDURE ProcessMCB; {Each Memory Control Block}
VAR {is processed by this PROCEDURE.}
b : CHAR;
Blocktype: STRING[12];
bytes : LongInt;
EnvSize : WORD;
i : WORD;
last : CHAR;
MCBenv : ^MemoryControlBlock;
MCBowner : ^MemoryControlBlock;
psp : ^ProgramSegmentPrefix;
BEGIN
IF (MCB^.BlockTag <> $4D) AND (MCB^.BlockTag <> $5A) AND
(MCB^.BlockTag <> $00)
THEN BEGIN
IF NullMCB > 0
THEN WRITELN (NullMCB:6,' contiguous MCBs pointing to empty ',
'blocks not shown.');
WRITELN ('Unknown Memory Control Block Tag ''',MCB^.BlockTag,
'''.');
WRITELN ('MemMap scan terminated.');
HALT
END;
IF (MCB^.BlockSize = 0) AND (LastSize = 0)
THEN INC (NullMCB) {Count but don't output multiple null MCBs}
ELSE BEGIN
LastSize := MCB^.BlockSize;
IF NullMCB > 0
THEN BEGIN
WRITELN (NullMCB:6,' contiguous MCBs pointing to empty ',
'blocks not shown.');
NullMCB := 0
END
ELSE BEGIN
bytes := LongInt(MCB^.BlockSize) SHL 4; {size of MCB in bytes}
WRITE (W2X(segment):6,W2X(MCB^.BlockSize):8,'0',bytes:9,
W2X(MCB^.BlockOwner):8,' ');

IF MCB^.BlockOwner = 0
THEN WRITELN ('Free Space ')
ELSE BEGIN
psp := Ptr(MCB^.BlockOwner,0); {possible PSP}
{Almost all programs have a tag of $20CD; DOS MODE is one
that uses $27CD in some versions.}
IF (psp^.PSPtag <> $20CD) AND (psp^.PSPtag <> $27CD)
THEN WRITELN ('System ', {not valid PSP}
'')
ELSE BEGIN {valid program segment prefix}
MCBenv := Ptr(psp^.Environment-1,0); {MCB of environment}
BlockType := 'Data '; {assume}
IF MCB^.Blockowner = (segment + 1)
THEN BlockType := ProgramBlock
ELSE
IF psp^.Environment = (segment + 1)
THEN BlockType := EnvironmentBlock;
WRITE (BlockType:12,' ');
IF MCB^.BlockOwner <> MCBenv^.BlockOwner
THEN
IF DOSVerNum <> 4
THEN WRITELN ('') {different owner; unknown in 3.X}
ELSE BEGIN {in DOS 4.0 short name is in MCB}
MCBowner := Ptr(MCB^.Blockowner-1,0); {MCB of owner block}
i := 1;
WHILE (MCBowner^.ProgramName[i] <> #$00) AND (i < 9) DO BEGIN
WRITE (MCBowner^.ProgramName[i]);
INC (i)
END;
WRITELN
END
ELSE BEGIN {environment must have same owner as MCB}
IF DOSVerNum < 3
THEN WRITELN ('') {DOS 1.X or 2.X}
ELSE BEGIN {DOS 3.X}
EnvSize := MCBenv^.BlockSize SHL 4; {multiply by 16}
i := 0;
b := CHAR( Mem[psp^.Environment:i] );
REPEAT
last := b; {skip through ASCIIZ environment variables}
INC (i);
b := CHAR( Mem[psp^.Environment:i] );
UNTIL (i > EnvSize) OR ( (b = #$00) AND (last = #$00));
INC (i); {end of environment block is $0000}
b := CHAR( Mem[psp^.Environment:i] );
IF (i >= EnvSize) OR (b <> #$01) {valid signature?}
THEN WRITE ('') {shell is probably COMMAND.COM}
ELSE BEGIN
INC (i,2); {skip process signature $0001}
b := CHAR( Mem[psp^.Environment:i] );
REPEAT
WRITE (b); {output process name byte-by-byte}
INC (i);
b := CHAR( Mem[psp^.Environment:i] )
UNTIL (i > EnvSize) OR (b = #$00);
END;
WRITELN
END
END;

IF vflag AND (BlockType = EnvironmentBlock)
THEN BEGIN {Display environment variables}
i := 0;
b := CHAR( Mem[psp^.Environment:i] );
WRITELN;
REPEAT
IF b = #$00
THEN WRITELN {end of ASCIIZ string}
ELSE WRITE (b);
last := b;
INC (i);
b := CHAR( Mem[psp^.Environment:i] );
UNTIL (i > EnvSize) OR ( (b = #$00) AND (last = #$00));
WRITELN
END

END
END
END
END
END {ProcessMCB};

BEGIN {MemMap}
DOSVerNum := Lo(DOSVersion); {major DOS version number, e.g., 3.X}
{Note: OS/2 1.1 DOS mode returns 10.10 for major/minor version}

vflag := (ParamCount > 0) AND
((ParamStr(1) = '/v') OR (ParamStr(1) = '/V')) AND
(DOSVerNum > 2); {Ignore in DOS 2.X or lower}
WRITELN ('Memory',' ':41,'MemMap (Version 2, May 89)');
WRITELN ('Control Block Size');
WRITELN (' Block [Bytes] Owner');
WRITELN ('Segment hex decimal Segment Type ',
' Name');
WRITELN ('------- ------- ------- ------- ------------ ',
'------------------------');
LastSize := $FFFF;
NullMCB := 0;

r.AH := $52; {undocumented DOS function that returns a pointer}
Intr ($21,r); {to the DOS 'list of lists' }
segment := MemW[r.ES:r.BX-2]; {segment address of first MCB found at}
{offset -2 from List of List pointer }
REPEAT
MCB := Ptr(segment,0); {MCB^ points to first MCB}
ProcessMCB; {Look at each MCB}
segment := segment + MCB^.BlockSize + 1
UNTIL (MCB^.Blocktag = $5A) {last one is $5A; all others are $4D}

END {MemMap}.


  3 Responses to “Category : Files from Magazines
Archive   : VOL9N11.ZIP
Filename : MEMMAP.PAS

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/