386SWAT Version History

Version 6.03

Version 6.02

Version 6.01

This mode is a variant of Real Mode in which any segment register can access all of the 4GB address space. That is, instead of the normal 64KB length of a segment, the length is 4GB. This command can enable all or just some of the segment registers for Unreal Mode. See SWATCMD.HTML for more details.

Version 6.00.002

Version 6.00.001

Version 6.00.000

This major upgrade is described (to some degree) in WINKDBG.DOC; also see 386SWAT.DOC and SWATVXD.DOC.

Version 5.10.079

Add service routine text displays for Win95 VMM routines. This text is displayed when decoding INT 20h calls.

Version 5.10.078

For some reason, the implementations of the .VMSTK and .VMRET commands didn't work, so now they do. Moreover, .VMSTK is now called .VMCRS (for Client Register Struc).

Version 5.10.077

On CPUs which support it (TSC bit set in CR4), display the # clocks executed since the last time 386SWAT was entered. There is a certain amount of overhead in each entry to 386SWAT, so the numbers displayed will never be at the level of single instruction clock counts, but it is a good measure of time over a longer set of instructions.

Version 5.10.076

The Microsoft Natural keyboard contains three new keys:
These keys have new scan codes which our keyboard handler now recognizes, although we don't do much with them as yet. The left and right Windows keys are meant to be modifiers just as Shift, Ctl-, and Alt-keys are modifiers. The Application key is meant to be an actual keystroke, so I've assigned arbitrary key codes to it in its Unshifted, Shift-, Ctl-, and Alt-states.
For the moment, until someone can think of something better, the Application key invokes the Help menu.

Version 5.10.075

Version 5.10.074

When printing multiple instruction screens, repeating the register display and other information on the second and subsequent screens is unnecessary. To this end, the key combination Ctrl-Shift-PrtSc prints the instruction portion of the display only, assuming the instruction window is displayed (if not, the entire screen is printed as usual).

Version 5.10.073

In case you do not need to restore a saved register set, the saved state can be cleared with the RC command.

Version 5.10.072

Commands entered on the command line are saved in a ring buffer whose length can be changed from the default of 1024 via the profile keyword CMDHIST=nnn.
Previous commands can be retrieved via the keystrokes Alt-< (previous command) and Alt-> (next command). Pressing either of these keys repeatedly scrolls through the buffer in the chosen direction. The keystroke Alt-? displays a history of (up to 25) commands from which a command can be chosen by scrolling up or down through the list, or by typing the letter next to the command. A command may be deleted from this list via the Del key.

Version 5.10.071

In an earlier TWT, when handling Page Faults, the ZF flag was cleared without realizing that subsequent code depended upon it being set. The effect was that searches for bytes were never found. This change fixes that.

Version 5.10.070

To debug Windows at the lowest level, we need to be able to insert ourselves into Windows startup shortly after it enters PM. To this end, the INSERT command is available. It is used from the 386SWAT command line at the point just before Windows enters PM.

Version 5.10.069

The Fill (F) command used to change data in memory now allows an optional trailing P also optionally followed by a CR3, just as the Unassemble and other commands allow.

Version 5.10.068

When displaying the data (if any) pointed to by the current instruction, if the instruction used an implicit stack reference (such as the PUSH instruction) we sometimes would use the wrong base register (ESP vs. SP). This TWT fixes that bug.

Version 5.10.067

The Autofault facility has been extended to GP Faults. This means that an attempt is made to interpret each GP Fault intercepted by 386SWAT in a short sentence. Type Shift-F4 to see the last Autofault error message. Because GP Faults are many and varied, some cases will be missed (marked as unknown) or mistaken. Please notify the author as you encounter such cases with the exact circumstances of the GP Fault so they may be corrected.

Version 5.10.066

Previously, when our local keyboard handler was active, we avoided checking and setting the keyboard values in the BIOS data area if Windows was active because we couldn't be sure that that memory region was mapped in. Now that I have discovered Win386 (INT 22h) services, we can map in/out that region around references to it.

Version 5.10.065

Because some programs get a kick out of resetting the debug registers which we've carefully setup, this change has 386SWAT automatically set the Global Debug (GD) bit in DR7 on startup so that we can stop such programs before they can do any harm. Perhaps it doesn't surprise you that Windows is the chief reason for this feature.

Version 5.10.064

As it's a very common data structure to view, the keystroke Shift-F5 now displays the RM IVT.

Version 5.10.063

Some symbols, especially from Windows programs written in C, are prefaced with text such as "__imp__", "_", and the like which adds the symbol's length but not understanding. This feature allows you to specify in the 386SWAT profile leading text which is to be stripped from each symbol. Separate each prefix with a space.
    SYMFILTER= text1 [text2 [...]]
The default settings are
    SYMFILTER=__imp__ _
Note the space between the two prefixes. Up to 128 characters can be specified in this way.

Version 5.10.062M

When we display a symbol names of 50 chars or greater at the top of a data screen, we're off by one in our calculations which can cause the name to fold to the next line.

Version 5.10.061

Previously, the calculation of when to change stack width (words or dwords) occurred only when the code selector changed. In fact, it should be checked when the stack selector changes (duh!).

Version 5.10.060

If the user hooks GP Faults, the handler in LCL_INT0D uses a stack structure which is missing one word in the middle. It's amazing it has worked at all so far.

Version 5.10.059

When the GD bit in DR7 is set, any read from or write to a debug
register triggers a Debug Fault (and the CPU clears the GD bit from
DR7 so the Debug Fault handler can use those registers).
Some environments (Microsoft Windows comes to mind) clear the debug registers upon entry (and at other times) thus making it difficult debug in that context. With this change, setting the GD bit traps reads and writes of those registers and handles them transparently. A read from a debug register returns the actual value. A write to a debug register is ignored. The GD bit can be set from the 386SWAT command line via
   R DR7.GD=1
If you desire this behavior to be the default, use SWATCMD with the above argument.

Version 5.10.058

Especially when debugging calls from a Windows app down to a VM interrupt handler, it is sometimes useful to know where we'll come back to in Windows on the other side of the ARPL wall. .VMRET will often work if the call was made via DPMI SIMVMI (function 0300h) or an INT instruction emulated by the DPMI host (Windows).
The GM (go monitor) command takes an expression which will be evaluated as the CPU single-steps (equivalent to Pad-plus or F11). No display will occur until
  1. the monitor expression evaluates TRUE or
  2. 386SWAT is invoked by some other means (GP fault, NMI, Ctrl-Alt-Pad5, etc.)
Boolean expressions may be constructed using the dyadic functions &&, ||,<, <=, ==, >=, and >. Operator precedence is the same as the C language.
For example:
GM ah executes until AH is non-zero.
GM [.csip == 21cd && ah!=9 executes until the current instruction is INT 21 and AH is any value other than 9 (DOS display string).
GM cx == 0 executes until CX is 0.
GM executes until the last expression specified with GM is TRUE.
There are some limitations:
  1. Currently, GM does not single-step across mode switches via INT (but will handle any mode switch handled by Pad Plus).
  2. It is slow as molasses.
  3. With the addition of boolean functions such as && and || precedence becomes more of something one would reasonably expect.
  4. GM will not work in TSS mode currently (non-critical — failure mode is the expression doesn't trigger).

Version 5.10.057

Due to an oversight, when I put in the code to determine the amount of extended memory using the INT 15h/0E801h call, I put it in after the INT 15h/0DA88h, instead of before. Because of a bug in Phoenix 4.04 BIOSes, which crash on the 0DA88h call, the order is important.
Also, when setting up the IDT entry for VCPI debugging using TSSes, we used to set the offset to -1 (because the IDT selector is a TSS and the offset isn't used). For convenience, I'm now setting the low-order byte of the offset to the interrupt #. That way, when looking at the IDT in memory (not via F4) it's easy to tell which interrupt it covers.

Version 5.10.056

Because of a quirk in Win95 (what, only one!), when we blast in the PTEs for 386SWAT to address the monochrome and color video buffers from local addresses, we need to preserve the AVL bits and set the accessed bit so this PTE won't be thought of as one available for allocation.

Version 5.10.055

If the resident portion of 386SWAT becomes too large (perhaps a large SYMSIZE or SAVESCREEN), then we might not be able to debug VCPI clients because our footprint exceeds the 4MB limit (one page directory) for VCPI. If this happens, we should at least warn the user in case s/he intends to debug VCPI clients.
When 386SWAT loads via the 386MAX profile, it is passed its linear address when it is a VCPI client in the third of the three GDT entries allocated for load modules. This is done because 386SWAT's PTEs are part of 386MAX's and get relocated by 386MAX when a VCPI client loads.
When 386SWAT intrudes into a Memory Manager, we don't use the third GDT entry in the same way, and in some cases we might not even allocate a third GDT entry if we have found existing GDT entries for an all memory selector and one which maps CR3. In this case (I encountered it when intruding into QEMM), we can mistakenly reference the third GDT entry. This TWT fixes that.
If a TSS fault occurs, there are some additional reasons for it which we now test for and report on, such as invalid selectors in the back link TSS when a return from a nested TSS occurs.
At the same time, I included some additional fault error messages which occur when we're using TSSs ourselves (typically when we're debugging VCPI clients) which we we're checking for before. This also involves moving that error message text from the data to the code segment to match where the Autofault code expects it.
Also, I changed references to $PTE_0 to $PTE_G as that's its new definition, and checked for Page Fault problems related to that bit if PTE Global Extensions are enabled in CR4.

Version 5.10.054

While tracking down a bug in the CDROM game The 11th Hour, I found that 386SWAT needed to handle intruding into multiple GDTs as this game appear to use up to three different ones, alternating between two quite frequently. We now support up to eight alternating GDTs.
At the same time, I fixed a bug where 386SWAT was not correctly recognizing whether or not it had already intruded into a GDT. This had the effect of filling up the GDT with 386SWAT's TSS selectors which crashed the system in quick order.
Finally, while running VCPITEST to see if I had broken anything in the process, I decided to remove the check for VMSINT=ON from the VCPI call DE01 (Get PM Interface) in order to allow Intrude 386SWAT to work with a cooperating VCPI client without having to set that variable. This means that Intrude 386SWAT will insert its PTEs into every such call, but that should be harmless. The VMSINT=ON setting still controls whether or not 386SWAT intrudes into the VCPI call DE0C (Switch From VM To PM).

Version 5.10.053

The Pentium CPU's debugging extensions are supported in 386SWAT via the BD command on an I/O port at which time the $DE bit is set in CR4. This change enables them at an earlier time so any other program (such as 386MAX) can modify its behavior depending upon whether or not the $DE bit is set.

Version 5.10.052

The recent change to 386MAX to support the 0E801h Extended Memory function call needs to be copied to device-loading 386SWAT not only so it can detect how much extended memory is in the system, but also so it can lie to any subsequent program requesting the extended memory size through that interface.

Version 5.10.051

Strolling through a large set of Page Tables such as under Windows can be tiresome, hence there's a new command. The SPTE command works exactly likely the PTE command (displaying the Linear address/PDE/PTE on the command line) as well as displaying the corresponding PTE (as if you had pressed F5 and scrolled down to the appropriate entry).
At the same time, I allowed Ctrl-Up and -Down to scroll through the PDEs/PTEs one entry at a time (Up and Down scroll through one line at a time).

Version 5.10.050

A previous TWT changed a local routine to be more self-sufficient by setting DS within the routine instead of relying upon the caller to set this register. Alas, that was a mistake as in some cases we rely upon the Invisible Descriptor Cache, particularly when we're accessing selector values in the caller's LDT. This TWT fixes that to use two routines, one which assumes the global DS has been set, one which does not.
At the same time, I fixed a problem with device-loading 386SWAT where software INTs 01h, 02h, 03h, and 68h are not being enabled if VME is.

Version 5.10.049

If we're loading as Device 386SWAT at startup, INIT_PROT is called at the point where 386SWAT is a temporary VCPI client of the MM. Thus the active IDT is that of the VCPI client and INIT_PROT is setting up the MM's IDT where the VCPI client has calculated the IDT's linear address in the VCPI client's linear address space.
All this is background to say that we can't signal an INT 01h if DEBUG=PMI is specified because the active IDT (that of the VCPI client) does not have its IDT entries setup for debugging unless there's a preceding 386SWAT in the picture. This changes enforces that condition.

Version 5.10.048

When 386SWAT is loaded as a device driver (whether it was intruding into an existing memory manager or loading as VCPI 386SWAT), previously it wasn't handling the transitions into and out of Windows.
When Windows starts up, 386SWAT needs to disable itself (by calling its REST_PROT entry point) so that it is in the proper state when the 386SWAT VxD calls 386SWAT's INIT_PROT entry point after Windows loads. Correspondingly, when Windows terminates, the VxD calls 386SWAT at its REST_PROT and 386SWAT needs to call its INIT_PROT entry point to re-enable it.
When 386SWAT is loaded from within 386MAX, MAX handles calling the proper REST_PROT/INIT_PROT entry points. When 386SWAT is loaded as a device driver, these calls were not made.
Now they are.

Version 5.10.047

When 386SWAT is active, it hooks various interrupts for its own use such as the timer, keyboard, cascade, and mouse (the latter two in case there's a PS/2-style mouse which goes through the keyboard controller).
When we toggle an interrupt via command line (TOGINT xx xx ...), or keystroke (Alt-F1, etc.), we need to swap out our local entries around the toggle so that we save the new entry in the proper (global) location. In particular, this affects TOGINT 0A which is hooked locally.

Version 5.10.045 & 5.10.046

When tracking down a bug in Win95, I found it useful to extend the search command to search through the PTEs for a specific value. The new syntax is
   S  addr addr#PTE
   S  addr Lexpr#PTE
 where PTE can be any expression.
At the same time, I fixed a bug where a Page Fault during the display of the searched for data caused a crash.

Version 5.10.044

A feature needed by WINSWAT is the ability to set a temporary breakpoint from a Windows program. This requires that we fill in the rest of the fields where else this feature is used.
A feature needed by WINSWAT is the ability to refresh debug hooks when a selector's linear address changes.

Version 5.10.043

The recent change to 386MAX to support the PCI Extended Memory function call needs to be copied to device-loading 386SWAT not only so it can detect how much extended memory is in the system, but also so it can lie to any subsequent program requesting the extended memory size through that interface.

Version 5.10.042

When displaying data via the Dx command, a new switch allows you to specify the number of elements to be displayed per line. For example, to display five (instead of the usual eight) words per line, use DW/5.
This feature is a stopgap until I implement a more general data record display as in the Periscope debugger.

Version 5.10.041

Rather than switch to the mono adapter every time I startup the system, I thought it easier to implement a keyword to do the same. With this keyword (MONO) present, if a monochrome adapter is present in the system, it becomes the initial display screen for 386SWAT. The monochrome adapter has always been supported by 386SWAT -- this just makes it the initial display screen as opposed to the color monitor.

Version 5.10.040

If a program enters PM from RM and asks 386SWAT to enter its GDT and IDT, as usual we setup TSS selectors for the interrupts we manage. If this program subsequently enters VM, we need to handle the interrupt via a TSS from VM differently as the stack and register interpretation (segments vs. selectors) are different. Previously, our TSS interrupt code expected to be entered from PM only, so a change is needed.
Also, when debugging such a RM program where the user sets a breakpoint shortly after entering PM (via setting the PE bit in CR0) but before setting TR, I found that 386SWAT failed miserably because it was depending upon there being a valid back link in the local TSS. Thus, more changes were needed to handle an invalid back link. In conjunction with this change, the register set command (R) is enhanced to allow TR and LDTR (a.k.a. LDT) to be read and set, so the user can setup a valid back link should the need arise.
Also, when 386SWAT is installed as a RM debugger, avoid setting TR to our local TSS as that changes it from an invalid value to a valid value. Unfortunately, this doesn't prevent another program from doing the same, but at least we're not the culprit. BTW, unlike the LDTR, there seems to be no way to clear (and thus invalidate) the Task Register once it's set. Setting TR to zero (which is after all its initial state), causes a GP Fault even though the current value of TR may be already be invalid. Thus, once TR is set to an invalid (and possibly non-zero) value, it stays that way until set to a valid value.
After switching into PM, the code in EPM.ASM should clear the NT bit in case a subsequent IRET/D occurs (as it does) in order to avoid a TSS Fault. Thanks to John Fine for pointing this out.

Version 5.10.039

Thanks to Roberto Deza Asensio, 386SWAT now supports this keyboard layout.

Version 5.10.038

Because they occur so often in code, the display of INT 21h instructions which are the current instruction now includes function-specific text (e.g., "Write File (handle)").

Version 5.10.037

Previously, I had attempted to calculate SYMSIZE based upon the size of the incoming .SSF file and it didn't work. This time it does. The effect is that you don't need to use SYMSIZE with a LOADSYM, thus reducing wasted space in 386SWAT's symbol table as well as perhaps avoiding a mistake when calculating SYMSIZE and finding it is too small.
Due to a bug in my linker, certain far calls weren't fixed up properly.

Version 5.10.036

One of 386SWAT's design goals is to be as unassuming about the system as possible, intruding into the system at an absolute minimum. As part of achieving this goal, 386SWAT has its own keyboard handler so it can debug keyboard actions within the BIOS as well as not depend upon the system's keyboard routines or data being intact and functional.
One consequence of this is that 386SWAT needs to be changed in order to support international keyboards which is what this TWT accomplishes.
To this end, the keyword KEYB= is recognized in the 386SWAT profile. At the start, the only keyboard supported is the German one -- its keyboard layout is 129, so the KEYB= value is GR129. Others can be supported as the need arises. See file 386SWAT.DOC under the KEYB= entry for the list of supported keyboards.
Thanks to Armin Kunaschik, 386SWAT now supports this keyboard layout.

Version 5.10.035

When I put in GPSKIP=INT, I checked for the INT xxh opcode (0CDh), but forgot about INT 03h (0CCh) and INTO (0CEh). These cases are now covered.

Version 5.10.034

A common address to jump to is the (near or far) return address of a subroutine. This is made easier by using shortened forms of the commands one might use to extract these addresses. For details, see the "Common Memory References" section in 386SWAT.DOC.

Version 5.10.033

I've encountered enough circumstances debugging RM where RM LIDT redirection has gotten in the way, that I've decided that it's best to make NORMLIDT the default and use the (new) keyword RMLIDT to enable it when necessary.

Version 5.10.032

For greater generality, the command line I/O instructions now allow an LVAL instead of just an atom. Also, the IMR command line action displays the original values not the ones set by 386SWAT.

Version 5.10.031

On occasion, I've had the system go poof on an IRET/D when the NT bit was set (and I didn't notice that) and the back link TSS was invalid for some reason (either bad TSS selector, or something was wrong with the TSS, such as the CR3 value was invalid). This TWT checks for that condition and reports it as part of the operand analysis display for the IRET/D instructions.

Version 5.10.030

If the user omits a profile on the 386SWAT device line, we skip out before setting default options. Now we don't.

Version 5.10.029

If we upload symbols with an invalid selector (say, the *.WSG file is for another context -- DPMI vs. VCPI vs. RM), the call to GETBASE returns an error along with EAX=-1. If this value is used for the linear address, the symbol is marked as invalid and the address hash code gets confused. This change checks for the above eventuality and sets the pseudo-linear address to zero to avoid this problem. BTW, the symptom is that (say) SWATRUN hangs when uploading symbols if it has two or more symbols with the same (invalid) linear address, e.g. 300|0.

Version 5.10.028

Now that INTRUDE is reasonably well debugged, I'm making it the default option so users don't need to remember to use it (which has happened several times). This will reduce the number of tech support questions I get from users of 386SWAT on the Internet. In case the user needs to use the VCPI client version of 386SWAT, the disabling option VCPISWAT is defined.

Version 5.10.027

An earlier TWT introduced a bug (for RM 386SWAT only) which set the B-bit in the stack selector. The problem is that I forgot to reset that bit when returning to RM. The solution is to define a new selector which has the same characteristics as DTE_SS, except with the B-bit is clear. Before returning to RM, we switch to this new selector so as to return to an environment which is compatible with RM.

Version 5.10.026

While debugging an incompatibilty with ViruSafe, I needed a minor enhancement to SIGINT to overcome their attempts to fool a RM debugger. They used many tricks including self-modifying code, as well as installing their own INT 01h/03h handlers. At one point their code signals INT 01h which 386SWAT intercepts, of course. I needed to signal this interrupt to them, but SIGINT 1 invoked it as a PM interrupt, which proceeded to crash the system. The solution was to signal INT 01h/03h as a VM interrupt, as well as ensure that TF is set in the return flags if it's INT 01h from a single-step (as opposed to a software interrupt INT 01h).

Version 5.10.025

After many years of wading through MAC entries, I decided to implement a separate display screen for them (actually, Win95 pushed me over the edge -- this is a variant of "The devil made me do it").
The keyboard combination of Ctl-M brings up this screen.

Version 5.10.024

When converting over to USE32 data, I missed a place where I should have cleared the high-order word of a 32-bit register.
Also, in the process of debugging this problem, I put in several more Shift debugging messages.

Version 5.10.023

In order for us to provide debugging services to VCPI clients, we need to insert our PTEs into the VCPI client's address space. There are several contexts in which this might occur:
  1. 386SWAT is loaded via LOAD= with 386MAX: our PTEs are automatically copied to the VCPI client's address space as part of 386MAX's response to the Get Protected Mode Interface (GPMI -- DE01h) call.
  2. 386SWAT is loaded as a VCPI client to a memory manager: previously we didn't handle this case. Now we use the newly defined RMDEV_GPMITAIL label in low DOS memory which this TWT defines an return point in order to catch the tail of the GPMI call. At this point, we switch back to our code in extended memory, and copy our PTEs to the end of the GPMI caller's PTE buffer.
  3. 386SWAT intruded into a MM (possibly 386MAX): previously we placed a PM return address on the stack and passed control on to the MM. This doesn't work with all MMs as some check the VM bit in the flags when interpreting the segment registers saved on the stack. Now we use the newly defined DEV_GPMITAIL label which this TWT defines as a return point in order to catch the tail of the GPMI call. At this point, we switch back to our code in extended memory, and copy our PTEs to the end of the GPMI caller's PTE buffer.

Version 5.10.022

The LIN2PPTE subroutine translates a linear address to a pointer to the corresponding PTE according to a specific CR3. Sometimes we need to read more than one PTE from the Page Directory which doesn't always work (because the subroutine doesn't know how many PTEs to map in the case we're not mapping relative to the current CR3). A solution to this is to tell the subroutine how many PTEs are to be mapped in.

Version 5.10.021

There is a popular shareware DOS extender available on the Internet called PMODE which is used to create PM programs. When it is run as a VCPI client, it allocates selectors from the top down in the GDT -- the same as 386SWAT does. PMODE uses the AVL bit in the DTE to mark a selector as in use, so this change has us set that bit in the selectors we allocate so PMODE doesn't write on top of our selectors.

Version 5.10.020

When we swap IDT entries (say when displaying the IDT via F4) so we see or act upon the global IDT entries, we don't swap INTs 74h and 76h. Now we do.

Version 5.10.019

Some memory managers (pssst, it's EMM386) set the DPL of various entries in the IDT to zero expecting the CPU to signal a GP Fault if the corresponding software interrupt occurs. When we intrude into their PL0 context, previously we were setting the DPL to three because we didn't expect to encounter a MM which had a fetish with GP Faults. Now we retain the same DPL as the original IDT entry except for INTs 01h and 03h. They are handled differently so we can issue the corresponding software interrupts and gain control immediately instead of having to hook the GP Fault handler and pick them off there.

Version 5.10.018

For years we've put up with this bug. Now it's fixed.
The problem occurs in any of three contexts:
* when reviewing last screens (Alt-F10),
* when switching between color and mono adapters (Alt-F7), or
* when swapping screens (say, when exiting 386SWAT).
The problem occurs because not all programs maintain a consistent set of data values in the BIOS data area on which we rely (e.g., the dependence between the cursor type and the cursor emulation bit).
The fix is to read the cursor start and end line values upon entry and restore those values in the above circumstances. A new routine, GET6845 is defined for the read starting value part. I seem to recall that the original definition of the 6845 registers was that they were write-only, but apparently they are now readable as well.
At the same time, while testing the different contexts in which 386SWAT changes the cursor type, I noticed that the Enter command handles the INS key, but not the XINS key, so I changed it.

Version 5.10.017

A common command line sequence is to set AH to 4C, SIGINT 21, and G. This is now done via a command called EXIT.

Version 5.10.016

To help me figure out why 386SWAT wasn't installing under Win95, I made several changes: