附录4 DEBUG的使用

附录4 DEBUG的使用

DEBUG是MS-DOS的一个外部命令,是基于命令行的16位调试器,用来测试和调试可执行程序。DEBUG能显示所有的程序代码和十六进制格式的数据,以及输入存储器的任何十六进制格式的数据,它通过单步、设置断点等方式为汇编语言程序员提供非常有效的调试手段。

1.DEBUG命令的格式

DEBUG的每个命令都是一个字母,后跟一个或多个参数。使用DEBUG命令的基本规则如下:

(1)不区分大小写字母。

(2)只使用十六进制数,且不带后缀H。

(3)命令各项之间使用空格或逗号作为分隔符。分隔符只在两个数值之间是必须的。

(4)段和偏移地址是用冒号来指定的,形如“段基址:偏移地址”。

(5)可以用Ctrl-C或Ctrl-Break终止命令的执行。

2.DEBUG命令的参数

DEBUG中许多命令的参数是<地址>和<地址范围>。下面分别对<地址>和<地址范围>作具体说明。

(1)<地址>的格式有两种:

①<段基址>:<偏移地址>

其中,<段基址>可以是数值或段寄存器,<偏移地址>是数值。

②<偏移地址>

若未指定<段基址>,则采用缺省值。与数据有关的命令D、E、C和F等,缺省段基址为DS的值;与代码有关的命令A、U、G、T和P等,缺省段基址为CS的值。

例如:

18E4:0100;段基址为18E4H,偏移地址为100H

CS:100;段基址为CS的值,偏移地址为100H

200;段基址为所在命令的缺省值(CS或DS),偏移地址为200H

(2)<地址范围>用来表示一个内存区域,有两种格式:

①<开始地址><结束地址>

其中,<结束地址>不带段基址。

②<开始地址>L<长度>

其中,<长度>表示字节数,指定的地址范围不跨段。

例如,内存区域18E4:1000H到18E4:1020H可表示为

18E4:10001020

18E4:1000L21

3.DEBUG程序的调用

DEBUG对应的可执行文件为debug.exe。debug.exe文件位于Windows\system32目录

(WindowsXP)或Windows\command目录(Windows9x)下。

在DOS提示符下,可输入如下命令启动DEBUG:

DEBUG[<可执行文件路径名>[<参数表>]

其中,<可执行文件路径名>是被调试的可执行文件的名字(.exe或.com文件),扩展名不能省略。<参数表>是被调试文件所需的命令行参数。

例如,若要调试的可执行文件名为demo.exe,则输入命令

DEBUG demo.exe

将进入DEBUG,同时将指定的程序demo.exe装入内存,以便调试。

如果用户输入文件名,则DEBUG将指定的文件装入存储器中,用户可对其进行调试。如果未输入文件名,则用户可以用当前存储器的内容工作,或者用DEBUG命令N和命令L把需要的文件装入存储器后再进行调试。

进入DEBUG后,出现提示符“-”,此时就可用DEBUG命令来调试程序。

4.DEBUG命令

较常用的DEBUG命令是D、E、G、Q、P、R、T和U。在DEBUG提示符下,使用帮助命令“?”,可以显示DEBUG命令列表,查看DEBUG主要命令及参数。以下DEBUG命令格式中方括号[]中的内容为可选项,表示可有可无。

(1)显示内存单元的命令D(dump),以十六进制和ASCII码形式显示部分内存单元的内容,默认的寄存器是DS,有下列两种格式。

①D[<地址>]

显示由指定地址开始的若干内存单元的值。对于80列显示模式,显示128个字节。如果未指定参数,则从上一个D命令的结束地址开始显示。若前面未用过D命令,缺省则从CS:IP开始显示。

例如:

-D200;显示从DS:200H开始的内存单元的值

-D;显示从CS:IP开始的内存单元的值

-DCS:150;显示从CS:150H开始的内存单元的值

②D<地址范围>

显示由<地址范围>指定的所有内存单元的值。

例如:

-D30032C;显示从300H到32C的内存单元的值

执行D命令后,屏幕左边显示的是内存地址,中间是从该地址开始的若干字节值(十六进制),右边是用ASCII字符表示的每个字节,·表示不可显示的字符。

(2)修改内存的命令E(Enter),用来设置指定内存单元的值,包括下列两种格式:

①E<地址><字节表>

<地址>若只给出偏移地址,则使用DS当前值作为段基址。<字节表>用来修改从指定地址开始的内存区域,它是以空格或逗号分隔的若干十六进制字节或字符串。字符串要使用单引号或双引号。

例如:

-EDS:200'any';用‘a’、‘n’、‘y’三个字节替代DS:200到DS:202原先的值-E105133A20;用13H、3AH、20H来替代DS:105到DS:107原先的值

②E<地址>

以交互方式逐个修改连续的内存单元。输入该命令后,DEBUG显示指定地址及相应内存单元的值,等待用户修改。此时,可以采取下列操作:

输入一个新的值;

输入空格跳到下一个地址单元;

输入“-”返回上一个地址单元;

按回车键结束E命令。例如,输入命令

-ECS:100

则可能显示为:

18E4:010089·

如果需要把该单元的内容修改为78,则用户可以直接输入78,再按“空格”键可接着显示下一个单元的内容,此时显示为:

18E4:010089·781B·

这样,用户可以不断修改相继单元的内容,直到用回车键结束该命令。

注意,E命令后必须指定内存地址。

(3)内存比较命令C(Compare),用来比较两个内存块的值,格式:

C<地址范围><地址>

其中,<地址范围>指出第一个内存块,<地址>指出第二个内存块的起始地址。比较的字节数由<地址范围>确定。若只给出偏移地址,则使用DS当前值作为段基址。

C命令依次比较两个内存块的每个字节。若两块相等,则不输出任何信息;若发现有不相等的字节,则显示出它们的地址和值。屏幕从左到右显示的依次是:第一个内存块地址及其相应的值、第二个内存块的值及其地址。

例如:

-C2000:010080;比较内存块2000:0H~2000:100H与DS:80H~DS:;180H

-C2000:0L203000:0;比较内存块2000:0H~2000:1FH与3000:0H~3000:;1FH

(4)内存填充命令F(Fill)。

格式:F<地址范围><字节表>

用此命令可将<字节表>中的字节写入<地址范围>所指定的内存区域。若只给出偏移地址,则使用DS当前值作为段基址。

若<字节表>中的字节数超过<地址范围>的字节数,则忽略多余的字节;若<字节表>中的字节数少,则重复使用这些数据,直到填满指定的<地址范围>为止。

例如:

-F2000:070;将2000:0000H~2000:0007H的8个字节均置为0

-F07123;将DS:0000H~DS:0007H的8个字节依次置为1、2、

;3、1、2、3、1、2

(5)内存传送命令M(Move),用来将一个内存区的数据(或代码)复制到另一个内存区。

格式:M<地址范围><地址>

其中,<地址范围>指出要复制的源内存块,<地址>作为目的内存块的起始地址,复制的字节数由<地址范围>确定。若只给出偏移地址,则使用DS当前值作为段基址。

例如:

-M2000:010080;复制内存块2000:0H~2000:100H的值到DS:80H~;DS:180H

-M2000:0L203000:0;复制内存块2000:0H~2000:1FH的值到3000:0H~;3000:1FH

如果源块与目的块重叠,DEBUG也能正确处理。

(6)寄存器命令R(Register),用来显示和修改寄存器的值,包括下列三种格式:

①R

显示CPU内所有寄存器和8个标志位的值,并反汇编CS:IP所指的命令。8个标志位的符号分别为(0/1):OF=NV/OV,DF=UP/DN,IF=DI/EI,SF=PL/NG,ZF=NZ/ ZR,AF=NA/AC,PF=PO/PE,CF=NC/CY。

②R<寄存器名>

显示和修改指定寄存器的值。如果不修改则按回车键结束命令,否则,可输入欲修改的内容。其中,<寄存器名>只能是8086/8088的16位寄存器AX、BX、CX、DX、SP、BP、SI、DI、DS、ES、SS、CS、IP和F(标志寄存器)。

③RF

显示和修改8个标志位的值。如果不修改则按回车键结束命令,否则,可输入标志位的符号,输入符号的个数与顺序可以是任意的。

(7)运行命令G(Go)。

格式:G[=<地址>][<断点地址1><断点地址2>…<断点地址10>]

其中,等号“=”后的<地址>指出程序执行的起始地址,若未指定,则缺省为CS: IP。指定的断点最多为10个,也可以没有。若只给出偏移地址,则使用CS当前值作为段基址。

G命令从指定地址开始执行内存中的程序,直到程序结束或遇到指定的任一断点时停止执行。若遇到断点,则显示所有寄存器和标志位的当前值以及要执行的下一条指令;若程序正常结束,则显示“Programterminatednormally”。

例如,假设从100H处开始执行指令,断点地址为012EH,则使用以下命令

-G=10012e

(8)跟踪命令T(Trace)。

格式:T[=<地址>][<指令条数>]

其中,等号“=”后的<地址>指出程序执行的起始地址,若未指定,则缺省为CS: IP。若只给出偏移地址,则使用CS当前值作为段基址。

T命令从指定地址开始以单步方式执行程序,<指令条数>给出执行的指令数。每条指令执行后,都要显示所有寄存器和标志位的值以及下一条指令。若未给出<指令条数>,则缺省值为1。

T命令执行时,若遇到CALL或INT指令,会跟踪进入相应过程或中断服务程序内部。对于带重复前缀(如REP)的指令,每次重复执行算一步。

例如:

-T;执行下一条指令

-T10;执行下面10H(16)条指令

(9)继续命令P(Proceed)。

格式:P[=<地址>][<指令条数>]

该命令类似于T命令,但将CALL、LOOP、INT或带重复前缀指令(如REP)执行当前一步,不会跟踪进入相应过程或中断服务程序内部。例如,如果继续执行的是INT10H操作,那么只要输入P就可以从头到尾地执行整个操作。

(10)汇编命令A(Assemble)。

格式:A[<地址>]

该命令的功能是将用户输入的汇编语言指令汇编为机器代码,存入指定地址开始(若只给出偏移地址,则使用CS当前值作为段基址。当地址缺省时,如果以前未用过此命令则从CS:100开始,如果以前用过此命令,则从它最后停止的地址开始)的内存单元。由于DEBUG把输入的数字均看成十六进制数,如果要输入十进制数,则其后应加以说明,如200D。

当执行A命令时,DEBUG等待用户输入指令序列。输入每条指令后回车,再直接按回车键结束A命令。

(11)反汇编命令U(Unassemble),用来将二进制代码反汇编为汇编语言的符号指令,包括下列两种格式:

①U[<地址>]

从指定地址开始,反汇编若干字节。对于80列显示模式,反汇编32个字节(为了保证最后一条指令的完整性,可能会多于32个字节)。若未指定地址,则从上一个U命令的最后一个单元开始;若前面未使用过U命令,则缺省为CS:IP。

②U<地址范围>

对指定范围的内存区进行反汇编。若只给出偏移地址,则使用CS当前值作为段基址。

例如,输入命令:

-U10010c则可能显示为:

18E4:0100C70604023801MOVWORDPTR[0204],0138

18E4:0106C70606020002MOVWORDPTR[0206],0200

18E4:010cC70608020202MOVWORDPTR[0208],0202

执行U命令后,屏幕左边显示的是内存地址,中间是机器代码,右边是对应的汇编语言指令。

(12)文件命名命令N(Name)。

格式:N<文件路径名>[<参数表>]

此命令将指定的文件路径名存入DEBUG的文件控制块FCB中,以便后面用L或W命令把文件装入或存盘。<参数表>给出可执行文件运行时的命令行参数。

例如下列命令:

-DEBUG;启动DEBUG

-NFilename

-L相当于

-DEBUG Filename

(13)装入命令L(Load),用来将一个文件或磁盘指定扇区的内容装入内存,包括下列两种格式:

①L[<地址>]

将已用N命令命名的文件装入到指定内存单元。要想装入没有命名的文件,应当首先给它命名。该命令把装入文件的字节数回送到BX:CX。对于可执行文件.EXE或.COM,通常不指定装入地址,由DEBUG分配,装入后自动设置CS:IP,一般IP为0(.EXE文件)或100H(.COM文件)。若指定地址,则可执行文件的装入地址必须是CS: 100H。

②L<地址><驱动器号><起始逻辑扇区号><扇区数>

将磁盘的若干扇区(最多80H)装入指定的内存地址。若只给出偏移地址,则使用CS当前值作为段基址。其中,0表示A盘,1表示B盘,2表示C盘,依此类推。例如,将C盘引导扇区(逻辑扇区号为0)的内容装入内存地址CS:0,然后查看,可用下列命令:

-L0202

-DCS:0

(14)写盘命令W(Write),有以下两种格式:

①W[<地址>]

将指定地址开始的BX:CX个字节写入已由N命令命名的文件中。若只给出偏移地址,则使用CS当前值作为段基址。若未指定地址,则缺省为CS:100H。

注意,在执行W命令前,必须正确设置BX和CX的值。另外,W只能写入.COM文件,不支持.EXE文件(为了修改.EXE文件,可以临时改变扩展名)。

②W<地址><驱动器号><起始逻辑扇区号><扇区数>

将指定内存地址的数据写入磁盘的若干扇区(最多80H个)中。若只给出偏移地址,则使用CS当前值作为段基址。各参数的含义同L命令。此格式下的W命令直接将数据写入指定扇区,使用时一定要小心,否则会破坏磁盘上的文件系统乃至引导扇区。

(15)搜索命令S(Search),用来在指定的内存区域内搜索特定字节串。

格式:S<地址范围><字节表>

若只给出偏移地址,则使用DS当前值作为段基址。若未找到所需的字节串,则不显示任何信息;否则,显示其每次出现的地址。

例如,在内存DS:100和DS:15E间查找“Pross”则使用以下命令:

-S10015E‘Pross’

(16)十六进制数计算命令H(Hex)。

格式:H<数值><数值>

显示两个十六进制数(16位)的和与差。最大长度是4个十六进制数位。

例如,命令

-H 14F22

显示结果为171(和)与12D(差)。

(17)端口输入命令I(Input)。

格式:I<端口地址>

此命令从指定的I/O端口读入一个字节并显示。

(18)端口输出命令O(Ouput),用于输出一个字节到指定的I/O端口。

格式:O<端口地址><字节>

(19)退出命令Q(quit),使用此命令退出DEBUG,返回DOS。此命令并无存盘功能,若需存盘应先使用W命令。

格式:Q

DEBUG命令摘要

img125

续表

img126