Enhanced DEBUG for PC DOS and MS-DOS

The enhanced DEBUG programs, DEBUG and DEBUGX are compatible with the
DEBUG utility which was included with every version of PC DOS and MS-DOS.

DEBUG supports all Intel x86 instructions up to the Pentium Pro (P6)
including the floating point instructions and undocumented instructions
such as SALC and LOADALL. DEBUGX supports additional features and also
supports the debugging of DPMI client programs.

DEBUG command line
------------------
DEBUG [/F] [[drive:][path]filename [arglist]]

  /F        enable page flipping
  filename  file to debug or examine
  arglist   parameters given to program

For a list of debugging commands, run DEBUG and type ? at the prompt.

DEBUG commands
--------------
DEBUG recognizes only hex numbers (without a trailing "H").

DEBUG maintains a set of variables that it uses to store a target
program's CPU registers. DEBUG initializes these variables each time
it is started. The variables for the AX, DX, BP, SI, and DI registers
are set to 0. If a target program or other file is loaded, the
variables for the BX and CX registers are set to the size of the
program or file. Otherwise, the variables for the BX and CX registers
are set to 0. If a target program is loaded, the variables for the
segment, IP, and SP registers are set to values appropriate for the
loaded program. Otherwise, the variables for the segment registers
are set to the segment address of the area of memory that DEBUG uses
to store the output from the Assemble command, the variable for IP
is set to 100h, and the variable for SP is set to FFFEh.

For 80386 and later processors, the high words of the 32-bit registers
are initialized to zero on program start.

Note that any DEBUG command that accepts a CPU register as a parameter
is actually using one of these variables. For the remainder of this
section, all register names refer to the associated variable.

For the commands that accept a range parameter, the parameter can be
used to specify a starting address, or a starting and ending address,
or a starting address and a length. To differentiate a length
parameter from an ending address, the length parameter must be
preceded with an "L". The starting address parameter can include a
segment register or a segment address constant, separated from the
offset address with a colon. Some examples using the Dump command:

-D 0
-D CS:0
-D F000:FFF6
-D 0 F
-D DS:100 102
-D SS:20 L 4

The Dump command also supports a length parameter without an address
to dump the specified length starting from the last displayed address
which is useful for displaying arrays.

DEBUGX understands this additional syntax:

#D $F000:FFF6

 which tells DEBUGX that F000 should be interpreted as a segment,
 not as a selector when debuggee is in protected-mode.

If the debuggee is in protected-mode and the segment part of the starting
address is a 32-bit selector, the offset parts of the starting and ending
address - as well as the length - can be 32-bit. Examples:

-D DS:110000 110FFF
-D CS:400000 L 20000

---

A
Assmble instructions

Syntax: A [address]

The Assemble command (A) is used to enter assembly mode. In assembly
mode, DEBUG prompts for each assembly language statement and converts
the statement into machine code that is then stored in memory. The
optional start address specifies the address at which to assemble the
first instruction. The default start address is CS:100h. A blank line
entered at the prompt causes DEBUG to exit assembly mode.

---

C
Compare data

Syntax: C range address

The Compare command (C) compares two memory regions. All differences will be
listed, both addresses are displayed, with their respective data bytes.

Example:

-C 0100 l 2 0200
1234:0100  E9  65  1234:0200
1234:0101  01  02  1234:0201

---

D
Dump memory

Syntax: D [range]
        DB [range]
        DW [range]
        DD [range]

The Dump command (D), when used without a parameter, causes DEBUG
to display the contents of the 128-byte block of memory starting at
CS:IP if a target program is loaded, or starting at CS:100h if no
target program is loaded. The optional range parameter can be used
to specify a starting address, or a starting and ending address,
a starting address and a length, or just a length. Subsequent Dump
commands without a parameter cause DEBUG to display the contents of
the 128-byte block of memory following the block displayed by the
previous Dump command. The DB, DW and DD variants display memory in
byte, word or doubleword format respectively. Subsequent D commands
will use the previously specified format with the default being byte
format. Pressing ENTER after a Dump command will autorepeat and
function as if another Dump command was entered without a range.

---

DI
Dump Interrupts (DEBUGX only)

Syntax: DI vector [count]

The Dump Interrupt (DI) command displays interrupt vectors in
real/v86-mode and DPMI interrupt vectors in protected-mode.

Examples:

Display interrupt 00 in real-mode:

-DI 0
00 02F8:03F8

Display interrupt and exception vectors 08-0B in 32-bit protected-mode:

#DI 8 4
08 00C7:00000D28 00C7:00001228
09 00C7:00000D2D 00C7:0000122D
0A 00C7:00000D32 00C7:00001232
0B 00C7:00000D37 00C7:00001237

---

DL
Dump LDT descriptors (DEBUGX only)

Syntax: DL selector [count]

The Dump LDT descriptor (DL) command displays DPMI LDT descriptors.

Example:

#dl 84 2
0084 base=00110800 limit=0000014F attr=00F2
008C base=00110000 limit=000007FF attr=00F3

DL can also be used to display limit and attributes of those GDT
descriptors which are accessible by the client. Example:

#dl 18 3
0018 base=???????? limit=FFFFFFFF attr=CFFB
0020 base=???????? limit=FFFFFFFF attr=CFF3
0028 base=???????? limit=???????? attr=????

---

DM
Dump Memory Control Block (MCB) chain

Syntax: DM

The Dump MCBs (DM) displays the current DOS PSP and the DOS Memory
Control Block (MCB) chain.

Example:

-dm
PSP:0754
021C 4D 0227 0009 DEBUG
0226 4D 0227 0522 DEBUG
0749 4D 0754 0009 DOSINFO
0753 5A 0754 98AC DOSINFO

The first value is the segment address of the MCB, followed by 4D or 5A,
the owner and size of the MCB and finally the 8-byte name of the owner.
An owner of 0000 means that this MCB describes a free memory block.
An owner of 0008 means that this MCB describes a system memory block.

---

DX
Dump extended memory (DEBUGX only)

Syntax: DX [address]

The Dump eXtended memory command (DX) allows the display of the full range
of memory. It uses Interrupt 15h, AH=87h for extended memory access.
It should be noted that, when running under a Expanded Memory Manager (EMM),
Interrupt 15h, AH=87h behaves slightly inconsistent: addresses below 110000h
are regarded as linear, while addresses >= 110000h are regarded as physical.
Pressing ENTER after a Dump eXtended memory command will autorepeat and
function as if another Dump eXtended memory command was entered.

---

E
Enter data into memory

Syntax: E address [list]

The Enter command (E) is used to enter data into memory. The required
address parameter specifies the starting location at which to enter
the data. If the address parameter does not specify a segment, DEBUG
uses DS. If the optional list parameter is not included, DEBUG
displays the byte value at the specified address and prompts for a
new value. The spacebar or minus key can be used to move to the next
or previous byte. Pressing the Enter key without entering a value
terminates the command. If the list parameter is included, it can
contain up to 8 byte values separated by spaces, commas, or tabs,
and/or a case significant string enclosed in single or double quotes.

Examples:

-E 100 01 02 03
-E 100 'ABC'
-E 100 'ABC' 0

---

F
Fill memory

Syntax: F range list

The Fill command (F) fills a memory regions with a byte pattern.

Example:
To fill the first 8000h bytes of current data segment with pattern 55 AA:

-F 0 L 8000 55 AA

---

G
Go

Syntax: G [=address] [break0 break1...]

The Go command (G), when used without a parameter, causes DEBUG to
copy the contents of the register variables to the actual CPU
registers and effectively jump to the instruction at CS:IP, giving
full control to the program being debugged. DEBUG will regain
control when the program terminates. The optional address parameter
can be used to specify the starting address. The optional breakpoint
list can be used to specify up to 10 temporary breakpoint addresses.
To differentiate the address parameter from the breakpoint list,
the address parameter must be preceded with an "=". Note that the
breakpoint addresses must coincide with the start of a valid
instruction. To resume execution after a breakpoint, use the Go
command without a parameter.

---

H
Hex add and subtract

The Hex command (H) computes the sum and difference of two hex numbers.

Syntax: H value1 value2

Examples:

H 1FF 10
020F 01EF

H 20000 4000
00024000 0001C000

---

I
Input from I/O port

Syntax: I port
        IW port
        ID port

The Input command (I) causes DEBUG to read and display the value
from the specified I/O port. The IW and ID variants read a word or
doubleword value from the specified I/O port. Note the ID command
can only be used on 80386 or later processors.

---

L
Load file or disk sectors

Syntax: L [address]
        L address drive startsector numberofsectors

The Load command (L) is used to load a file into memory. The file to
load is specified with the Name command (N). The optional address
parameter specifies the load address. The default load address is
CS:100 for all files other than EXE files, for which information in
the file header determines the load address. After DEBUG loads the
file it sets BX:CX to the file size in bytes.

The Load command can also be used to load one or more logical sectors
from a disk drive into DEBUG's memory. The drive should be specified
as 0=A, 1=B, 2=C etc.

---

M
Move data

The Move command (M) copies a memory region to another location. If
source and destination overlap, parts of the source will be overwritten.

Syntax: M range address

---

M
Set CPU/FPU mode (DEBUGX only)

Syntax: M [mode|N|T]

The M command (M) sets the current CPU and FPU mode for the Assemble and
Unassemble commands. The mode value is 0 for a 8086/8088, ... 5 for a Pentium,
6 for a Pentium Pro or later. Specifying N indicates no FPU and specifying T
indicates a 80386 with a 80287.

To display the current CPU and FPU mode use the M command without a parameter.

---

N
Set program name and arguments

Syntax: N filespec [arguments]

The Name command (N) is used to input a filename (actually, a file
specification that can include a drive and a path) for a subsequent
Load or Write command. Because the Name command uses the simulated
PSP as a buffer, it can also be used to enter command line arguments
and/or switches for the program being debugged.

Be aware that the N command alters the value of the AX register.

---

O
Output to I/O port

Syntax: O port byte
        OW port word
        OD port dword

The Output command (O) causes DEBUG to write the specified value
to the specified I/O port. The OW and OD variants write a word or
doubleword value to the specified I/O port. Note the OD command
can only be used on 80386 or later processors.

---

P
Proceed trace

Syntax: P [=address] [number]

The Proceed command (P) functions like the Trace command (T) for all
instructions other than the repeat (REP) string, LOOP, CALL, and INT
instructions. For a repeat string instruction, DEBUG executes the
instruction to completion. For a LOOP instruction, DEBUG executes the
entire loop to completion. For a CALL or INT, DEBUG executes the entire
call or interrupt up to and including the return instruction. After
execution is complete, DEBUG continues as it does for the Trace command.
Pressing ENTER after a Proceed command will autorepeat and function as
if another Proceed command was entered.

---

PR
Proceed Return

Syntax: PR

The Proceed Return (PR) command exits the current subroutine by proceeding
past the next RET, RETF or IRET instruction which is not nested or program
termination. All other instructions including any nested calls or interrupts
are executed without stopping.

---

Q
Quit

Syntax: Q

The Quit command (Q) exits DEBUG.

---

R
Display or modify registers

Syntax: R [register] [value]

The Register command (R), when used without a parameter, causes
DEBUG to display the contents of the target program's CPU registers.
The optional register parameter will cause DEBUG to display the
contents of the register and prompt for a new value. When DEBUG
displays the contents of the registers, it encodes the processor
flags as follows:

   Flag              Set   Clear
   -----------------------------
   Overflow          OV    NV
   Direction         DN    UP
   Interrupt         EI    DI
   Sign              NG    PL
   Zero              ZR    NZ
   Auxiliary Carry   AC    NA
   Parity            PE    PO
   Carry             CY    NC

If the register argument is given, it can be immediately followed
by the new value. No prompt will appear in that case.

The processor flags can be changed in two ways. The first syntax changes
individual flags:

-R F [OV|NV|DN|UP|EI|DI|NG|PL|ZR|NZ|AC|NA|PE|PO|CY|NC]

the other syntax will set the [E]FL register:

-R [E]FL <[d]word value>

---

RM
Display MMX registers (DEBUGX only)

Syntax: RM

The RM command displays MMX registers (if available).

---

RN
Display FPU registers

Syntax: RN[R]

The RN command display the content of the floating point registers. DEBUGX
renders the content of these registers in "readable" floating point format,
DEBUG displays the content in raw hex format. Additionally DEBUGX supports
the RNR command which displays the content in raw hex format.

---

RX
Set/clear extended (32-bit) register mode

Syntax: RX

The RX command is active if the current CPU is a 80386 or better.
RX will toggle between the simple 16-bit register display (which is the
default) and the full 32-bit register display.

---

S
Search memory

Syntax: S range list

Search (S) is used to find the occurrence of a specific byte or series
of bytes within a segment.

Examples:

To find all occurrences of 'CD 21' in memory region DS:100-1FF:

-S 100 l 100 CD 21
 1234:0122
 1234:01EC

To find all strings "hello" in DS:0100-FFFF:

-S 100 FFFF 'hello'
 1234:0122
 1234:1221
 1234:EADC

---

T
Trace

Syntax: T [=address] [number]

The Trace command (T), when used without a parameter, causes DEBUG
to execute the instruction at CS:IP. Before the instruction is
executed, the contents of the register variables are copied to the
actual CPU registers. After the instruction has executed, and updated
the actual CPU registers (including IP), the contents of the actual
CPU registers are copied back to the register variables and the
contents of these variables are displayed. The optional address
parameter can be used to specify the starting address. The optional
count parameter can be used to specify the number of instructions to
execute. To differentiate the address parameter from the count
parameter, the address parameter must be preceded with an "=". Note
that the first byte at the specified address must be the start of a
valid instruction. Pressing ENTER after a Trace command will autorepeat
and function as if another Trace command was entered.

If the current CS:IP points to an INT opcode, DEBUG's behaviour depends
on the current value of the TM option. If it is 0 (the default), DEBUG
will regain control when the INT has been processed. If TM is 1, DEBUG
will step "into" the INT.

---

TM
Trace mode

Syntax: TM [0|1]

The Trace Mode command (TM), sets the INT trace mode. If it is 0
the debugger will regain control when the INT has been processed.
If TM is 1, the debugger will step "into" the INT.

---

U
Unassemble instructions

Syntax: U [range]

The Unassemble command (U), when used without any parameter, causes
DEBUG to read approximately 32 bytes of memory starting at the initial
CS:IP values specified in the file header if an EXE file is loaded,
or starting at CS:100h if any other type of file or no file is loaded.
For each instruction in this memory, DEBUG disassembles (translates
from machine code to assembly language) the instruction and displays
the address, the machine code, and the corresponding assembly language.
The optional range parameter can be used to specify a starting address,
or a starting and ending address, or a starting address and a length.
Subsequent Unassemble commands without any parameter cause DEBUG to
start at the instruction following the last instruction processed by
the previous Unassemble command. Pressing ENTER after an Unassemble
command will autorepeat and function as if another Unassemble command
without a range was entered.

---

V
View flip

Syntax: V

The View flip command (V) displays the program output screen if DEBUG
was started with the /F option. Press any key to return to DEBUG.

---

W
Write file or disk sectors

Syntax: W [address]
        W address drive startsector numberofsectors

The Write command (W) causes DEBUG to write BX:CX bytes to the output
file. The optional address parameter specifies the starting source
address. The default starting source address is 100h. Note that
loading a file from the DEBUG command line or with the Load command
will set BX:CX to the size of the file, a feature clearly intended
to aid in the patching of executables.

The Write command can also be used to write one or more logical sectors
to a disk drive. The drive should be specified as for the Load command.

---

X
Expanded memory (EMS) commands

Syntax: XA count
Syntax: XD handle
Syntax: XM logicalpage physicalpage handle
Syntax: XR handle count
Syntax: XS

The EMS commands (XA, XD, XM, XR, XS) are used to perform various
EMS functions. XA allocates expanded memory, XD deallocates
expanded memory, XM maps a logical page to a physical page,
XR reallocates expanded memory and XS displays expanded memory status.
Note the expanded memory commands are disabled by default since they
are of litte use to typical debugging. The may be enabled by defining
EMSCMD to 1 in DEBUG.ASM and rebuilding DEBUG and DEBUGX.

---

Functionality
-------------
For the Trace, Proceed, and Register commands, after DEBUG completes
the operations described above, it disassembles the next instruction
and displays the address of the instruction, the machine code, and
the corresponding assembly language. For the Trace and Proceed
commands, if the instruction contains a memory operand, DEBUG displays
the address that the operand refers to and the contents of that
address. The segment register specified in the address is the default
segment register for the instruction, or the segment register
specified by a segment override.

One perhaps non-obvious use for the Register command would be to
control the starting address for the next Trace or Proceed command
by loading a new value into CS and/or IP. And along the same lines,
non-obvious uses for the Assemble and Enter commands would be to
alter the instructions and/or data for the program being debugged.

When DEBUG processes a Trace, Proceed, Register, or Unassemble command,
it displays assembly language (as described above) for any byte value
or sequence of byte values that it recognizes as a valid instruction.
For any other byte value, DEBUG displays the DB pseudo-instruction
followed by the byte value. DEBUG may fail to recognize a byte value
as part of a valid instruction for any of the following reasons:

   The byte is part of an instruction that is specific to a later
   generation x86 processor.

   The disassembly process did not start at the first byte of a
   valid instruction.

   The byte is data.

Note that DEBUG's ability to execute an instruction (for the Trace
and Proceed commands) does not depend on its ability to recognize the
instruction.

DEBUG hooks the following interrupts:

                                real-mode       protected-mode (DPMI)
00 divide by zero               always          always
01 single-step                  always          always
03 breakpoint                   always          always
06 invalid opcode               CATCHINT06=1    always
0C stack fault                  CATCHINT0C=1    always
0D general protection fault     CATCHINT0D=1    always
0E page fault                   never           always
22 program termination          always          never

DEBUG saves and restores the program's Control-C (INT 23h) and
critical error (INT 24h) interrupt vectors, providing for better
isolation between the debugger and the program being debugged.

When a debugged program terminates, DEBUG will display the exit code
obtained from INT 21h function 4Dh. The high byte is the exit type
(0=normal, 1=Ctrl-C, 2=critical error, 3=TSR) and the low byte is the
return code.

DEBUGX supports debugging of DPMI client programs. When in protected-mode
the prompt changes from dash (-) to hashtag (#) to denote the CPU mode.

Instruction operands
--------------------
The instruction operands are the objects on which the instruction
"operates". For DEBUG, these objects can be constants, registers, or
memory. A memory operand specifies the offset address of the data to
operate on. To differentiate memory operands from constants, memory
operands must be enclosed in square brackets.

For a direct memory operand, the offset address of the data is
specified in the operand. For an indirect memory operand, the offset
address of the data is calculated at run-time using the contents of
one or two registers and an optional displacement. In 16-bit code, the
registers can be a base register (BX or BP) or an index register (SI or DI),
or one of each. The following examples illustrate the differences
between constant operands, register operands, direct memory operands,
and indirect memory operands:

   MOV   AX,100   ; Moves the value 100 into AX
   MOV   AX,BX    ; Copies the value in BX to AX
   MOV   AX,[100] ; Copies the word at DS:100 to AX
   MOV   AL,[BP+2]; Copies the byte at SS:BP+2 to AL

   JMP   100      ; Destination offset is 100
   JMP   AX       ; Destination offset is the value in AX
   JMP   [100]    ; Destination offset is the word at DS:100
   JMP   [BX]     ; Destination offset is the word at DS:BX
   JMP   [BX+4]   ; Destination offset is the word at DS:BX+4

   ; Near calls work just like the jump instructions above.

DEBUG statements
----------------
This section deals with the statements that DEBUG recognizes while
in assembly mode.

Each statement occupies a single line. For each statement, the first
character that is not a space or a tab must be a semicolon or the
start of a valid instruction mnemonic. A semicolon, at the start of
a statement or anywhere within a statement, causes DEBUG to ignore
the remainder of the line.

As previously noted, memory operands must be enclosed in square brackets.

In addition to the items detailed above, DEBUG statements can include
the following:

   The CPU register names (other than IP):
      AX BX CX DX
      AL AH BL BH CL CH DL DH
      SP BP
      SI DI
      CS ES DS SS

   The 32-bit CPU register names (other than EIP):
      EAX EBX ECX EDX ESP EBP ESI EDI
      FS GS

   The words NEAR (or NE) and FAR, optionally followed by PTR,
   which are used to override the default forms of the CALL and JMP
   instructions. The default form of a JMP instruction can be short,
   near, or far, depending on the destination. The default form of a
   CALL instruction can be near or far, depending on the destination.
   Note that DEBUG will default to far only if the destination is
   recognizable as a far address, which means that it must be a
   constant of the form segment:offset (for example, "JMP F000:FFF0").
   If the destination is specified by a memory operand (for example,
   "JMP  [100]"), DEBUG will default to near. The optional PTR has
   no effect on the assembly process.

   The words BYTE (or BY) and WORD (or WO) and DWORD (or DW),
   optionally followed by PTR, which are used to specify the type for
   memory data. For instructions that take two operands, DEBUG will
   assume that the type for the data specified by a memory operand matches
   the type for the other operand. For instructions that take one operand,
   the type must be specified. The optional PTR has no effect on
   the assembly process.

   For floating point opcodes, there exist 3 additional memory types,
   FLOAT (or FL), DOUBLE (or DO) and TBYTE (or TB):
       FLD  FLOAT [100]
       FSTP DOUBLE [100]
       FSTP TBYTE [100]

   The DB / DW / DD pseudo-instructions, which are used to assemble
   byte / word / dowubleword values. These pseudo-instructions are
   normally used to set aside space for and initialize data. They can
   also be used to synthesize instructions that DEBUG cannot assemble.
   Note that DEBUG will not allow a trailing comment on the same line
   as one of these pseudo-instructions.

   The pseudo-instructions ORG is used to set the starting address for the
   assembly of instructions.

   DEBUG checks for errors as it assembles each statement. If an error
   is detected, DEBUG stops assembling the statement and displays
   "^ Error" on the line following the statement. The position of the
   caret indicates the location in the statement where DEBUG detected
   the error.

Using page flipping
-------------------
If DEBUG is started with the /F option then page flipping is used.
DEBUG will write all of its output to video page 1 while program
output will be written to video page 0. Since most programs use the
current display page or in the case of fullscreen programs, page 0
this will keep DEBUG's output separate from that of the debugged
program. Use the V command to view the program output.
Note page flipping only works in standard color text modes (0-3).

DEBUG scripts
-------------
Because DEBUG uses the standard input and output devices, and because
these devices can be redirected, DEBUG can be made to input from
and/or output to a text file. This makes it possible to place DEBUG
commands and statements in a text file, a so-called DEBUG script, and
submit the file to DEBUG for processing.

---

N LOADIT.TXT
N This is a DEBUG script that will copy BOOTCODE.BIN
N to the first sector of drive A. Note that this will
N work only if the OS recognizes the diskette as
N having a valid format.
N BOOTCODE.BIN
L 100
W 100 0 0 1
Q

---

; SAVEMBR.TXT
; This is a DEBUG script that will save the MBR to the file MBR.BIN
a
mov dx,80
mov cx,1
mov bx,200
mov ax,201
int 13
int 3

g
r bx
0
r cx
200
n mbr.bin
w 200
q

---

; SYSVARS.TXT
; This is a DEBUG script that will dump the DOS 5+ SYSVARS table.
; Note: It will not work in MS-DOS or PC DOS DEBUG.
a
mov ah,52
int 21
lds si,es:[bx+4]
lds si,es:[bx+16]
nop

g 104
; DPB ptr, SFT ptr, CLOCK$ ptr, CON ptr
dd es:bx l10
; buffer size
dw l2
; buffers ptr, CDS ptr, FCB-SFT ptr
dd lc
; FCB keep count
dw l2
; actual drives, logical drives
db l2
; NUL device header
db l12
t
; SFT
dd ds:si l4
dw l2
db l3b
db l3b
db l3b
db l3b
db l3b
t
; CDS
d ds:si l58
d l58
d l58
d l58
d l58
q

---
