附录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命令摘要
续表