home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Pascal / TSRSRC30.ZIP / DEVICE.PAS next >
Encoding:
Pascal/Delphi Source File  |  1991-10-07  |  10.3 KB  |  384 lines

  1. {
  2.  Display the DOS device driver chain.
  3.  Adapted from an assembly language program by Ray Duncan and modified by
  4.  several others.
  5.  
  6.  version 3.0 9/2/91
  7.    for consistency
  8. }
  9.  
  10. {$R-,S-,I-,V-,B-,F-,A-,E-,N-,G-,X-}
  11. {$M 2048,0,655360}
  12.  
  13. program Device_Chain;
  14.  
  15. uses
  16.   Dos,
  17.   MemU;
  18.  
  19. const
  20.   Version = '3.0';                {Version number}
  21.  
  22.   MaxDevices = 100;               {Maximum number of devices to report}
  23.  
  24. type
  25.   {FCB used to find start of device driver chain}
  26.   FileControlBlock =
  27.     record
  28.       Drive : Byte;
  29.       Filename : array[1..8] of Char;
  30.       Extension : array[1..3] of Char;
  31.       CurrentBl : Word;
  32.       LRL : Word;
  33.       FilSizeLo : Word;
  34.       FilSizeHi : Word;
  35.       FileDate : Word;
  36.       FileTime : Word;
  37.       Other : array[0..7] of Byte;
  38.       CurRecord : Byte;
  39.       RelRecLo : Word;
  40.       RelRecHi : Word;
  41.     end;
  42.  
  43.   DisplayRec =
  44.     record
  45.       StartAddr : Pointer;
  46.       Header : DeviceHeader;
  47.     end;
  48.   DisplayArray = array[1..MaxDevices] of DisplayRec;
  49.  
  50. var
  51.   DeviceControlBlock : FileControlBlock; {File Control Block for NUL Device}
  52.   DevicePtr : ^DeviceHeader;      {Pointer to the next device header}
  53.   DeviceSegment : Word;           {Current device segment}
  54.   DeviceOffset : Word;            {Current device offset}
  55.   DeviceCount : Word;             {Number of devices}
  56.   Devices : DisplayArray;         {Sortable list of devices}
  57.   RawMode : Boolean;
  58.   NulStatus : Byte;
  59.  
  60.   procedure Abort(Msg : String);
  61.   begin
  62.     WriteLn(Msg);
  63.     Halt(1);
  64.   end;
  65.  
  66.   function FindNulDevice(Segm : Word) : Word;
  67.     {-Return the offset of the null device in the specified segment}
  68.   var
  69.     Ofst : Word;
  70.   begin
  71.     for Ofst := 0 to 65534 do
  72.       if MemW[Segm:Ofst] = $554E then
  73.         {Starts with 'NU'}
  74.         if Mem[Segm:Ofst+2] = Byte('L') then
  75.           {Continues with 'L'}
  76.           if (MemW[Segm:Ofst-6] and $801F) = $8004 then begin
  77.             {Has correct driver attribute}
  78.             FindNulDevice := Ofst-10;
  79.             Exit;
  80.           end;
  81.     Abort('Cannot find NUL device driver');
  82.   end;
  83.  
  84. var
  85.   Pivot : DisplayRec;
  86.   Swap : DisplayRec;
  87.  
  88.   function PhysAddr(X : Pointer) : LongInt;
  89.     {-Return the physical address given by pointer X}
  90.   begin
  91.     PhysAddr := (LongInt(OS(X).S) shl 4)+OS(X).O;
  92.   end;
  93.  
  94.   function Less(X, Y : DisplayRec) : Boolean;
  95.     {-Return True if address of X is less than address of Y}
  96.   begin
  97.     Less := (PhysAddr(X.StartAddr) < PhysAddr(Y.StartAddr));
  98.   end;
  99.  
  100.   procedure Sort(L, R : Word);
  101.     {-Sort device headers}
  102.   var
  103.     I : Word;
  104.     J : Word;
  105.   begin
  106.     I := L;
  107.     J := R;
  108.     Pivot := Devices[(L+R) shr 1];
  109.     repeat
  110.       {Sort by address}
  111.       while Less(Devices[I], Pivot) do
  112.         Inc(I);
  113.       while Less(Pivot, Devices[J]) do
  114.         Dec(J);
  115.       if I <= J then begin
  116.         Swap := Devices[J];
  117.         Devices[J] := Devices[I];
  118.         Devices[I] := Swap;
  119.         Inc(I);
  120.         Dec(J);
  121.       end;
  122.     until I > J;
  123.     if L < J then
  124.       Sort(L, J);
  125.     if I < R then
  126.       Sort(I, R);
  127.   end;
  128.  
  129.   procedure WriteHelp;
  130.     {-Write a simple help screen}
  131.   begin
  132.     WriteLn;
  133.     WriteLn('DEVICE produces a report showing the device drivers loaded into the system as');
  134.     WriteLn('well as how much memory each uses, and what interrupt vectors are taken over.');
  135.     WriteLn;
  136.     WriteLn('DEVICE accepts the following command line syntax:');
  137.     WriteLn;
  138.     WriteLn('  DEVICE [Options]');
  139.     WriteLn;
  140.     WriteLn('Options may be preceded by either / or -. Valid options are as follows:');
  141.     WriteLn('     /R     raw, unsorted report.');
  142.     WriteLn('     /?     write help screen.');
  143.     Halt(1);
  144.   end;
  145.  
  146.   procedure GetOptions;
  147.     {-Check for command line options}
  148.   var
  149.     Arg : String[127];
  150.     I : Integer;
  151.   begin
  152.     RawMode := False;
  153.     I := 1;
  154.     while I <= ParamCount do begin
  155.       Arg := ParamStr(I);
  156.       if Length(Arg) = 2 then
  157.         if (Arg[1] = '/') or (Arg[1] = '-') then
  158.           case Upcase(Arg[2]) of
  159.             'R' : RawMode := True;
  160.             '?' : WriteHelp;
  161.           end;
  162.       Inc(I);
  163.     end;
  164.   end;
  165.  
  166.   function GetName(Header : DeviceHeader) : String;
  167.     {-Get a device name}
  168.   const
  169.     Plural : array[Boolean] of String[1] = ('', 's');
  170.   var
  171.     Num : String[3];
  172.   begin
  173.     with Header do
  174.       if (Attributes and $8000) <> 0 then
  175.         GetName := DeviceName
  176.       else begin
  177.         Str(Ord(DeviceName[1]), Num);
  178.         GetName := Num+' Block Unit'+Plural[Ord(DeviceName[1]) <> 1];
  179.       end;
  180.   end;
  181.  
  182.   procedure RawReport;
  183.     {-Raw, unsorted device report}
  184.   var
  185.     D : Word;
  186.   begin
  187.     WriteLn;
  188.     WriteLn(' Starting      Next             Strategy   Interrupt   Device');
  189.     WriteLn(' Address     Hdr Addr   Attr   Entry Pnt   Entry Pnt   Name');
  190.     WriteLn('---------   ---------   ----   ---------   ---------   --------');
  191.  
  192.     for D := 1 to DeviceCount do
  193.       with Devices[D], Header do
  194.         WriteLn(HexPtr(StartAddr), '   ',
  195.                 HexW(NextHeaderSegment), ':', HexW(NextHeaderOffset), '   ',
  196.                 HexW(Attributes), '   ',
  197.                 HexW(DeviceSegment), ':', HexW(StrategyEntPt), '   ',
  198.                 HexW(DeviceSegment), ':', HexW(InterruptEntPt), '   ',
  199.                 GetName(Header));
  200.   end;
  201.  
  202.   function GetCommandPtr(DosPtr : DosRecPtr) : Pointer;
  203.     {-Get the address of COMMAND.COM}
  204.   type
  205.     McbRec =
  206.       record
  207.         ID : Char;
  208.         PSPSeg : Word;
  209.         Len : Word;
  210.       end;
  211.   var
  212.     McbPtr : ^McbRec;
  213.   begin
  214.     McbPtr := Ptr(DosPtr^.McbSeg, 0);
  215.     McbPtr := Ptr(OS(McbPtr).S+McbPtr^.Len+1, 0);
  216.     GetCommandPtr := Ptr(McbPtr^.PSPSeg, 0);
  217.   end;
  218.  
  219.   procedure WriteDevice(StartAddr : Pointer;
  220.                         Name : String;
  221.                         Start, Stop : LongInt;
  222.                         ShowVecs : Boolean);
  223.     {-Write data for one device}
  224.   var
  225.     Size : LongInt;
  226.     VecAddr : LongInt;
  227.     Vec : Byte;
  228.     Cnt : Byte;
  229.     BPtr : ^Byte;
  230.   begin
  231.     Size := Stop-Start;
  232.     ShowVecs := ShowVecs and (Size <> 0);
  233.  
  234.     Write(HexPtr(StartAddr), '   ');
  235.     if Size <> 0 then
  236.       Write(Size:6)
  237.     else
  238.       Write('     -');
  239.     if ShowVecs then
  240.       while Length(Name) < 14 do
  241.         Name := Name+' ';
  242.     Write('   ', Name);
  243.  
  244.     if ShowVecs then begin
  245.       Cnt := 0;
  246.       for Vec := 0 to $80 {!!} do begin
  247.         VecAddr := PhysAddr(Pointer(MemL[0:4*Vec]));
  248.         if (VecAddr >= Start) and (VecAddr < Stop) then
  249.           {Points to this memory block}
  250.           if Byte(Pointer(VecAddr)^) <> $CF then begin
  251.             {Doesn't point to IRET}
  252.             if Cnt >= 12 then begin
  253.               WriteLn;
  254.               Write('                                   ');
  255.               Cnt := 0;
  256.             end;
  257.             inc(Cnt);
  258.             Write(' ', HexB(Vec));
  259.           end;
  260.       end;
  261.     end;
  262.     WriteLn;
  263.   end;
  264.  
  265.   procedure SortedReport;
  266.     {-Sorted report better for user consumption}
  267.   const
  268.     NulDevice : array[1..8] of Char = 'NUL     ';
  269.   var
  270.     D : Word;
  271.     DosCode : Pointer;
  272.     CommandPtr : Pointer;
  273.     DosPtr : DosRecPtr;
  274.     DosBuffers : SftRecPtr;
  275.     Start : LongInt;
  276.     Stop : LongInt;
  277.     FoundNul : Boolean;
  278.   begin
  279.     {Pointer to DOS variables}
  280.     DosPtr := Ptr(OS(DosList).S, OS(DosList).O-2);
  281.  
  282.     {Get the address of the lowest DOS code}
  283.     DosCode := Ptr(OS(Devices[1].StartAddr).S, 0);
  284.  
  285.     {Get the address of the start of DOS's file tables}
  286.     DosBuffers := DosPtr^.FirstSFT^.Next;
  287.  
  288.     {Get pointer to command.com}
  289.     CommandPtr := GetCommandPtr(DosPtr);
  290.  
  291.     WriteLn;
  292.     WriteLn(' Address     Bytes   Name           Hooked vectors');
  293.     WriteLn('---------   ------   -------------- --------------');
  294.     {        ssss:oooo   ssssss   nnnnnnnn       xx xx xx xx xx}
  295.  
  296.     {Display the devices}
  297.     FoundNul := False;
  298.     for D := 1 to DeviceCount-1 do begin
  299.       if FoundNul then begin
  300.         Start := PhysAddr(Devices[D].StartAddr);
  301.         Stop := PhysAddr(Devices[D+1].StartAddr);
  302.       end else if GetName(Devices[D].Header) = NulDevice then begin
  303.         FoundNul := True;
  304.         Start := PhysAddr(DosCode);
  305.         Stop := PhysAddr(Devices[D+1].StartAddr);
  306.       end else begin
  307.         Start := 0;
  308.         Stop := 0;
  309.       end;
  310.       {Protect against devices patched in after DOS}
  311.       if Stop > PhysAddr(DosBuffers) then begin
  312.         WriteLn('Detected device drivers patched in after CONFIG.SYS');
  313.         Exit;
  314.       end;
  315.       with Devices[D] do
  316.         WriteDevice(StartAddr, GetName(Header), Start, Stop, True);
  317.     end;
  318.  
  319.     {Last device}
  320.     with Devices[DeviceCount] do begin
  321.       Start := PhysAddr(StartAddr);
  322.       Stop := PhysAddr(DosBuffers);
  323.       WriteDevice(StartAddr, GetName(Header), Start, Stop, True);
  324.     end;
  325.  
  326.     {DOS buffers}
  327.     Start := PhysAddr(DosBuffers);
  328.     Stop := PhysAddr(CommandPtr);
  329.     WriteDevice(DosBuffers, 'DOS buffers', Start, Stop, False);
  330.   end;
  331.  
  332. begin
  333.   WriteLn('DEVICE ', Version, ', Copyright 1991 TurboPower Software');
  334.  
  335.   GetOptions;
  336.  
  337.   {Find the start of the device driver chain via the NUL device}
  338.   FillChar(DeviceControlBlock, SizeOf(DeviceControlBlock), 0);
  339.   with DeviceControlBlock do begin
  340.     Filename := 'NUL     ';
  341.     Extension := '   ';
  342.     asm
  343.       mov ax,$0F00
  344.       mov dx,offset devicecontrolblock
  345.       int $21
  346.       mov NulStatus,al
  347.     end;
  348.     if NulStatus <> 0 then
  349.       Abort('Error opening the NUL device');
  350.     if Lo(DosVersion) > 2 then begin
  351.       {DOS 3.0 or later}
  352.       DeviceSegment := 0;
  353.       DeviceOffset := FindNulDevice(DeviceSegment);
  354.     end else begin
  355.       {DOS 2.x}
  356.       DeviceOffset := Word(Pointer(@Other[1])^);
  357.       DeviceSegment := Word(Pointer(@Other[3])^);
  358.     end;
  359.     DevicePtr := Ptr(DeviceSegment, DeviceOffset);
  360.   end;
  361.  
  362.   {Scan the chain, building an array}
  363.   DeviceCount := 0;
  364.   while OS(DevicePtr).O <> $FFFF do begin
  365.     if DeviceCount < MaxDevices then begin
  366.       Inc(DeviceCount);
  367.       with Devices[DeviceCount] do begin
  368.         StartAddr := Pointer(DevicePtr);
  369.         Header := DevicePtr^;
  370.       end;
  371.     end;
  372.     with DevicePtr^ do
  373.       DevicePtr := Ptr(NextHeaderSegment, NextHeaderOffset);
  374.   end;
  375.  
  376.   if RawMode then
  377.     RawReport
  378.   else begin
  379.     {Sort the array in order of starting address}
  380.     Sort(1, DeviceCount);
  381.     SortedReport;
  382.   end;
  383. end.
  384.