wenmo8 发布的文章

窗口切换

可以使用以下键盘快捷方式窗口之间进行切换。

效果

CTRL+TAB

调试信息窗口之间切换。 通过重复使用此密钥,你可以扫描通过的所有窗口,而不考虑是否浮动、 停靠本身,或选项卡式停靠窗口的集合的一部分。

Alt+Tab

目前,在您的桌面上的窗口之间切换。 此外可以使用此键盘快捷方式的 WinDbg 帧和已创建任何其他停靠之间进行切换。

菜单命令

您可以使用以下键盘快捷方式而不是鼠标来选择菜单命令。 

等效的菜单

F1

帮助 |内容

F3

编辑 |查找下一个

SHIFT+F3

与相同编辑 |查找下一个,但按反向执行搜索。

Alt + F4

文件 |退出

CTRL+F4

文件 |关闭当前窗口

F5

调试 |转到

SHIFT+F5

调试 |停止调试

CTRL+SHIFT+F5

调试 |重新启动

F6

文件 |附加到进程

F7

调试 |运行到光标处

F8

调试 |单步执行

F9

如果活动窗口的源或反汇编窗口:在当前行中插入断点。 (如果已没有当前行上设置断点,此按钮将移除该断点。)

否则:此时将打开断点像那样的对话框编辑 |断点

ALT+F9

编辑 |断点

F10

调试 |逐过程执行

Ctrl+F10

调试 |运行到光标处

F11

调试 |单步执行

SHIFT+F11

调试 |跳出

ALT+1

此时将打开调试器命令窗口(与相同视图 |命令)。

ALT+SHIFT+1

关闭命令窗口。

ALT+2

此时将打开监视窗口 (与相同视图 |观看)。

ALT+SHIFT+2

关闭监视窗口

ALT+3

此时将打开局部变量窗口(与相同视图 |局部变量)

ALT+SHIFT+3

关闭局部变量窗口。

ALT+4

此时将打开寄存器窗口(与相同视图 |注册)。

ALT+SHIFT+4

关闭寄存器窗口。

ALT+5

打开一个新内存窗口(与相同视图 |内存)。

ALT+SHIFT+5

关闭内存窗口。

ALT+6

此时将打开调用窗口(与相同视图 |调用堆栈)。

ALT+SHIFT+6

关闭调用窗口

ALT+7

此时将打开反汇编窗口(与相同视图 |反汇编)。

ALT+SHIFT+7

关闭反汇编窗口。

ALT+8

打开草稿板 (与相同视图 |Scratch Pad)。

ALT+SHIFT+8

关闭草稿板。

ALT+9

此时将打开进程和线程窗口(与相同视图 |进程和线程)。

ALT+SHIFT+9

关闭进程和线程窗口中。

CTRL + A

编辑 |选择所有

CTRL + C

编辑 |复制

CTRL + D

文件 |打开故障转储

CTRL+E

文件 |打开可执行文件

Ctrl+F

编辑 |查找

CTRL + G

编辑 |转到地址

CTRL+I

文件 |图像文件路径

CTRL+SHIFT+I

编辑 |设置当前指令

CTRL + K

文件 |内核调试

Ctrl+L

编辑 |转到行

Ctrl+O

文件 |开放源代码文件

Ctrl+P

文件 |源文件路径

CTRL+R

文件 |连接到远程会话

Ctrl+S

文件 |符号文件路径

CTRL + V

编辑 |粘贴

CTRL+SHIFT+V

编辑 |评估所选内容

Ctrl+W

文件 |打开工作区

CTRL+X

编辑 |剪切

CTRL + SHIFT + Y

编辑 |显示所选的类型

ALT +\* (数字键盘)

编辑 |转到当前指令

SHIFT + DELETE

编辑 |剪切

SHIFT + INSERT

编辑 |粘贴

CTRL + INSERT

编辑 |复制

CTRL + BREAK

调试 |中断

ALT+DEL

调试 |中断

控制键

以下键盘快捷方式是等效于 KD / CDB 控制键。

等效的菜单KD / CDB 控制密钥

CTRL+ALT+A

调试 |内核连接 |周期的波特率

CTRL + A

CTRL + ALT + D

 

CTRL + D (切换调试信息)

CTRL+ALT+K

调试 |内核连接 |周期初始中断

CTRL + K

CTRL + ALT + R

调试 |内核连接 |重新同步

CTRL+R

CTRL+ALT+V

视图 |详细输出

CTRL + V

CTRL + ALT + W

视图 |显示版本

Ctrl+W

插入符控制

您可以使用以下键盘快捷方式移动插入符号 (^) 中的大多数调试的信息窗口。

插入符号移动

向左一个字符

左侧

右一个字符

右侧

左移字

CTRL+LEFT

正确的单词

CTRL + 向右键

向上移动一行

UP

向下移动一行

向下

向上翻页

Page Up

向下翻页

Page Down

当前行的开头

Home

在行尾

End

该文件的开头

CTRL + HOME

文件的末尾

CTRL + END

请注意  中调试器命令窗口、 向上和向下键浏览通过命令历史记录。 可以使用 INSERT 键以将插入模式下打开和关闭。

文本选择

使用以下键盘快捷方式选择文本。

选择

左侧的字符

SHIFT+LEFT

右侧的字符

SHIFT + 向右键

左侧的单词

SHIFT+CTRL+LEFT

右侧文字

SHIFT + CTRL + 向右键

当前行

SHIFT + 向下插入符号是否在第 1 列

上述行

SHIFT + 向上如果插入点在第 1 列

至行尾

SHIFT + END

到行首

SHIFT + HOME

启动屏幕

SHIFT + PAGE UP

屏幕上向下

SHIFT + Page Down

到文件的开头

SHIFT + CTRL + HOME

到文件的末尾

SHIFT+CTRL+END

文本删除

使用以下键盘快捷方式删除文本。

DELETE

插入符号右边的字符

DELETE

插入符号左边的字符

退格符

所选的文本

DELETE

在 WinDbg 中,源窗口显示已加载到调试器中的源文件。

如何打开源代码窗口

  • 通过菜单File--->Open Source File打开源代码文件,窗口随之打开
  • 通过快捷键Ctrl+O
  • 通过工具栏
  • 设置源路径,调试器实时自动打开

使用源代码窗口

通过上面方式打开的窗口如下:

 

每个源窗口都显示一个源文件的文本。 不能在调试器中编辑源文件。每个源窗口都具有包含附加命令的快捷菜单。 若要访问菜单,请右键单击标题栏,或单击窗口右上角附近显示的图标(显示源窗口工具栏快捷菜单的按钮屏幕截图)。 以下列表描述了一些菜单命令:

 

  • Set instruction pointer to current line 会将指令指针的值更改为对应于当前行的指令。 此命令等效于使用 "编辑 |设置当前指令命令或按 CTRL + SHIFT + I.

  • Edit this file 在文本编辑器中打开源文件。编辑器由WinDiff编辑器注册表信息或WINDBG_INVOKE_editor环境变量的值确定。例如,当WINDBG_INVOKE_EDITOR的值为以下值时。

     
    c:\my\path\myeditor.exe -file %f -line %l

软件调试的概念

软件调试是泛指重现软件缺陷问题,定位和 查找问题根源,最终解决问题的过程。 软件调试通常有如下两种不同的定义:

  • 定义1:软件调试是为了发现并排除软件程序中 的错误,可以通过某种方法控制被调试程序的执行过 程,以便随时查看和修改被调试程序执行状态的方法。 在该定义中,软件测试属于软件调试的一部分,与 牛津词典中的调试定义类似。 在牛津词典中调试定义 为:“识别和排除计算机硬件或软件中错误的过程。”
  • 定义2:调试是执行一次成功的测试之后所要进 行的工作。 所谓成功的测试,是指它可以证明程序没 有实现预期的功能。 调试包含两个步骤,从执行了一个成功测试用例,发现问题后开始;第一步,确定程序 中可疑错误的准确性质和位置;第二步,修改错误。 在该定义中软件测试从调试工作中分离出来。

软件调试的内涵

软件调试是将编制的程序投入实际运行前,用手工或编译程序等方法进行测试,修正语法错误和逻辑错误的过程。这是保证计算机信息系统正确性的必不可少的步骤。编完计算机程序,必须送入计算机中测试。根据测试时所发现的错误,进一步诊断,找出原因和具体的位置进行修正。

调试这个术语可能意味着很多不同的事情,但最字面的意思是,它意味着从代码中删除错误、异常和bug。现在,有很多方法可以做到这一点。例如,可以通过扫描代码以查找输入错误或使用代码分析器进行调试。您可以使用性能分析器调试代码。或者,可以使用调试器进行调试。

软件调试的基本过程

按照定义1,软件系统调试的基本过程如下:

  1. 用编辑程序把编制的源程序按照一定的书写格式送到计算机中,编辑程序会根据使用人员的意图对源程序进行增、删或修改。
  2. 把送入的源程序翻译成机器语言,即用编译程序对源程序进行语法检查并将符合语法规则的源程序语句翻译成计算机能识别的“语言”。如果经编译程序检查,发现有语法错误,那就必须用编辑程序来修改源程序中的语法错误,然后再编译,直至没有语法错误为止。
  3. 使用计算机中的连接程序,把翻译好的计算机语言程序连接起来,并扶植成一个计算机能真正运行的程序。在连接过程中,一般不会出现连接错误,如果出现了连接错误,说明源程序中存在子程序的调用混乱或参数传递错误等问题。这时又要用编辑程序对源程序进行修改,再进行编译和连接,如此反复进行,直至没有连接错误为止。
  4. 将修改后的程序进行试算,这时可以假设几个模拟数据去试运行,并把输出结果与手工处理的正确结果相比较。如有差异,就表明计算机的程序存在有逻辑错误。如果程序不大,可以用人工方法去模拟计算机对源程序的这几个数据进行修改处理;如果程序比较大,人工模拟显然行不通,这时只能将计算机设置成单步执行的方式,一步步跟踪程序的运行。一旦找到问题所在,仍然要用编辑程序来修改源程序,接着仍要编译、连接和执行,直至无逻辑错误为止。也可以在完成后再进行编译。

按照定义2,软件系统调试的基本过程如下:

  1. 重现问题:重现软件测试发现的问题;
  2. 问题定位:确定可能发生问题的程序段位置;
  3. 查找原因:分析相关代码,确定导致缺陷问题 的内在原因;
  4. 设计方案:提出软件缺陷问题解决方案;
  5. 修改代码:根据设计方案修改程序代码;
  6. 验证和确认:采用审查、分析和测试等技术来 确定错误是否被排除,是否引入了新的错误。

上述6个步骤不断迭代进行,直至问题解决。 软件调试基本过程如图1所示:

 

在这些步骤中,问题定位和查找原因是软件调试 的关键环节,其工作量约占总工作量的90%以上。 软 件调试是一项既耗时又费力,同时又富有技巧性的工 作。 目前软件调试中的问题定位研究的比较多。

 

 

可以看到,定义一的流程更贴合我们的日常开发测试工作;而定义二的流程更贴合我们测试特别是软件发布或上线后发现问题的处理相关工作。

软件调试基本特征

  • 广泛的关联性
    需要调试人员有着雄厚的计算机基础知识(包括操作系统、开发语言、工具等)以及精通面向的业务问题域知识。
  • 难度大
    从"广泛的关联性"就可以知道难度大不大了。当然也看面临的具体问题和调试人员的素质
  • 难以预估完成时间
    这个时间真的是没法预估,除非某个问题的领域专家和对软件整体架构及代码的理解熟悉程度。

软件调试分类

  • 按调试目标的系统环境分类:Windows下的软件调试、Linux下的软件调试、Dos下的软件调试等
  • 按目标代码的执行方式分:
    脚本程序 – 脚本调试器
    执行编译的程序:
            先编译为中间代码,在运行时再动态编译为当前CPU能够执行的目标代码(比如C#开发的.NET程序) – 托管调试
            直接编译和链接成目标代码的程序(C/C++) – 本地调试
            兼具以上两种的 – 混合调试
  • 按目标代码的执行模式分:用户态调试(User Mode Debugging)、内核态调试(Kernel Mode Debugging);
    在Windows这样的多任务操作系统中,作为保证安全和秩序的一个根本措施,系统定义了两种执行模式,即低特权等级的用户模式(User Mode)和高特权等级的内核模式(Kernel Mode)。
    应用程序代码是运行在用户模式下的,操作系统的内核、执行体和大多数设备驱动程序是运行在内核模式的。
  • 按软件所处的阶段分:开发期调试、产品期调试(分界线是产品的正式发布)
  • 按调试器和调试目标的相对位置分:本机提哦啊哈斯、远程调试
  • 按调试目标的活动性分:活动目标调试、转储文件调试   

根据软件代码规模,应用软件的开发大致分为三 种模式。

程序员个人开发的小软件

用例图

这种模式和早期的软件开发模式类似。 小软件开发用例图如图所示。

 

 

软件调试的特点

发现问题(测试)、定位问题和提出解决问题方 案、修改程序代码、验证全部由程序员负责。

软件调试 可以分为静态调试与动态调试。

1、静态调试。 源程序代码编译时同时对源代码进行静态检查, 编译器提供了源代码各种编程错误和错误所在的位 置。 静态调试就是程序员逐条修改编译器提示的错 误,通过代码编译这一关。

2、动态调试。 动态调试分为查错和纠错。 查错就是对程序进行 功能性能测试,查找各种不符合设计要求的各种问题; 纠错就是根据发现的问题,查找原因,修改程序源代 码。 这里的软件调试工作包括软件测试。 动态调试通 常采用以下两种方式:

  • 仔细分析发现的问题,通过推理来查找发生 问题的原因。 程序员对程序的架构设计、编码实现十 分熟悉,往往能比较快地定位和处理问题。 这种方式 通常具有全局观念,可以避免解决问题过程中诱导出 现其他问题。
  • 通过调试工具采用人机交互方式调试代码。 这种方式是逐条执行和跟踪程序代码,观察各种状态 和变量的变化,检查是否符合程序设计的要求来定位 问题。 这种方式有助于查找程序代码的微观错误,要 求程序员对程序代码的实现十分熟悉。 这两种方式是互补的,综合应用调试程序代码。

3、版本管理。 版本管理通常采用小型软件配置管理工具VSS, 也可采用文件存储的方式

程序组软件开发

这种模式与软件开发中期的开发模式类似。 通常 软件分为多个软件模块,每个程序员仅负责自己开发 的软件模块。 这种开发模式通常用于中、小型软件的 开发。

角色和用例图

软件设计人员:负责软件设计,提供设计规格 文档。

程序开发组:程序代码编写和程序调试,负责软件 的版本管理和集成构建。

测试人员:负责软件功能、性能测试。 程序组开发的软件用例图如图所示

 

 

软件调试的特点

1、软件的设计工作和大部分测试工作从程序组 工作中分离出去。 设计人员负责软件设计,程序员负 责程序代码的实现,定位问题和提出解决问题方案往 往由设计人员和程序组共同合作处理,程序员负责软 件纠错(程序代码修改),测试人员负责测试工作。

2、调试分为两个阶段:

(1)、开发组自己测试软件。 程序员完成程序源代码的编写,程序代码的静态 检查,使用调试工具对程序代码进行功能点的调试。 所有的功能点都调试完成后,通过组内代码评审之后, 将源代码合入版本库。 开发组组长指定某个程序员负责程序代码的集成 构建,编译过程中发现的问题,反馈给相关的程序员进 行处理。 源代码完成集成构建之后,打包提交给测试 人员测试。

(2)、测试人员测试软件。 测试人员根据设计规格文档设计测试用例,测试 提交过来的软件包。 测试人员发现的各种问题反馈给 程序开发组进行软件调试处理。 程序开发组和设计人 员确定发生问题的原因,确定修改方案,分配给相关的 程序员进行代码纠错处理。 对于比较复杂的问题,软 件设计人员需要提供实现编码的设计文档。 程序代码修改后,进行验证和确认。

3、版本管理通常采用软件配置管理工具 SVN。 通过版本管理工具对程序员提交的代码进行冲突检 查,通过调试处理保证代码的兼容性和一致性。

项目组开发的软件

软件通常由多个模块组成,每个模块由若干开发 单元组成。 开发单元分配给程序员编写程序代码。 这 种开发模式通常用于大型软件的开发。

角色和用例图

1、软件设计组:提供总体和各模块的设计规格 文档。

2、软件开发组:按模块分为开发小组,开发小组 将开发单元分配给程序员进行程序编码。

3、软件配置管理员:负责基线和版本库的管理。

4、持续集成工程师:负责软件的持续集成工作,搭建的集成构建工程,通过制定定时任务来自动 完成从版本库更新代码、静态检查、编译、出包、冒烟测 试等任务。 冒烟测试也称为预测试,对集成构建成功 的软件包的主要功能进行快速自动化测试。 构建成 功,可以获得最新Build版本,建立新的编码基线。 持 续集成工程师进行全量构建生成内部转测试版本,提 交测试组进行的测试工作。

5、软件测试组:对软件转测试版本进行功能、性 能测试,通过后产生测试(Tested)基线。 为持续集成 工作提供进行冒烟测试的自动化测试用例脚本包,搭 建相应的测试环境。 项目组开发软件(通常为大型软件)用例图如图 所示。

 

软件调试的特点

1、软件设计人员和软件测试人员增加了,有的软 件项目测试人员比开发人员还要多。 软件测试不仅要 发现程序编码中的问题,而且测试软件设计中的问题。 设计中的问题自然由设计人员处理,程序编码中的问 题由设计人员和开发人员共同处理。

2、软件的版本管理和集成构建工作由专人负责,实行基线和版本库的管理。 基线管理[13-14]为全体开 发人员提供统一的开发基点,统一的程序接口。 通过 控制集成构建的频率,有助于及时发现程序代码问题。

3、软件调试分为三个阶段:

(1)、开发人员调试自己开发软件单元。 程序开发人员每天从版本库检出需要的文件,放 在本地作为工作副本开始工作。 在工作副本上进行查 看、修改、编译、运行、调试等操作。 为了提供高质量的 代码,需要对编写好的代码进行单元测试,静态走码检 查,冲突处理和本地构建工作,处理发现的各种问题。 最后将评审过的代码提交到版本库。 开发人员向版本 库提交时,要添加注释、说明、CR单号、修改原因等,以 保证可追溯。

(2)、处理持续集成工程师发现的问题。 通常持续集成工作包括静态测试、编译、链接和冒 烟测试,每一步发现问题都要反馈给相关开发人员处 理,直到通过集成构建。

(3)、处理测试组发现的问题。 测试组测试转测试版本,将测试结果反馈给相关 人员,对存在的问题逐一定位,查找原因,修改程序,对 每个软件缺陷问题进行跟踪管理,直到问题解决为止。

4、设计人员和程序员共同处理反馈的各种问题, 定位问题和提出解决问题方案。 程序员负责程序代码 修改,测试人员负责验证和确认工作。

5、版本管理可以选择SVN、ClearCase、Git等软件 配置管理工具。 通过版本管理工具进行软件的版本管 理、基线管理和代码冲突检查。

6、软件开发过程中采用持续集成和基线管理技 术,可以更有效地进行开发和调试工作。

在日常工作中,我们还是有些原则要坚守,也有些策略可用:

1、调试的本质:确认原则

修正充满错误的程序,就是逐个确认,你自认为正确的许多事情所对应的代码确实是正确的。当你发现其中某个假设不成立时,就表示已经找到了关于程序错误的位置的线索了,可能并不时准确的位置。

换一种表达方式来说:惊讶是好事。当你认为关于程序的某件事情是正确的,而在确认它的过程中却失败了,你就会感到惊讶,但这是好事,因为这种发现会引导你找到程序错误所在的位置。

2、熟悉软件设计和编码

让熟悉软件设计和编码的人参与调试工作,修改 错误也是程序设计的一种形式。 在程序设计阶段使用 的方法都可以应用到程序错误的修正工作中。

3、从简单工作开始调试

在调试过程的开始阶段,应该从容易、简单的情况开始运行程序。这样做也许无法揭示所有程序错误,但是很有可能发现其中的部分错误。例如,如果代码由大型循环组成,则最容易发现程序错误的是在第一次或第二次迭代期间引发错误。又比如多线程程序改为单线程或减少几个线程。

4、从软件模块的最小集成包开始

在增量式软件开发过程中,软件模块最初的起始 可能是一个最低功能限度的集成包,随后新的代码不 断加入到系统中。 调试工作可以从最小的集成包开 始,不断增加代码和模块来查找、定位问题。

5、分而治之

每次只处理一个问题,把被调试组件从其上下文 组件之中孤立出来,通过设计驱动模块和桩模块进行 调试。

6、发现问题及时反馈和处理

检测到的错误越早,就越容易找到原因。 如果等 到问题症状出现在客户端接口,那么可能很难缩小发 生问题的原因列表。

7、兼顾全局

程序代码错误修改兼顾全局,确保修改错误没有 影响软件的其他部分。

8、彻底修改

如果提出的修改方案不能解释与该错误有关的全 部线索,那就表明只修改了错误的一部分,必须对错误 进行彻底修改。

9、关注相关问题

在查找问题根源时,对可能发现的一些相关问题 也要做处理。 暂时不能处理的相关问题应该记录在案,为以后的调试工作保留相关信息。】

10、自顶向下的方法

通常采用自顶向下或模块化方法来编写代码。 采 用自顶向下或模块化的方法来调试代码,可以缩小软件问题定位的范围,提高调试效率。