一般程序崩溃可以通过debug,找到程序在那一行代码崩溃了,最近编一个多线程的程序,都不知道在那发生错误,多线程并发,又不好单行调试,终于找到一个比较好的方法来找原因,通过生成map文件,由于2005取消map文件生成行号信息(vc6.0下是可以生成行号信息的,不知道microsoft怎么想的,在2005上取消了),只能定位在那个函数发生崩溃。这里可以通过生成cod文件,即机器码这一文件,具体定位在那一行崩溃。
1 . 首先配置vc2005生成map文件和cod文件:
(1).map文件:property->Configuration Properties->Linker->Debugging 中的Generate Map File选择Yes(/MAP);
(2).cod文件:property->Configuration Properties->C/C++->output Files中Assembler OutPut中选择Assembly,Maching Code and Source(/FAcs),生成机器,源代码。
2.生成测试代码
创建一个默认的对话框文档,添加一个按钮的单击事件:
void CTESTDlg::OnBnClickedButton1()
{
AfxGetApp()->GetMainWnd()->SetWindowText(_T("Crash")); //乱七八糟的代码,主要是为后面异常提供一个偏移量
int* pTest = NULL;
*pTest = 0; // 为空指针赋值,程序将崩溃
}
在release下运行代码,点击,跳出错误对话框: 提示内存 0x0040146f错误,该内存....你懂的
3. 阅读map文件:
3.1 Preferred load address is 00400000 //虚地址,实际的错误地址是0x0040146f - 00400000 = 146f;
偏移地址(Rva)+ 基地址(Base) 比如:
0001:00000440 ?OnQueryDragIcon@CTESTDlg@@IAEPAUHICON__@@XZ 00401440 f TESTDlg.obj
0001:00000450 ?OnBnClickedButton1@CTESTDlg@@QAEXXZ 00401450 f TESTDlg.obj
0001:00000480 ?Create@CDialog@@UAEHIPAVCWnd@@@Z 00401480 f i TESTDlg.obj
3.2 推理出出错函数
00401450 f 中的 0040就是高位, 1450就是低位,高位就不参与计算了,主要是对比低位, 注意后面变态的f,大家都认为是16进制的f,其实别管他,老子也不知道是哪请来的临时演员。
这里的 1450 < 146f <1480,所以错误时产生在函数OnBnClickedButton1中的。 到这里,你已经成功一半了,哈哈
4.定位到具体的代码行
因为上面的错误函数在TESTDlg.obj里,也就是在TESTDLG.cpp中,我们打开它的 .cod文件
用146f - 1450 = 1f (注意是16进制的计算, 如果找不到xp的计算器可在路径C:\WINDOWS\system32\dllcache\calc.exe 下找);
然后在 .cod文件里的0001f 89 00处找到 157行代码 *pTest = 0; // 为空指针赋值,程序将崩溃
; 156 : int* pTest = NULL;
0001d 33 c0 xor eax, eax
; 157 : *pTest = 0; // 为空指针赋值,程序将崩溃
0001f 89 00 mov DWORD PTR [eax], eax
; 158 : }
00021 c3 ret 0
有时候错误可能没有这么明显,需要自己上下文判断一下。
Linux下Debug版本定位崩溃代码行:
ulimit -c unlimited
echo "/opt/kdm/pui/core-%e-%p" > /proc/sys/kernel/core_pattern
gcc -o main -g a.c
gdb main /opt/kdm/pui/core-main-10815