DOS Debugger Program

A DOS debugger is a utility program that comes with the MS-DOS operating system as a programming tool for debugging (trouble shooting) and testing executable files. The debugger is sometimes called a "mini-assembler," because it allows the user to create and run short or small assembly language programs. With the debugger, the user can access the system's main memory and save the program directly on the disk without the intervention of the DOS. In addition, the debugger can be used to disassemble object codes (machine instructions) into readable codes.

There are two ways to run the program under the debugger: single-step (trace) or Go with full speed. Single-stepping or tracing the program is to execute one instruction at a time. After each tracing, the program stops so that the user can examine the effects that are caused by every instruction in the program. The debugger also allows us to set a few breakpoints, and run program at the full speed until the particular instruction is reached.

Note that unless you are real sure about the operational function of the program that you are debugging, don't use G command to run the program, because it might cause some unexpected results. Since the DOS debugger allows the user to write on the absolute sector address on a disk, for the safety reason, it is very important that the user should make a backup copy of the program and then run the program.

DOS Debugger Environment

Before invoking or loading the DOS Debugger, you may want to locate where the DEBUG.COM program is stored in the system: it may be stored under C:\DOS\DEBUG.COM, if you are using a PC with a hard disk; or, it may be on a DOS supplemental disk or operating disk. After invoking the DEBUG.COM, the DEBUG itself then is loaded into the following memory area in the PC's main memory.

Refer to Figure 1, via the DEBUG you have complete access to the memory and the CPU registers of the 8088/8086 used in the PC.

 

 

 

Figure 1. The Debugger environment

 

Figure 2 shows the 16-bit registers that are shown on the debug screen. Note that the 8-bit registers such as AH, AL, and so on, are not directly displayed on the debug screen.

 

16-bit 8-bit Special Registers/general purpose

AX AH AL Accumulator

BX BH BL Base register

CX CH CL Counter register

DX DH DL Data register

16-bit Instruction Fetch

CS Code Segment Register Base address

IP Instruction Pointer Offset address

16-bit Stack Segment Operation

SP Stack Pointer Offset address

BP Base register Offset address

SS Stack segment register Base address

16-bit Source of String /Array

DS Data Segment Register Base address

SI Source Index Register Offset address

16-bit Destination of String /Array

ES Extra Data Seg. Reg. Base address

DI Destination Index Reg. Offset address

Flags: Overflow (OF), Directional Flag (DF), Interrupt Flag (IF), Trace Flag (TF), Sign bit flag (SF),

Zero Flag (ZF), Auxiliary Flag (AF), Parity Flag (PF), and Carry Flag (CF)

Figure 2. 8088/8086/80286 CPU registers

 

Debugger Commands

All DEBUG commands are single letter commands, and are usually followed by one or more parameters. The commands can be uppercase or lower case letters, or a combination of both. Delimiters are only required, however, between two consecutive hex numbers. The commands become effective only after you press the [Enter] key. To end the command, enter [Ctrl] and [Break] keys.

To invoke the debugger, enter one of two commands (depending on the system setup); the debug prompt, a dash '-', is displayed; debugger is then ready to take commands from you.

C>DOS\DEBUG ....If using a hard disk

A>DEBUG ....If two floppy drive PC is used

- ....Debug prompt

DEBUG COMMANDS

Commonly used debug commands such as ASSEMBLE, DUMP, ENTER, FILL, MOVE, COMPARE, and SEARCH are available for use in entering programs, examining or modifying storage locations in the memory.

 

A[address] (Assemble command)

We can write an assembly language program with the "A" or "a" command. The Assemble command "A" allows us to enter assembly language instructions using mnemonic symbols directly into memory. When we enter just "A" or "a" after the debugger prompt:

-A

0910:100- ..... you enter the instruction right after this prompt

CS:0100 is the default address. It uses the offset address 100H as the beginning address of the program. The other alternative is to specify the beginning address explicitly as follows:

-A100

0910:100- ..... you enter the instruction right after this prompt

 

C [addr1][range][addr2] (Compare command)

- [addr1] is the beginning address of 1st block of memory

- [range] determine the length of comparison

- [addr2] is the beginning address of the second block of memory

The "C" command compares the contents of two blocks of memory. For example, the following commands compare a memory block starting at DS:200 through DS:300 to an equal-size data block starting at address DS: 500. It will display each unequal element found in the address and contents of that byte in both blocks. No information is displayed if both of these blocks contain the same data.

-C 200 300 500

 

D[address] (Display or dump memory command)

The "D" command allows us to examine the contents of memory locations by dumping the data stored in the memory onto the screen.

If [address] is omitted,

-D

then the address used by previous D command is assumed and the 128 consecutive bytes offset from the current value in DS are displayed. When no previous D is used, the offset address 100 Hex is used.

Other examples of using the "D" command are

-D 100 .. dump memory locations starting at 100H

-D DS:100 .. dump memory locations starting at DS:100

-D CS:100 .. dump memory location starting at CS:100

-D DS:200 210 .. dump memory location in the range of 200-210

 

E[address][list] (Enter command)

Enter command will replace the contents of memory locations starting at the address specified by the DS register. Using this command, you can enter the machine code directly into the memory. The following examples show how to use the "E" command:

-E DS:100 FF FF FF FF .. enter four FF at 100H

-E DS:200 "The E Command:" .. enter ASCII characters

 

F [range][list] (Fill memory command)

The format of the "F" command is filling the memory locations in the [range] with the values in the [list]. The "F" command can be used to fill a block of consecutive memory locations with the same data. The "F" command examples are:

-F 100 110 FF .. Fill memory 100-110 with FF

-F 200 220 00 .. Fill memory 200-220 with 00

G[=address][address[address..]] (Go, execute command)

The "G" command allows us to execute the instructions and programs under the debugger. Examples of the GO commands are

-G =CS:200 210 .. run the program from 200 through 210

-G =CS:100 .. run the program at 100

-G .. run the program from current CS:IP location

H[value][value] (Hex arithmetic: add and sub)

Add and subtract two hex numbers; display sum and display. For example, we enter

-H AE BF

01B0 FF04 .. first number is sum .. second no is difference

-H 96 C2

0158 FF04

 

I[port address] (Input command)

Input and display one byte from the specified port in hex

L[address[drive [sector sector ]] (Load a file or disk sectors)

Load a file or absolute diskette sectors into memory; maximum number of sectors that can be loaded with a single Load command is Hex 80.

M[range][address] (Move a block of data)

Move or copy from one block of memory to another. Example of M command is

-M 100 200 300 .. move a data block start from the location

through 200 to the destination block starting

at 300

 

N[d:][path] filename (Name)

Name the file for the write disk command or Load command to call it.

 

O[port address][byte] (Output)

Send output bytes to the output port

P[=address][value] (Proceed)

Execute a loop, a repeat string instructions, a software interrupt, or a procedure

Q exit DEBUG program and return to the DOS

R[register name] (Register)

Display and/or modify the contents of registers and flags

 

S[range][list] (Search)

Search for characters through a specified range of address. The example is

-S 200 210 FF .. search the data byte FF in the range 200

through 210

 

T[=address][value] (Trace)

Execute an instruction and display the CPU registers. The examples of "T" commands are

-T .. trace the program from current CS:IP

-T =CS:100 .. trace the program from CS:100

-T =CS:100 4 .. trace the program from CS:100 for 4

instructions

U[address] (Unassemble command)

Translate the contents of memory into assembly instructions. The examples of "U" commands are

-U .. unassemble the program from current CS:IP

-U CS:100 105 .. unassemble the program from 100 to 105

 

W[address[drive sector sector]] (Write to disk command)

Write file on absolute diskette sectors. The CX should hold the number of bytes to be written on the disk, and the name of the program should be given by using the "N" command.

DEBUG COMMANDS (Continue)

Following commands are found in DOS 5.0 only

XA[count] (Allocate expanded memory)

Allocate a specific page of expanded memory. A page is 16-kbytes of memory.

For example: allocate 10 pages of expanded memory:

-XA A ..... you enter

Handle created=0003

XD[handle] (Deallocate expanded memory)

Deallocate a handle to expanded memory

For example: deallocate the handle 0003

-XD 0003

Handle 0003 deallocated

XM[lpage][ppage][handle] (Map expanded memory pages)

Map a logical page of expanded memory, belonging to the specific handle, to a physical page of expanded memory.

For example: to map logical page 6 of handle 0003 to physical page 2

-XM 5 2 0003

XS (Display expanded memory status)

Display information about the status of expanded memory

For example:

-XS

 

Using DEBUG

Example 1:

Using DEBUG.COM to examine 8088/8086/80286 CPU registers, modify the contents of AX register, verify the change, and then exit the debugger.

-r ....Examine registers command

AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=111E ES=111E SS=111E CS=111E IP=0100 NV UP EI PL NZ NA PO NC

111E:0100 2D444F SUB AX, 4F44

-RAX ....Examine and modify AX register

AX=0000

:10 ....You enter 10

-R ....Examine the resiters to see AX

AX=0010 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=111E ES=111E SS=111E CS=111E IP=0100 NV UP EI PL NZ NA PO NC

111E:0100 2D444F SUB AX, 4F44

-Q ....Exit debugger and return the control

to DOS

A>

Figure 3. Output display of example 1

After the r command is entered, the DEBUG sets the CPU registers with default values: registers AX, BX, CX, DX, BP, SI, and DI are set to 0000.

All segment registers are set to DS=111E, ES=111E, SS=111E, CS=111E. This number is the base address of the memory that the DEBUG is working on and it may be different from one machine to another machine, and may be different from one time to another. The instruction pointer, IP, is set to its default offset address (0100) by the DOS. Starting from actual memory location 112E0 Hex, that we calculated by shifting the IP one digit to the right and added to the CS, there is a garbage instruction

SUB AX, 4F44.

CS 111E

+ IP 0100

Effective Address 112E0 Hex

You then enter: RAX (or R AX or rax )

for examining/or modifying AX register. If you want to examine other registers, the correct register name must be referred. The AX=0010 is the correct entered value.

Finally, you enter Q or q to exit the DEBUG.

Example 2. Using the DEBUG to perform the following tasks:

1) Enter a short assembly language program as shown in Figure 4.

2) Save this program as "a:ex2-2.com" then exit DEBUG

3) Reinvoke the DEBUG to test the ex2-2.com program.

A>DEBUG .... invoke or load debugger

-A100 .... assemble the instructions at CS:100

111E:0100 MOV AX,0123 ... hit Enter key

111E:0103 ADD AX,25 ... hit Enter key

111E:0106 MOV BX,AX

111E:0108 ADD BX,AX

111E:010A MOV CX,BX

111E:010C SUB CX,AX

111E:010E SUB AX,AX

111E:0110 ... hit Enter key to end

-R ... examine registers

AX=0010 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=111E ES=111E SS=111E CS=111E IP=0100 NV UP EI PL NZ NA PO NC

111E:0100 B82301 MOV AX, 1023

-U ... disassemble the instructions

111E:0100 B82301 MOV AX,0123

111E:0103 052500 ADD AX,25

111E:0106 89C3 MOV BX,AX

111E:0108 01C3 ADD BX,AX

111E:010A 89D9 MOV CX,BX

111E:010C 29C1 SUB CX,AX

111E:010E 29C0 SUB AX,AX

111E:0110 0800 OR [BX+SI],AL .... Junks

Figure 4. Output display of example 2

The assembly language instructions that we use in this example are:

MOV AX, 1023 ; Move 1023 Hex into AX register

ADD AX, 25 ; AX = AX + 25 Hex = 1048 Hex

MOV BX, AX ; Move the content of AX register to BX register and

; the AX is unchanged BX = AX = 1048

ADD BX, AX ; BX = BX + AX = 1048 + 1048 = 2090 Hex

MOV CX, BX ; a copy of BX is move to CX register

SUB CX, AX ; CX = CX - AX

SUB AX, AX ; AX =AX - AX or clear AX register

Example 2 (continue)

2) Save the entered program as a:ex2-2.com.

Before you save the program, you may want to count how many bytes of memory space will be needed by this program. We count it starting from the instruction MOV AX, 1023 through SUB AX,AX.

The number on the first column is the base address and the numbers on second column are the offset addresses of the memory.

The numbers on the third column are translated machine codes. One hexadecimal digit on this column is 4-bit (two digits give 1-byte).

We counted the number on the third column: 16-bytes. The DEBUG uses the CX register as a counter that indicates the number of bytes to be saves. So we entered the following commands to save the program:

-RCX ..... modify the CX register

CX 0000

:10 ..... hex (decimal 16)

-n a:ex2-2.com ..... name the program

-w ..... write to the disk

Writing 0010 bytes

-q ..... Exit DEBUG

A>DIR ex2-2.com ..... see if the program is saved

Figure 2-12 Output display of example 2-2

3) Reinvoke the DEBUG for testing a:ex2-2.com

A>DEBUG ex2-2.com

-u .... unassembly the program

1133:0100 B82301 MOV AX,0123

1133:0103 052500 ADD AX,25

1133:0106 89C3 MOV BX,AX

1133:0108 01C3 ADD BX,AX

1133:010A 89D9 MOV CX,BX

1133:010C 29C1 SUB CX,AX

1133:010E 29C0 SUB AX,AX

1133:0110 50 PUSH AX .... Junks

-

Figure 5. Output display of example 2

Example 2 (continue)

4) Test the ex2-2.com program by tracing the instructions

-R ..... examine CPU regiter before single-step

AX=0010 BX=0000 CX=0010 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0100 NV UP EI PL NZ NA PO NC

1133:0100 B82301 MOV AX, 1023 ....(Move 1023Hex to AX)

-T ...... execute the instruction appears

AX=1023 BX=0000 CX=0010 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0103 NV UP EI PL NZ NA PO NC

1133:0103 052500 ADD AX, 0025 ...... (AX = AX + 25 Hex)

-T

AX=1048 BX=0000 CX=0010 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0106 NV UP EI PL NZ NA PE NC

1133:0106 89C3 MOV BX, AX ...... (BX = AX)

-T

AX=1048 BX=1048 CX=0010 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0108 NV UP EI PL NZ AC PE NC

1133:0108 01C3 ADD BX, AX ......(BX = BX + AX)

-T

AX=1048 BX=0290 CX=0010 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010A NV UP EI PL NZ AC PE NC

1133:010A 89D9 MOV CX, BX ......(CX = BX)

-T

AX=1048 BX=0290 CX=0290 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010C NV UP EI PL NZ AC PE NC

1133:010C 29C1 SUB CX, AX ......(CX = CX - AX)

-T

AX=1048 BX=0290 CX=1048 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010E NV UP EI PL NZ AC PE NC

1133:010E 29C0 SUB AX, AX ......(AX = AX - AX)

-T

AX=0000 BX=0290 CX=1048 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0110 NV UP EI PL NZ NA PE NC

1133:0110 50 PUSH AX ...... Junks, stop!

Figure 6. Output display of example 2

Notice that in the debugger environment, all the numeric data are represented in hex numbers. The debugger shows the instruction to be executed, before you enter the trace command (T). After the execution of each instruction, the instruction pointer IP is incremented and the register that appears on the left side of the instruction is modified. In addition, some flags are changed to reflect the status after the operations. All these changes are showed in the high-lighted areas. If you want to run trace the program one more time, the IP must be set to the right offset address.

Example 3. Using the debugger to perform the following tasks:

1) Create a short assembly language program that does the following:

- Move 09 Hex to AX register:

- Double this number in AX and then move a copy of this number to both

BX and CX registers

- Set the source index register (SI) to 180 Hex: [MOV SI, 180]

- Store the contents of AX, BX, and CX to the data area pointed to by DS:SI, where

the data segment register (DS) holds the default base address:

MOV [SI], AX

INC SI

MOV [SI], BX

INC SI

MOV [SI], CX

2) Save this program as a:ex2-3.com

3) Exit the Debug

4) Invoke DEBUG to load a:ex2-3.com

5) Trace the program and examine the data area that is pointed to by DS:180

- Fill the data area pointed to by the DS:200 through DS:220 with the hex number FF

and examine this result.

Solution:

1) Moving the hex number 09 into AX register requires the instruction [MOV, AX, 09].

This is the instruction of the immediate addressing mode, since the data 09 is included in the instruction. Notice that AX is the destination of the data movement.

2) There is more than one instruction than can be used to double the contents of the AX register. We use addition instruction: [ADD AX,AX]. This is the register addressing mode instruction since the source and destination of the data are all within the CPU register. This instruction does the following operation: AX = AX + AX

3) The [MOV BX,AX; MOV CX, AX] instructions move data from AX to both BX and CX. The addressing mode of this type of instruction is register addressing.

4) The source index register is initialized with the offset address 180 hex through the instruction MOV SI, 180

5) To store the data in the data area whose base address is held by the data segment register DS and offset address is held by the SI register. We use the indirect addressing instruction:

MOV [SI], AX

Where the bracket around the SI register means that the destination of this data movement is the memory pointed by the DS:SI register.

We move three 16-bit words' data to memory. After the first movement, we then increment the SI by one so it can point to next available location:

INC SI

We then repeat the SI updating and data storing until all the contents of the AX, BX and CX are stored. Figure 2-15 shows the programming model for the solving this problem.

Figure 4 Programming model of the example 3

 

Invoke the debug , enter the instructions, name the program, count file size, and write to

the disk.

A>DEBUG

-a100 .... assemble the instructions at CS:100

111E:0100 mov ax,09 .... hit enter

111E:0103 add ax,ax

111E:0105 mov bx, ax

111E:0107 mov cx, ax

111E:0109 mov si, 180

111E:010C mov [si],ax

111E:010E inc si

111E:011F mov [si],bx

111E:0111 inc si

111E:0112 mov [si],cx

111E:0114

-n a:ex2-3.com .....name the program

-r cx ....No of bytes to write

CX 0000

:14

-w

Writing 0014 bytes

Figure 5 Output screen of example 3.

There are two ways to load the program into the debug. The first approach is to invoke the DEBUG and pass the program name as the parameter: A>DEBUG A:EX2-3.COM

The second approach is to invoke the debug, name the program, and then load the program. We take this approach to bring the program back to DEBUG

A>DEBUG

-n a:ex2-3.com

-l ...... load the program

-r

AX=0000 BX=0000 CX=0014 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0100 NV UP EI PL NZ NA PO NC

1133:0100 B80900 MOV AX,0009

-t

AX=0009 BX=0000 CX=0014 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0103 NV UP EI PL NZ NA PO NC

1133:0103 01C0 ADD AX,AX

-t

AX=0012 BX=0000 CX=0014 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0105 NV UP EI PL NZ AC PE NC

1133:0105 89C3 MOV BX,AX

Figure 6 Loading and tracing the example ex2-3.com program

 

 

 

 

-t

AX=0012 BX=0012 CX=0014 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0107 NV UP EI PL NZ AC PE NC

1133:0107 89C1 MOV CX,AX

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0109 NV UP EI PL NZ AC PE NC

1133:0109 BE8001 MOV SI,0180

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0180 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010C NV UP EI PL NZ AC PE NC

1133:010C 8904 MOV [SI],AX DS:0180=1212

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0180 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010E NV UP EI PL NZ AC PE NC

1133:010E 46 INC SI

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0181 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=010F NV UP EI PL NZ NA PE NC

1133:010F 891C MOV [SI],BX DS:0181=1200

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0181 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0111 NV UP EI PL NZ NA PE NC

1133:0111 46 INC SI

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0182 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0112 NV UP EI PL NZ NA PE NC

1133:0112 890C MOV [SI],CX DS:0182=0000

-t

AX=0012 BX=0012 CX=0012 DX=0000 SP=FFFE BP=0000 SI=0182 DI=0000

DS=1133 ES=1133 SS=1133 CS=1133 IP=0114 NV UP EI PL NZ NA PE NC

1133:0114 0D0A00 OR AX,000A

Figure 7. Loading and tracing the example ex2-3.com program (continue)

To verify that the data area pointed by the register pair DS:SI, we dump or display the data block using D command. We see that the data are stored in the right place.

 

 

 

 

-d ds:180

1133:0180 12 12 12 00 72 65 61 64-73 20 66 72 6F 6D 20 61 ....reads from a

1133:0190 20 64 65 76 69 63 65 0D-0A 00 B3 39 42 52 45 41 device....9BREA

1133:01A0 4B 20 69 73 20 00 DC 39-56 45 52 49 46 59 20 69 K is ..9VERIFY i

1133:01B0 73 20 00 E8 39 45 43 48-4F 20 69 73 20 00 F5 39 s ..9ECHO is ..9

1133:01C0 6F 66 66 0D 0A 00 00 3A-6F 6E 0D 0A 00 08 3A 49 off....:on....:I

1133:01D0 6E 76 61 6C 69 64 20 70-61 74 68 20 6F 72 20 66 nvalid path or f

1133:01E0 69 6C 65 20 6E 61 6D 65-0D 0A 00 0F 3A 49 6E 76 ile name....:Inv

1133:01F0 61 6C 69 64 20 6E 75 6D-62 65 72 20 6F 66 20 70 alid number of p

-

-q

Figure 8 Dump memory data on the screen