home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MEMMAP.ZIP / MEMMAP.TXT < prev   
Encoding:
Text File  |  1989-07-08  |  12.8 KB  |  292 lines

  1.                   MemMap:  Map of DOS Memory Blocks
  2.                         Using Turbo Pascal 5.0
  3.  
  4.                                   by
  5.  
  6.                              Earl F. Glynn
  7.                            Overland Park, KS
  8.                          CompuServe 73257,3527
  9.  
  10.                 (C) Copyright 1989, All Rights Reserved.
  11.  
  12.  
  13. Introduction
  14. ------------
  15.  
  16. MemMap is a DOS utility that displays all allocated memory blocks,
  17. including terminate-and-stay-resident (TSR) programs and their
  18. associated environment memory blocks.  With a /V switch, MemMap
  19. displays the variables in each environment block.
  20.  
  21. MemMap has been tested with DOS 2.10, 3.3, 4.0 and OS/2 Extended Edition
  22. 1.1 DOS Command subset.
  23.  
  24. The original motivation for writing MemMap was to determine the amount
  25. of memory lost to needless environment variables being saved every time
  26. a TSR was loaded into memory.  But several other factors shaped the
  27. development of MemMap:
  28.  
  29.      - DOS 4.0 "MEM /DEBUG" functionality is not present in DOS 3.X.
  30.        Some utilities, such as PC Magazine's PCMAP, give part of the
  31.        information desired about TSRs.
  32.  
  33.      - PCMAP returns "unknown" for most program names when run under
  34.        DOS 4.0 (See Figure 1).  Since MEM is a new command under
  35.        DOS 4.0, and cannot be run on earlier DOS versions, a common
  36.        program that operates under both DOS 3.X and 4.X is desirable.
  37.  
  38.      - DOS 4.0 MEM reports block sizes only in hexadecimal bytes, e.g.,
  39.        Sidekick (SKM) is hex 7180 bytes long, instead of decimal
  40.        29056 bytes.
  41.  
  42.      - PCMAP aggregates both environment and program blocks, creating
  43.        two problems:  (1) the memory entries are not always listed
  44.        in ascending order; (2) size information about individual
  45.        environment blocks is not available.
  46.  
  47.      - The size and contents of the environment blocks cannot be
  48.        effectively managed without an easy way to display all variables
  49.        in all environment blocks.
  50.  
  51.      - Several memory map programs have erratic behavior when IBM's
  52.        Workstation Program (INDCIPL.EXE) and Expanded Memory
  53.        Manager (INDXMAA.SYS) are in memory.
  54.  
  55.      - Turbo Pascal can be used to write system utilities as easily
  56.        as assembly language or C.  In particular, MemMap demonstrates
  57.        the ability of Turbo Pascal to manipulate DOS system control
  58.        blocks using pointer variables and record types.
  59.  
  60.  
  61. Background
  62. ----------
  63.  
  64. The layout of DOS user memory is shown in Figure 2.  Following the DOS
  65. system area, each memory block is preceded by a memory control block
  66. (MCB).  This MCB stores information on the owner of the block and
  67. the size of the memory block -- described in Figure 3.  Once the
  68. initial MCB is found, the next MCB follows the memory block.  All
  69. of user memory can be mapped by stepping through, MCB by MCB.  The last
  70. MCB is tagged differently than all other MCBs, so a termination condition
  71. is easily recognized.  But how is the address of the first MCB found?
  72.  
  73. The first Memory Control Block can be found by searching through
  74. memory at paragraph boundaries, or by using the undocumented function
  75. call $52 of DOS interrupt $21.  MemMap uses the latter approach
  76. to obtain the address of the so-called DOS "List of Lists".  At an offset
  77. of -2 in this "List of Lists" is the segment address of the first MCB.
  78.  
  79. The "Type" of an MCB is determined by observing when certain relationships
  80. exist.  If the MCB owner is hex 0000, the block following the MCB is
  81. not allocated and its type is shown as "Free Space".  When the first
  82. word of the paragraph following the MCB is hex 20CD (or possibly
  83. 27CD), the block type is "Program", if the "owner" field points
  84. to this next paragraph; otherwise, the "owner" is assumed to be the DOS
  85. kernel and the block type is shown as "System".  See Figure 4.  The block
  86. type is "Environment" when the block's owner has an environment pointer
  87. back to the paragraph following the MCB.  When none of the above
  88. relationships hold, the block is assumed to have a "Data" type.  (One
  89. TSR that I've found with a "Data" memory block is PC Magazine's
  90. PRN2FILE).
  91.  
  92. The "Name" of an MCB is determined from the environment block when
  93. possible.  In DOS 3.X, the fully-qualified program name follows the
  94. environment value(s) and a special tag word (hex 0001), as shown in
  95. Figure 4.  When an environment block does not exist for a program,
  96. or when the program name does not follow the environment block,
  97. a "short" program name (1-8 characters) can be found in the last
  98. half of the MCB -- but only in DOS 4.0.  In earlier DOS versions
  99. the name is "<unknown>" in such a case.
  100.  
  101.  
  102. Implementation Details for Turbo Pascal 5.0
  103. -------------------------------------------
  104.  
  105. Pointers are usually used to address dynamic variables created with
  106. the standard Pascal NEW procedure (or Turbo Pascal's GetMem procedure),
  107. but pointers can also be used to manipulate existing data structures,
  108. such as DOS memory blocks.  An example of accessing DOS's "List of Lists",
  109. Memory Control Blocks (MCBs) and the Program Segment Prefix (PSP) blocks
  110. using pointer variables is shown in the MemMap Turbo Pascal 5.0 program.
  111. (See Figure 5).
  112.  
  113. To obtain the address of the DOS "List of Lists", the undocumented
  114. function call $52 of DOS interrupt $21 is needed.  The DOS Turbo Pascal
  115. UNIT provides the "Intr" procedure and "Registers" type:
  116.  
  117.      ...
  118.  
  119.      VAR r:  Registers;                {Figure 5, line  57}
  120.      ...
  121.  
  122.      r.AH := $52;                                {line 205}
  123.      Intr ($21,r);                               {line 206}
  124.  
  125. After this DOS interrupt, a pointer to the "List of Lists" is in ES:BX.
  126. At an offset of -2 in the "List of Lists" is the segment address of the
  127. first MCB:
  128.  
  129.      segment := MemW[r.ES:r.BX-2];               {line 207}
  130.  
  131. where the "MemW" Turbo Pascal "system array" returns the word at the
  132. given segment:offset address.  The "MCB" pointer variable is then
  133. defined using the Turbo Pascal "Ptr" procedure:
  134.  
  135.      MCB := Ptr(segment,0);                      {line 210}
  136.  
  137. At this point all the variables defined by the MemoryControlBlock TYPE
  138. can be accessed.  Typecasting can be used to help calculate the size of
  139. the memory block following the MCB:
  140.  
  141.      bytes := LongInt(MCB^.BlockSize) SHL 4;     {line 102}
  142.  
  143. If the MCB^.BlockOwner is zero, the block is free space.  If it is
  144. nonzero, the MCB^.BlockOwner points to a memory block, which is a
  145. valid Program Segment Prefix (PSP) if it starts with the word $20CD
  146. (or possibly $27CD).  The PSP pointer is defined by
  147.  
  148.      psp := Ptr(MCB^.BlockOwner,0);              {line 109}
  149.  
  150. A segment pointer to the environment block is at an offset of hex 2C from
  151. the beginning of the PSP, which is defined by psp^.Environment.
  152. Since the environment block must be immediately preceded by an MCB, the
  153. environment MCB is defined by:
  154.  
  155.      MCBenv := Ptr(psp^.Environment-1,0);        {line 116}
  156.  
  157. If the MCB^.BlockOwner is the same as the MCBenv^.BlockOwner,
  158. environment variables follow in ASCIIZ delimited strings (character
  159. strings ending with a $00).  A null (zero-length) variable marks the
  160. end of the environment.  The program name follows the special
  161. $0001 tag.
  162.  
  163. Once an MCB and its associated information is displayed, the segment
  164. address of the next MCB is found by the statement:
  165.  
  166.      segment := segment + MCB^.Blocksize + 1;    {line 212}
  167.  
  168. The extra "1" above is needed since the MCB is itself a single
  169. paragraph long.
  170.  
  171. Contiguous MCBs and memory blocks can be sequentially listed until
  172. the last MCB is found, which is tagged with MCB^.Blocktag = $5A.
  173.  
  174. A final note:  DO NOT use DISPOSE (or FreeMem) to deallocate
  175. a pointer variable that was not allocated using NEW (or GetMem).
  176. Since the DOS control blocks described above are allocated outside
  177. of MemMap, they should not be deallocated by MemMap.
  178.  
  179.  
  180. Results
  181. -------
  182.  
  183. To demonstrate MemMap, several DOS commands and other TSRs were executed
  184. to create a variety of memory control blocks (after booting without
  185. an AUTOEXEC.BAT or CONFIG.SYS present):
  186.  
  187.      APPEND ..
  188.      GRAPHICS
  189.      MODE LPT1=COM1
  190.      \TSR\DOSED
  191.      \PCMAG\INSTALL
  192.      \PCMAG\CAPTURE
  193.      \PCMAG\CONFIRM
  194.      \PCMAG\PRN2FILE
  195.      \PCMAG\PUSHDIR
  196.      \PCMAG\POP-CAL
  197.      \SIDEKICK\SKM
  198.  
  199. Figure 6 shows MemMap's output from PC DOS 3.3.  Note that the name of
  200. several programs cannot be determined, namely the MCB at 103E (CAPTURE),
  201. 1190 and 1200 (PRN2FILE) and 1301 (PUSHDIR).  With the same set of TSRs
  202. loaded with DOS 4.0, Figure 7 shows the "short" 1-8 character names of
  203. all programs "unknown" to DOS 3.3, since these names were stored in the
  204. block owner's MCB.  For comparison, the output from the DOS 4.0
  205. "MEM /DEBUG" command is shown in Figure 8.
  206.  
  207. The contents of the environment blocks can be determined using the /V
  208. switch of MemMap.  Figure 9 shows the output of "MEMMAP /V".
  209. Note in Figure 9 that OS/2 EE 1.1 DOS subset reports itself as
  210. DOS 10.10.  But the MemMap listing for OS/2 DOS subset is more like
  211. DOS 3.3 than DOS 4.0.
  212.  
  213. The current environment variables maintained by DOS are in the first
  214. environment block with a name of "<shell>".  The size of this first
  215. block is 160 bytes in Figures 6 and 7 since this is the default
  216. environment size.  The size of this first environment block can be
  217. increased by adding a statement to the CONFIG.SYS (and re-booting).
  218. For example, to increase the environment space to 512 bytes, add the
  219. following to CONFIG.SYS:
  220.  
  221.      SHELL=\COMMAND.COM /P /E:512
  222.  
  223. In addition to the working set of environment variables set up at
  224. boot time, DOS makes a copy of the variables in effect at the time a
  225. TSR is loaded.  The size of each of these environment blocks is
  226. adjusted to accommodate only the variables set at the time the TSR
  227. is loaded.  This is why DOS 3.3 shows 10 environment blocks (Figure 6)
  228. and DOS 4.0 shows 7 environment blocks (Figure 7).  Apparently,
  229. the DOS 4.0 commands APPEND, GRAPHICS and MODE are now "smart" enough
  230. not to make copies of the environment variables.
  231.  
  232. Inspection of output using "MEMMAP /V" results in a few "rules" to
  233. minimize unnecessary, wasted memory:
  234.  
  235.      1.  Load TSRs with the smallest possible set of environment
  236.          variables in effect.  If possible, reduce the set to COMSPEC
  237.          and a very short PATH.
  238.  
  239.      2.  In AUTOEXEC.BATs, load TSRs before PATH or SETs, if possible.
  240.          Use fully-qualified names to load TSRs so the PATH can be
  241.          reduced.
  242.  
  243.      3.  Never re-execute AUTOEXEC.BAT after bootup, if it contains TSRs
  244.          that re-install themselves multiple times.  Many TSRs do not
  245.          check to see if they are already resident.  MemMap can quickly
  246.          determine when a TSR is loaded into memory multiple times.
  247.  
  248. Even when these "rules" are followed in loading TSRs, Figure 6
  249. shows 576 bytes lost to environment blocks -- not counting the 160-byte
  250. boot-time "current" environment block.  Hundreds of bytes can be lost
  251. to needless copies of environment variables if care is not taken.
  252.  
  253.  
  254. A Memory Enigma
  255. ---------------
  256.  
  257. The IBM 3270 Workstation Program (INDCIPL.EXE) allows mainframe host "sessions"
  258. and PC "sessions" with a hotkey between them.  Depending on how INDCIPL is
  259. configured, DOS conventional memory can be very limited, even when the
  260. IBM Expanded Memory Manager (INDXMAA.SYS) is used.
  261.  
  262. The state of DOS conventional memory from a PC session under INDCIPL
  263. is shown in Figure 10 from both PCMAP and MemMap.  Note both programs
  264. report a large number of null MCBs -- MCBs pointing to zero-length
  265. memory blocks.  The reason the two programs are not consistent, and
  266. the reason why only a portion of conventional memory appears to be
  267. available has not yet been explained.  This should not be surprising
  268. since much "undocumented" information is used by PCMAP and MemMap.
  269. Information about MCBs is not in the IBM DOS 3.3 Technical Reference
  270. Manual, but rather books such as "The Waite's Group MS-DOS Developer's
  271. Guide".
  272.  
  273. These null MCBs appear to be a trick to reserve large memory chunks
  274. and make them unavailable to "normal" DOS applications.  In the two
  275. MemMap cases shown in Figure 10, a 51K chunk and a 312K chunk of memory
  276. are taken up with consecutive null MCBs that appear to be placeholders.
  277.  
  278.  
  279. Summary
  280. -------
  281.  
  282. MemMap demonstrates Turbo Pascal can easily manipulate DOS control
  283. blocks using pointer variables and record types.  MemMap has 215 Pascal
  284. lines and creates a 6128-byte EXE file.  By contrast, PCMAP has 300
  285. assembly language statements  and creates a 643-byte COM file (stored
  286. in a 2048-byte cluster on most hard disks).  While certain efficiencies
  287. are lost in a high-level language, like Pascal, when writing system
  288. utilities, often the maintainability is much easier in the high
  289. level language.  Besides, it's not difficult to improve on certain
  290. DOS components, such as the PC DOS 4.0 MEM command:  MEM is a 20133-byte
  291. EXE file -- more than 3 times larger than the MEMMAP.EXE program.
  292.