调试发行版程序 (一)
程序员都知道世界上不存在没有 BUG 的程序,那么在一个程序发布后:
1、客户那里报程序崩溃了,你该如何办?
2、服务器上的程序CPU冲的很高,可是却不提供服务了?
3、程序长时间运行后进入一种意想不到的状态,如何定位问题?
上面这些问题就是发行版程序的调试问题,以前使用 SoftICE,进入 Windows 时代后,系统越来越复杂,所以微软在这方面也提供了一些工具,现在使用最多的就是 Windows Debuging Tools 简称 WinDebug,目前提供 X86、X64 和 IA64 三种版本,其中 X64 版本的可以调试 X86 的程序;
WinDebug 下载地址:http://www.microsoft.com/whdc/devtools/debugging/default.mspx
要想调试发行版程序,必须在编译时产生符号;所以在发行版的设置中需要注意
1、在 “C++” 的“常规”选项中“调试信息格式”设置为“程序数据库(/Zi)”
2、在“链接器”的“调试”选项中将“生成调试信息”设置为“是”,并设置PDB文件的路径
在这里需要考虑到一个程序都是有很多的动态库和可执行程序组成,所以输出的PDB最好设定到一个目录中,这样可以避免后面遗忘部分符号文件(PDB)
此时编译出来的程序是发布版程序,本身不包含调试信息,但是其内部会指明调试信息存储在一个编号为多少的什么名称的符号文件中,好到此程序的编译就算完成了,然后是从微软的服务器上下载 WinDebug 程序,并在本机上进行安装,假设安装在 D:\WinDebug\Program 目录中,那么该目录中会出现
1、WinDbg.exe :这是图形化界面的调试的程序,命令行形势的是:CDB.EXE
2、SymStore.exe :这是将符号保存到符号库中的命令行程序,该程序可以用来搭建本地符号库和符号服务器
3、SymChk.exe :这是检查符号文件的命令,也可以从服务器上下载符号,例如从微软的符号服务器上下载操作系统文件的符号
然后将“D:\WinDebug\Program ”添加到系统环境变量“PATH”中,方便以后使用,同时在 D:\WinDebug 目录下面建立
1、Symbols 子目录 : 该目录用来构建本地符号库
2、Publish 子目录 : 该目录用来临时存储发布的程序和符号文件
3、SymPut.bat 批处理文件 :该批处理是为了方便每次发布和在 DailyBuild 脚本中进行调用(关于每日构建的文章很多,此处不再赘述)
@ REM SymPub.bat file
@ ECHO OFF
REM 分析系统的日期和时间并设置对应的变量值
FOR /F "tokens=1,2,3 delims=- " %%i IN ('date /t') DO SET DATE_STR=%%i.%%j.%%k
FOR /F "tokens=1,2 delims=: " %%i IN ('time /t') DO SET TIME_STR=%%i.%%j
REM 构造默认的符号相关信息变量
SET PRODUCT="Default Product Name"
SET VERSION="Ver %DATE_STR% %TIME_STR%"
SET COMMENT="%DATE_STR% %TIME_STR%"
REM 检测参数并设置相应的变量
if NOT $%1 == $ SET PRODUCT=%1
if NOT $%2 == $ SET VERSION=%2
if NOT $%3 == $ SET COMMENT=%3
REM 显示设置信息
ECHO Product : %PRODUCT%
ECHO Version : %VERSION%
ECHO Comment : %COMMENT%
REM 将符号加入符号库中
symstore add /3 /r /f Publish\*.* /s D:\WinDebug\Symbols /t %PRODUCT% /v %VERSION% /C %COMMENT%
ECHO ON
每次编译完发布版程序后,将编译的动态库和可执行程序以及符号文件复制到 Publish 子目录中,然后执行 SymPut 批处理即可将符号导入本地符号库中
另外需要注意的是,如果想在 Symbols 目录中产生三级的目录来对符号文件进行分类管理,需要在 Symbols 目录中建立一个名为 index2.txt 的空文件,这样发布的符号将使用符号文件名称的前两个字母最为一级目录,符号文件的名称作为二级目录,符号文件的编号作为三级目录,如此可对大量的文件进行分级索引,避免Symbols 目录下的子目录过多;此处说明一下符号文件的编号:VC6编译的符号文件其内部编号是编译时间的绝对秒,就是 time 函数返回的32位从1970年1月1日0点开始的秒数,后面加上程序的特征,例如目标机器的类型、程序类型等;VC7.0、7.1、8.0、9.0 编译的符号文件编号是一个 GUID,这可能是为了避免多线程同时编译相同特征的程序引发内部编号冲突;
下面来配置 WinDbg 进行程序的调试,在命令行中输入 WinDbg 启动调试界面,点击“File”菜单的“Symbol File Path”命令,在弹出的对话框中输入 SRV*D:\WinDebug\Symbols*HTTP://msdl.microsoft.com/download/symbols;
然后点击 OK 按钮,这样 WinDbg 就可以使用刚才导入的符号对发行版程序进行调试了;
如果你不能上网,将无法从微软的符号服务器下载系统动态库的符号,可以直接输入 D:\WinDebug\Symbols;这样可以提高符号文件的下载速度
启动你编译的发布版程序,例如 MapSpace.exe ,然后在命令行中输入 WinDbg -pn MapSpace.exe ,WinDbg 启动后直接挂入指定的程序进入调试状态;
到此为止,如果服务器端程序跑到了异常状态,就可以使用 WinDbg 进行调试查看内部的各个线程的状态,如何使用 WinDbg 请参阅 Windbg 的帮助文件;
但是如果程序直接崩溃了,我们该如何扑捉?请参阅《调试发行版程序 (二)》