使用WinDbg进行动态调试

前言

  • 本文章主要介绍如何使用WinDbg进行动态调试。如果程序崩溃后,没有记录dump文件,或者程序启动时发生异常,比如常见的 应用程序无法正常启动(0xc000007b) 报错,都可以使用WinDbg动态调试功能来定位问题。文章最后,对WinDbg常用命令进行了总结。
  • 对WinDbg不熟悉的可以参考我的另一篇WinDbg入门教程 WinDgb安装和使用

什么时候使用WinDbg进行动态调试

  • 程序崩溃后没有生成dump文件
  • 使用visual studio调试时发生异常,看不到完整的调用堆栈
  • 程序启动时发生异常错误,比如比较常见的 应用程序无法正常启动(0xc000007b)

WinDbg动态调试步骤

  • 测试程序
    •   #include <windows.h>
        #include <stdio.h>
        
        void myfunc() {
              
              
        	printf("join to myfunc...\n");
        
        	//这里程序会崩溃
        	char* p = NULL;
        	memcpy(p, "hello word", strlen("hello word"));
        
        	printf("end myfunc");
        }
        
        void myMath(int a, int b) {
              
              
        	int sum = 0;
        	sum = a + b;
        	printf("sum = %d\n", sum);
        
        	myfunc();
        
        	int minus = 0;
        	minus = a - b;
        	printf("sum = %d\n", sum);
        }
        
        int main() {
              
              
        
        	myMath(10, 20);
        	system("pause");
        	return 0;
        }
      
  • 使用WinDbg动态调试程序
    • 先启动我们的程序,打开WinDbg,选择File->Attach to a Process,然后选择要调试的目标进程。这里会看到当前运行的所有进程,选择你要调试的进程即可。
      在这里插入图片描述

    • 如果要调试程序无法正常启动,或者说启动后会直接退出,那么也可以直接使用WinDbg打开程序进行调试,选择 File->Open Executable,选择要调试的程序打开即可。

    • 运行后默认会终端,在命令行输入g命令,可以继续运行
      在这里插入图片描述
      在这里插入图片描述

    • 通过上面测试程序可以知道,程序运行后会崩溃,从调试信息可以看到,发生Access violation,即内存访问违规。

    • 使用kn命令,可以看到具体的堆栈信息,并且打印了的行号。
      在这里插入图片描述

    • 如果这里的堆栈没有函数和行号信息,是因为没有加载pdb文件,选择File->Symbol File Path将pdb所在目录添加进去即可。

    • 使用lm命令可以查看pdb文件是否加载上了,使用lm vm 模块名可以看到更详细的信息。如果pdb文件的完整路径打印出来了,说明加载成功了。
      在这里插入图片描述
      在这里插入图片描述

    • 如果pdb文件加载失败,第一个原因就是可执行程序和pdb文件不一致,也就是说可执行程序可能改过代码了,但pdb文件还是之前的。还有一个原因就是可执行程序和pdb文件时间戳不一致,也就是说代码是一致的,但可执行程序生成时间和pdb生成时间不一致。如果还有其他问题导致pdb文件加载失败,可以使用 .reload /f 可执行程序名 强制加载pdb文件。

    • 可以通过 File->Source File Path将源代码路径设置进行,就可以在WinDbg中使用源代码调试了
      在这里插入图片描述

    • 那么相比于使用Visual Studio调试,WinDbg有什么好处呢。比如我们写完程序,放到客户电脑上,程序运行异常了,从日志和dump文件都分析不出问题,而且开发机还复现不了问题。这个时候就只能在客户电脑上调试了。那如果使用Visual Studio调试,我们不仅要去搭建环境,而且还要将代码拷贝到客户电脑上,实际场景肯定是不现实的。这个时候就可以使用WinDbg来进行调试了,只需要在客户电脑上安装一个WinDbg,并把对应程序的pdb文件拷贝过去,就可以现场进行调试了。

通过WinDbg导出dump文件

  • 如果程序崩溃了,但我们程序又没有记录dump文件的功能,可以通过 .dump /ma dump文件名 命令将dump文件导出,事后进行分析。
    在这里插入图片描述

应用程序无法正常启动(0xc000007b)分析

  • 这种报错一般是由于可执行程序的依赖库位数不匹配导致的,比如我这个可执行程序依赖的vcruntime140d.dll是64位,我打包发布的时候,拷了一个32位的库进去,运行时就会报这个错误。
    在这里插入图片描述
    在这里插入图片描述
  • 那实际项目中,可执行程序依赖的库是很多的,我们不知道哪一个依赖库出现了问题,就可以使用WinDbg来进行动态调试。
    在这里插入图片描述
  • 使用WinDbg调试时可以看到,加载vcruntime140d.dll时出现了错误,这样我们就能准确定位到是哪个依赖库出问题了。

WinDbg常用命令

  • g
    • 跳过当前中断,继续运行
  • .ecxr
    • 切换到发生异常的线程中。如果是动态调试,会直接切换到异常的线程中,因此不需要执行此命令。
  • kn/kv/kp
    • 查看当前线程的函数调用堆栈
  • lm
    • 查看二exe或者二进制文件的信息,lm vm fileDump 可以查看fileDump模块的详细信息。
  • .reload
    • 加载pdb文件,比如 .reload /f fileDump.exe , 强制加载 fileDump.exe的pdb文件
  • ~
    • 查看当前进程所有线程信息
  • ~ns
    • 切换到n号线程中
  • !analyze
    • 详细分析当前异常,完整命令为 !analyze -v
  • .dump
    • 导出dump文件,比如 .dump /ma F:\0001.dmp
  • bp/bl/bc
    • bp : 添加断点,比如 bp fileDump!main,给fileDump模块中的main函数设置断点
    • bl : 列出当前所有断点
    • bc : 清除断点
  • r
    • 查看当前线程所有寄存器的值
  • .cls
    • 清屏
  • .effmach
    • 切换当前进程的上下文

猜你喜欢

转载自blog.csdn.net/new9232/article/details/132774219