[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]
{$M 4000,0,0}
PROGRAM MemMap;
{
(C) Copyright 1995, Jose Antonio Noda, Spain.
All Rights Reserved.
I can be reached at the places
listed below:
Jose Antonio Noda
Urb: 80 Viviendas, B-5§, 1§ Izq.
35620 - Gran Tarajal
Fuerteventura - (Islas Canarias)
Spain
Compuserve ID 100667,2523
}
USES DOS;
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;
FUNCTION W2X(w: WORD): STRING; {binary word to hex character string}
CONST HexDigit: ARRAY[0..15] OF CHAR = '0123456789ABCDEF';
BEGIN
W2X := HexDigit[Hi(w) SHR 4] + HexDigit[Hi(w) AND $0F] +
HexDigit[Lo(w) SHR 4] + HexDigit[Lo(w) AND $0F];
END;
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 <unallocated>')
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}
'<DOS ',DosVerNum,'.',Hi(DOSVersion),'>')
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 ('<unknown>') {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 ('<unknown>') {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>') {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;
END;
END;
END;
END;
END;
BEGIN
DOSVerNum := Lo(DOSVersion); {major DOS version number}
WRITELN ('Memory',' ':41,'MemMap (Version 1.0, Jul 95)');
Writeln;
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.
[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]