第Ⅰ部分 调试概述
第1章 错误来源和除错方法
1.1 错误及其调试
1.1.1 什么是错误
1.1.2 错误产生的原因和解决办法
1.1.3 规划调试
1.2 优秀调试人员的必备技能
1.2.1 所需技能
1.2.2 学习各种技能
1.3 调试过程
1.3.1 步骤1:重现错误
1.3.2 步骤2:描述错误
1.3.3 步骤3:总是假设是您自己造成的错误
1.3.4 步骤4:分而治之
1.3.5 步骤5:创造性地思考
1.3.6 步骤6:借助于工具
1.3.7 步骤7:开始大规模调试
1.3.8 步骤8:验证错误已经被更正
1.3.9 步骤9:学习和与人分享
1.3.10 调试过程的最终秘密
1.3.11 本章小结
第2章 开始调试
2.1 跟踪所有更改直至项目完成
2.1.1 版本控制系统
2.1.2 错误跟踪系统
2.1.3 选择适当的系统
2.2 在进度表中安排时间建立调试系统
2.2.1 保证所有版本中都带调试符号
2.2.2 把托管代码中的编译警告视为编译错误
2.2.3 对于本机代码将大多数编译警告视为编译错误
2.2.4 了解本机代码中DLL的加载位置
2.2.5 如何处理托管模块及其基址
2.2.6 为发布版本设计轻量级的诊断系统
2.3 必须进行频繁生成和冒烟测试
2.3.1 频繁生成
2.3.2 冒烟测试
2.4 尽早创建安装程序
2.5 QA必须测试调试版本
2.6 安装操作系统调试符号并建立符号库
2.7 本章小结
第3章 边编码边调试
3.1 断言
3.1.1 如何断言以及断言什么
3.1.2 在.NET Windows窗体或控制台应用程序中设置断言
3.1.3 在ASP.NET程序和XML Web服务中设置断言
3.1.4 在本机C++程序中设置断言
3.1.5 Visual C++中不同类型的断言
3.1.6 SUPERASSERT
3.2 跟踪、跟踪、再跟踪
3.2.1 在Windows窗体应用和控制台.NET应用程序中跟踪
3.2.2 在ASP.NET应用程序和XML WEB Services中跟踪
3.2.3 在本机C++应用程序中跟踪
3.3 注释、注释、再注释
3.4 信任自己,但要进行验证(单元测试)
3.5 本章小结
第Ⅱ部分 强大的调试技术
第4章 操作系统对调试的支持以及Win32调试器工作原理
4.1 Windows调试器的类型
4.1.1 用户模式调试器
4.1.2 内核模式调试器
4.2 Windows操作系统对调试对象的支持
4.2.1 实时(JIT)调试
4.2.2 在调试器中自动启动(映像文件执行选项)
4.3 MinDBG:一个简单的Win32调试器
4.4 WDBG:真正的调试器
4.4.1 读/写内存
4.4.2 断点和单步执行
4.4.3 符号表、符号引擎和堆栈遍历
4.4.4 Step Into、Step Over和Step Out
4.5 编写您自己的调试器
4.6 对WDBG的改进建议
4.7 本章小结
第5章 Visual Studio.NET调试器高级用法
5.1 高级断点及其用法
5.1.1 断点设置技巧
5.1.2 在任何函数位置快速中断
5.1.3 位置断点智能特性
5.2 Watch窗口
5.2.1 在Watch窗口中调用方法
5.2.2 Set Next Statement命令
5.3 本章小结
第6章 Visual Studio.NET高级.NET调试
6.1 .NET程序中的高级断点
6.1.1 条件表达式
6.2 Watch窗口
6.2.1 自动展开自定义类型
6.3 提示与技巧
6.3.1 DebuggerStepThroughAttribute和DebuggerHiddenAttribute
6.3.2 混合模式调试
6.3.3 远程调试
6.4 ILDASM和Microsoft中间语言
6.4.1 开始学习ILDASM
6.4.2 公共语言运行库(CLR)
6.4.3 MSIL、局部变量和参数
6.4.4 重要指令
6.5 其他逆向工程工具
6.6 本章小结
第7章 Visual Studio.NET本机代码高级调试技术
7.1 本机应用程序的高级断点
7.1.1 高级断点语法
7.1.2 系统或导出函数的断点
7.1.3 条件表达式
7.1.4 数据断点
7.1.5 更好的数据断点
7.2 Watch窗口
7.2.1 数据的格式化和表达式的计算
7.2.2 在Watch窗口中记录代码执行时间
7.2.3 未归档的伪寄存器
7.2.4 自动展开自己的类型
7.3 远程调试
7.4 提示与技巧
7.4.1 调试插入的代码
7.4.2 Memory窗口和自动内存计算
7.4.3 监视异常
7.4.4 处理符号的更多技巧
7.4.5 与Windows 2000进程分离
7.4.6 处理转储文件
7.5 x86汇编语言
7.5.1 CPU基础
7.5.2 浅谈Visual C++.NET内联汇编器
7.5.3 您需要了解的指令
7.5.4 通用序列:函数的入口和出口
7.5.5 调用过程和返回
7.5.6 调用约定
7.5.7 变量访问;全局变量、参数和局部变量
7.5.8 更多需要了解的指令
7.5.9 字符串操作
7.5.10 常见的汇编语言结构
7.5.11 结构引用和类引用
7.5.12 完整的示例
7.5.13 Disassembly窗口
7.5.14 手动查看堆栈
7.5.15 提示与技巧
7.6 本章小结
第8章 WinDBG的高级本机代码调试技术
8.1 要点回顾
8.2 基础知识
8.3 调试环境
8.3.1 获得帮助信息
8.3.2 确保加载了正确的符号
8.3.3 进程和线程
8.4 使用Command窗口进行普通调试
8.4.1 查看和计算变量
8.4.2 执行、步进和跟踪
8.4.3 断点
8.4.4 异常和事件
8.4.5 控制WinDBG
8.5 神奇的扩展命令
8.5.1 加载和控制扩展
8.5.2 重要的扩展命令
8.6 处理转储文件
8.6.1 创建转储文件
8.6.2 打开转储文件
8.6.3 调试转储文件
8.7 Son of Strike(SOS)扩展
8.7.1 使用SOS
8.8 本章小结
第Ⅲ部分 .NET的强大调试工具和技术
第9章 扩展Visual Studio .NET IDE
9.1 使用宏进行扩展
9.1.1 宏的参数
9.1.2 与项目有关的问题
9.1.3 代码元素
9.2 CommenTater:能解决共同面临的棘手问题吗?
9.3 外接程序简介
9.3.1 修改外接程序向导生成的代码
9.3.2 处理工具栏按钮问题
9.3.3 创建工具窗口
9.3.4 使用托管代码创建选项属性页
9.4 SuperSaver外接程序
9.5 SettingsMaster外接程序
9.5.1 SettingsMaster的实现要点
9.5.2 对SettingsMaster的改进建议
9.6 本章小结
第10章 托管异常的监视
10.1 Profiling API简介
10.1.1 启动您的分析器
10.2 ProfilerLib
10.3 ExceptionMon
10.3.1 进程内调试与ExceptionMon
10.4 .NET中异常的使用
10.5 本章小结
第11章 流程跟踪
11.1 在Profiling API中钩挂函数
11.1.1 请求Enter和Leave通知
11.1.2 实现钩子函数
11.1.3 内联
11.1.4 FunctionIDMapper函数
11.2 使用FlowTrace
11.3 FlowTrace实现中的主要问题
11.4 对FlowTrace的改进建议
11.5 本章小结
第Ⅳ部分 本机代码的强大调试工具和技术
第12章 通过崩溃时返回的地址找到源文件和行信息
12.1 创建和读取MAP文件
12.1.1 MAP文件内容
12.1.2 寻找源文件、函数名和行号
12.1.3 PDB2MAP——崩溃发生后的Map文件
12.2 使用CrashFinder
12.2.1 实现要点
12.3 对CrashFinder的改进建议
12.4 本章小结
第13章 崩溃处理机制
13.1 结构化异常处理机制和C++异常处理机制
13.1.1 结构化异常处理机制
13.1.2 C++异常处理机制
13.1.3 避免使用C++异常处理
13.1.4 不要使用_set_se_translator
13.2 SetUnhandledExceptionFilter API函数
13.3 使用CrashHandler API函数
13.4 转换EXCEPTION_POINTERS结构
13.5 小型转储(Minidump)
13.5.1 MiniDumpWrite Dump API
13.5.2 关于MiniDumpWrite Dump
13.6 本章小结
第14章 调试Windows服务和加载到服务中的DLL
14.1 服务的基础知识
14.1.1 API要点
14.1.2 安全问题
14.2 调试服务
14.2.1 调试核心代码
14.2.2 调试基本服务
14.3 本章小结
第15章 多线程死锁
15.1 多线程编程提示和技巧
15.1.1 不要使用多线程
15.1.2 不要过多使用多线程
15.1.3 只在很小的离散程序段中使用多线程
15.1.4 在最低级别同步
15.1.5 旋转临界区
15.1.6 不要使用CreateThread/ExitThread
15.1.7 默认的内存管理器可能令程序失败
15.1.8 当场进行转储
15.1.9 检查代码——并再次检查代码
15.1.10 在多处理器机器上进行测试
15.2 DeadlockDetection的要求
15.3 关于DeadlockDetection的高级设计问题
15.4 使用DeadlockDetection
15.5 实现DeadlockDetection
15.5.1 钩挂导入函数
15.5.2 实现要点
15.6 对DeadlockDetection的改进建议
15.7 本章小结
第16章 自动化测试
16.1 单元测试的难点:用户界面
16.2 对Tester的要求
16.3 使用Tester
16.3.1 Tester脚本
16.3.2 记录脚本
16.4 实现Tester
16.4.1 TESTER.DLL通知和回放的实现
16.4.2 实现TESTREC.EXE
16.5 对Tester的改进建议
16.6 本章小结
第17章 调试C运行时库和内存管理
17.1 调试C运行时库的特性
17.2 使用调试C运行时库
17.2.1 DCRT中的缺陷
17.2.2 DCRT函数
17.3 为应用程序选择合适的C运行时库
17.4 使用MemDumperValidator
17.4.1 在C++中使用MemDumperValidator
17.4.2 在C语言中使用MemDumperValidator
17.4.3 深层验证
17.5 实现MemDumperValidator
17.5.1 在C++中初始化和终止
17.5.2 泄漏报告都到哪儿去了?
17.6 使用MemStress
17.6.1 有趣的压力测试问题
17.7 操作系统堆
17.8 发现内存问题的技巧
17.8.1 发现未初始化的内存写入问题
17.8.2 发现内存溢出
17.9 重要开关
17.9.1 运行时检查开关
17.9.2 缓冲区安全检查开关
17.10 本章小结
第18章 FastTrace:用于服务器应用程序的高性能跟踪工具
18.1 基本问题和解决方案
18.2 使用FastTrace
18.2.1 合并跟踪日志文件
18.3 FastTrace的实现
18.4 本章小结
第19章 优化工作集
19.1 工作集调整
19.2 使用SWS
19.2.1 设置SWS编译
19.2.2 使用SWS运行应用程序
19.2.3 生成和使用排序文件
19.3 实现SWS
19.3.1 _penter函数
19.3.2 .SWS文件格式和符号枚举
19.3.3 运行时符号问题和模块调整
19.4 对SWS的改进建议
19.5 本章小结
附录A:阅读Dr.Watson日志