首页 > 编程语言 >C++ - 崩溃定位用dump和pdb文件

C++ - 崩溃定位用dump和pdb文件

时间:2023-05-11 10:22:05浏览次数:33  
标签:文件 exe dump C++ CCreateDump pdb 调试

目的

利用dump和pdb文件来快速定位程序崩溃的地方

步骤

1、写一个简单的崩溃程序
sample.cpp

 1 class Test{
 2 public:
 3     void say(){
 4         int a = 0;
 5         int b = 10 / a;
 6     }
 7 };
 8 
 9 int _tmain(int argc, _TCHAR* argv[])
10 {
11     Test t;
12     t.say();
13 
14     return 0;
15 }

int b=10/a这句代码会导致程序崩溃。

2、dump文件生成相关配置

添加两个文件。
CCreateDump.h

 1 #pragma once
 2 #include <string>
 3 
 4 using namespace std;
 5 class CCreateDump
 6 {
 7 public:
 8     CCreateDump();
 9     ~CCreateDump(void);
10     static CCreateDump* Instance();
11     static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
12     //声明Dump文件,异常时会自动生成。会自动加入.dmp文件名后缀
13     void DeclarDumpFile(std::string dmpFileName = "");
14 private:
15     static std::string    strDumpFile;
16     static CCreateDump*    __instance;
17 };

CCreateDump.cpp

 1 #include "stdafx.h"
 2 #include <Windows.h>
 3 #include "CCreateDump.h"
 4 #include <DbgHelp.h>
 5 #pragma comment(lib,  "dbghelp.lib")
 6 
 7 CCreateDump* CCreateDump::__instance = NULL;
 8 std::string CCreateDump::strDumpFile = "";
 9 
10 CCreateDump::CCreateDump()
11 { 
12 }
13 
14 CCreateDump::~CCreateDump(void)
15 {
16 
17 }
18 
19 long  CCreateDump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo)
20 {
21     HANDLE hFile = CreateFile(strDumpFile.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
22     if (hFile != INVALID_HANDLE_VALUE)
23     {
24         MINIDUMP_EXCEPTION_INFORMATION   ExInfo;
25         ExInfo.ThreadId = ::GetCurrentThreadId();
26         ExInfo.ExceptionPointers = ExceptionInfo;
27         ExInfo.ClientPointers = FALSE;
28         //   write   the   dump
29         BOOL   bOK = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
30         CloseHandle(hFile);
31         if (!bOK)
32         {
33             DWORD dw = GetLastError();
34             //写dump文件出错处理,异常交给windows处理
35             return EXCEPTION_CONTINUE_SEARCH;
36         }
37         else
38         {    //在异常处结束
39             return EXCEPTION_EXECUTE_HANDLER;
40         }
41     }
42     else
43     {
44         return EXCEPTION_CONTINUE_SEARCH;
45     }
46 }
47 
48 void CCreateDump::DeclarDumpFile(std::string dmpFileName)
49 {
50     SYSTEMTIME syt;
51     GetLocalTime(&syt);
52     char c[MAX_PATH];
53     sprintf_s(c, MAX_PATH, "[%04d-%02d-%02d %02d:%02d:%02d]", syt.wYear, syt.wMonth, syt.wDay, syt.wHour, syt.wMinute, syt.wSecond);
54     strDumpFile = std::string(c);
55     if (!dmpFileName.empty())
56     {
57         strDumpFile += dmpFileName;
58     }
59     strDumpFile += std::string(".dmp");
60     SetUnhandledExceptionFilter(UnhandleExceptionFilter);
61 }
62 
63 CCreateDump* CCreateDump::Instance()
64 {
65     if (__instance == NULL)
66     {
67         __instance = new CCreateDump;
68     }
69     return __instance;
70 }

在sample.cpp添加一句

1 int _tmain(int argc, _TCHAR* argv[])
2 {
3     CCreateDump::Instance()->DeclarDumpFile("dumpfile");//新加代码
4     Test t;
5     t.say();
6 
7     return 0;
8 }

3、pdb文件生成相关配置

对项目属性进行配置:
属性–》链接器-》调试–》生成调试信息–》是

4、生成dump和pdb文件

对项目进行编译生成sample.exe文件,可以同时生成了sample.pdb文件。

双击运行.exe程序,程序一闪而过,崩溃了,同时生成了dump文件。

调试 方式一

1、用vs打开dump文件,点击使用本机进行调试。

可以发现自动定位到崩溃的代码了。

当然这是最理想的状态。工程项目的目录结构跟生成pdb文件的时候一样没发生改变,不需要设置源码的路径,直接把exe、pdb、dump文件放到同一个文件夹下就行了,因为pdb文件中保存了源代码的绝对路径。否则需要手动添加源码路径,然后在进行本机调试。
属性-》调试源文件

当然也可以不管,直接本机调试,根据调用堆栈也能知道是哪句代码出问题,只是看不到具体代码。

2、注意

前面的部分有个大前提,就是得保证exe、dump和pdb文件的一致性,就是说exe和pdb都是由一份代码在同一时间生成的,而dump又是由这个exe生成的。这三个文件有GUID的效验码,假如不一致的话就会没法定位。代码稍微改动了没关系,只是定位会不是很准确。这个GUID貌似是跟时间戳相关的,就算代码没变,重新生成了的话也会改变GUID。

可以用dumpbin查看guid。打开VS2013 开发人员命令提示,输入

dumpbin /headers D:\opgl\sample\Debug\sample.exe

这部分就是GUID

前面还有一段,这是时间戳信息,也就是生成exe的时间,可以用它来找相应的代码。

调试 方式二

1、用Windbg定位

据说:Windbg是一款功能十分强大的调试工具,它设计了极其丰富的功能来支持各种调试任务,包括用户态调试、内核态调试、调试转储文件、远程调试等等。

2、设置pdb文件路径

file-》Symbol Search Path。我的pdb是放在这个路径下。

3、设置源码位置

file-》Source Search Path

4、打开dump文件

把dump文件直接拖进去。

输入自动分析命令
!analyze -v

此时左边变成了BUSY,就是在工作中,等它变回去就结束了。

5、分析结果关键部分是这个

STACK_TEXT表示堆栈信息,后面表示崩溃的代码。
不输入源代码路径的话它就会自动读取pdb中的源码路径,假如找不到的话就没后面部分,只能知道哪个函数出错了。

6、我用的Windbg是这个
链接:https://pan.baidu.com/s/1eNMibUvA1xgIgM6GIM9ePA
提取码:z221

外面的windbg是汉化版,但用起来有问题,我用的是x64里面的。

 

标签:文件,exe,dump,C++,CCreateDump,pdb,调试
From: https://www.cnblogs.com/citrus/p/17390280.html

相关文章

  • 真机调试可以正常安装,但是不能正常运行,出现错误:couldn‘t find “libc++_shared.so“
    在迁移代码的时候,发现代码可以在模拟器上运行,但是无法在真机上面运行,最后经过挨个的排查,最终发现是ndk的问题。在app的build.gradle中的ndk缺少了匹配的实体机类型,然后加了一下'x86','armeabi-v7a','armeabi','armabi-v7a','x86_64','arm64-v8a','mips','mips64......
  • 总结:C++引用(Reference)
    声明:资料整理自网络资源,未能全部注明引用来源,如有侵权请联系。一、基本概念引用(Reference)是C++相对于C语言的又一个扩充。引用变量是一个别名,即某个已存在变量的另一个名字。声明方法:类型标识符&引用名=目标变量名;inta;//定义变量aint&b=a;//定义引用b,a和b表......
  • 编程打卡:C++语言程序设计
    //Node.h#ifndefNODE_H#defineNODE_H//类模板的定义template<classT>classNode{private: Node<T>*next; //指向后继结点的指针public: Tdata; //数据域 Node(constT&data,Node<T>*next=0);//构造函数 voidinsertAfter(Node<T>*p); //......
  • c++打卡训练
    自守数(半成品,指没写出来,双倍给明天)流程图:伪代码:源代码:#include<iostream>usingnamespacestd;intmain(){ longinti,m; intj,n,k,a=1; for(i=0;i<=100000;i++){ n=i; m=i*i; for(j=0;n=0;j++){ n/=10; for(k=j;k>=0;k--){ a=a+a*10; if(m%a==i){ printf......
  • C++
    学生类的析构与构造#include<iostream>#include<string.h>usingnamespacestd;classStudent{public:Student(int_num,string_name,char_sex){num=_num;name=_name;sex=_sex;cout<<"Constructorcalled."......
  • C++ 类和对象: 初始化列表
    1.回顾构造函数构造函数是6个默认的成员函数之一,完成对象初始化的工作而在构造函数中,有两种初始化对象的方式,初始化列表和函数体内赋值首先来回顾一下用函数体内赋值方法进行初始化#include<iostream>usingnamespacestd;classDate{public: Date(intyear=1,......
  • C++ return std::move(obj)的效率问题
    在visualstudio2022x32release模式下测得 直接看图即可,可以看出returnstd::move反而会降低性能,而直接返回obj则与直接构造无任何差异。这其实不符合我们对直接返回对象的直觉理解,不过这个和编译器的优化相关,可以详细搜索RVO和NRVO的相关内容。......
  • C++MFC数据库程序设计[2023-05-10]
    C++MFC数据库程序设计[2023-05-10]项目必须使用面向对象程序设计的方法来完成,项目中涉及的数据存取必须由数据库完成,同时程序必须有UI(图形或菜单均可)界面,必须完成数据录入、修改、删除、插入、浏览、查询和排序等功能。是否使用MFC中的对话框、单文档等,由同学们自行决定。即......
  • C++ 类和对象: const关键字
    1.const关键字在C语言中,const关键字用来修饰变量,表示变量的值不能被修改在C++中,const可以修饰变量,也可以用来修饰对象和类成员变量下面先来看一下,const修饰对象使用const修饰的对象d1,调用成员函数报错,这是为什么?那么只要把this指针类型改为constDate*,......
  • C++ Primer学习笔记——第二章
    第二章变量和基本类型前言数据类型是程序的基础:它告诉我们数据的意义以及我们能在数据上执行的操作。2.1基本内置类型C++定义了包括算术类型(arithmetictype)和空类型(void)在内的基本数据类型。2.1.1算术类型算术类型分为两类:整型和浮点型。具体分类:类型含义最小容......