Windows上使用dump文件调试

news2024/12/23 9:20:02

dump文件

dump文件记录当前程序运行某一时刻的信息,包括内存,线程,线程栈,变量等等,相当于调试程序时运行到某个断点上,把程序运行的信息记录下来。可以通过Windbg打开dump,查看程序运行的变量等,来调试程序。

在Liunx上也有类似的技术,Coredump,具体可以参考:coredump详解_coredump文件分析_贺二公子的博客-CSDN博客

dump 文件分类

dump可以分为 minidump 和 Full dump

minidump通常只包含了一些关键信息,一般比较小,通常只要几MB,

Full dump包含了程序运行时的所有信息,包括程序的所有内存,一般有几十MB到几GB。

minidump虽然只包含了部分信息,但这些信息大部分情况足够用于调试,所以大部分情况都是使用minidump调试

生成dump文件

通过任务管理器导出

在进程上右击->创建内存转储文件,这样创建的是Full dump

通过Process Explorer导出

Process Explorer - Sysinternals | Microsoft Learn

选择对应的进程->Process->Create Dump,然后选择要创建minidum 还是 Full Dump

使用MiniDumpWriteDump函数序生成 

#include <iostream>
#include <Windows.h>
#include <Dbghelp.h>
#include <thread>
#pragma comment(lib, "Dbghelp.lib")

void createMinidump()
{
    wchar_t DumpPath[MAX_PATH] = {0};

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[256] = {0};
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth,
              SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

    if (file != INVALID_HANDLE_VALUE)
    {
        DWORD Flags = MiniDumpWithHandleData |
                      MiniDumpWithUnloadedModules |
                      MiniDumpScanMemory|
                      MiniDumpWithIndirectlyReferencedMemory |
                      MiniDumpWithProcessThreadData |
                      MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD) GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE) (Flags),
                              nullptr, nullptr, nullptr) != 0)
        {
            std::cout << "Create Minidump successful!! file:";
            std::wcout << DumpPath << std::endl;
        }
        else
        {
            std::cout << "Create Minidump failed!!" << std::endl;
        }
    }

    CloseHandle(file);
}

void createFullDump()
{
    wchar_t DumpPath[MAX_PATH] = {0};

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[256] = {0};
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d_full.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth,
              SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

    if (file != INVALID_HANDLE_VALUE)
    {

        const DWORD Flags = MiniDumpWithFullMemory |
                            MiniDumpWithFullMemoryInfo |
                            MiniDumpWithHandleData |
                            MiniDumpWithUnloadedModules |
                            MiniDumpWithProcessThreadData |
                            MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD) GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE) (Flags),
                              nullptr, nullptr, nullptr) != 0)
        {
            std::cout << "Create Full dump successful!! file:";
            std::wcout << DumpPath << std::endl;
        }
        else
        {
            std::cout << "Create Full dump failed!!" << std::endl;
        }
    }

    CloseHandle(file);
}

程序崩溃时自动导出Dump

我们希望程序运行崩溃时可以自动导出dump,这样可以通过分析dump文件找到崩溃原因。

程序崩溃很多情况都是由异常引起的,Windows提供了SetUnhandledExceptionFilter函数用来设置一个函数指针,用于处理未处理的异常,可以在这个函数中导出Dump文件。

1. 准备一个处理异常的函数,并在其中导出dump。异常处理函数有一个参数,这个参数记录了当前异常信息,这个异常信息可以一起随dump文件导出,方便后续查找文件

LONG WINAPI DumpException(EXCEPTION_POINTERS* info)
{
    std::cout << "DumpException, Thread ID:"<< std::this_thread::get_id() << std::endl;
    std::cout << "Exception: 0x" << std::hex << info->ExceptionRecord->ExceptionCode << std::endl;

    wchar_t DumpPath[MAX_PATH] = { 0 };

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[100] = { 0 };
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d_crash.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (file != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION mdei;
        mdei.ThreadId = (DWORD)GetCurrentThreadId();
        mdei.ExceptionPointers = info;
        mdei.ClientPointers = 0;

        DWORD Flags = MiniDumpWithHandleData |
                      MiniDumpWithUnloadedModules |
                      MiniDumpScanMemory|
                      MiniDumpWithIndirectlyReferencedMemory |
                      MiniDumpWithProcessThreadData |
                      MiniDumpWithThreadInfo;

//        Flags = MiniDumpWithFullMemory |
//                MiniDumpWithFullMemoryInfo |
//                MiniDumpWithHandleData |
//                MiniDumpWithUnloadedModules |
//                MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD)GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE)(Flags),
                              &mdei, nullptr, nullptr) != 0)
        {
            std::cout << "Create Crash dump successful!! file:";
            std::wcout << DumpPath << std::endl;
            CloseHandle(file);
            return EXCEPTION_EXECUTE_HANDLER;
        }
    }
    std::cout << "Create Crash dump failed!!" << std::endl;
    CloseHandle(file);

    return EXCEPTION_CONTINUE_SEARCH;
}

2. 在程序启动时设置异常处理函数

int main()
{
    std::cout << "Main Thread ID:" << std::this_thread::get_id() << std::endl;

    LPTOP_LEVEL_EXCEPTION_FILTER oldExceptionFilter = nullptr;
    oldExceptionFilter = SetUnhandledExceptionFilter(&DumpException);

    // ... ...
    // ... ...

}

PS

1. 这里是通过异常捕获生成dump,如果是调用abort,exit,TerminateProcess, TerminateThread函数,这些函数会立即结束函数,所以不会生成dump。

2. SetUnhandledExceptionFilter是全局的,只需设置一次,设置后对所有线程有效。SetUnhandledExceptionFilter有些异常捕获不到。

3. 可以使用第三方库捕获崩溃事件,例如:crashrpt,google breakpad,qBreakpad,Crashpad

UnhandledExceptionFilter未处理的异常

Windows中所有的函数都是从BaseThreadStart函数开始运行

VOID BaseThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) {
__try {
ExitThread((pfnStartAddr)(pvParam));
}
__except (UnhandledExceptionFilter(GetExceptionInformation())) {
ExitProcess(GetExceptionCode());
}
// NOTE: We never get here
}

这里的函数UnhandledExceptionFilter用来处理线程中捕获的未处理的异常,调用SetUnhandledExceptionFilter就是用来设置这个函数。

这里的__try{}__except{} 是 Windows系统的结构化异常处理(SEH),具体参考 《Windows核心编程第五版》——第24章

使用VS调试Dump文件

调试Dump文件,dump文件以外,还需要pdb符号文件,pdb符号文件是编译时和exe程序同时生成的,默认情况下Debug版本会生成符号文件,Release文件不生成符号文件,Release模式下需要收到打开生成符号文件。

打开Dump文件

文件->打开->文件,选择dump文件

设置符号文件

符号文件(pdb)必须保证时和exe同时生成的,且不能改文件名,否则会加载失败

有两种方法

1. 把符号文件和dump文件放在同一个目录下,VS在加载dump时会读取dump目录下的符号文件。

2. 通过 【工具->选项->调试->符号】设置符号文件路径。

 3. 点击右上角的 【使用 混合 进行调试】,则可以查看dump文件的内容,和调试模式下运行出现异常是一样的。

 

使用Windbg调试Dump文件

Windbg 下载 Install WinDbg - Windows drivers | Microsoft Learn

Windbg打开dump后会提示是否有异常

调试步骤:

1. 设置符号文件 【文件->settings->debuging settings】

2. 输入 .ecxr 命令

3. 输入 kn 命令

查看exe编译时间

lm vm test_win*

通过这个时间可以去查找exe对应的pdb文件 

完整代码例子:小康6650/StudyProject - Gitee.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/892360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DispatcherServlet doDispatch()方法解析(1)

目录 简介doDispatch() 源码解析this.mappingRegistry 简介 在DispatcherServlet类中, 最关键的就是doDispatch()这个方法, 每一次请求都需要经过这个方法, 对每个请求进行转发, 通过反射调用对应的方法 doDispatch() 源码解析 可以看到最关键的代码就是1047行, 根据请求对象…

Python规范

PEP8 风格指南&#xff1a; 缩进&#xff0c;用 4 个空格&#xff0c;不要用制表符。(Python 不允许混合制表符和空格进行缩进。)换行&#xff0c;一行不超过 79 个字符。用空行分隔函数和类&#xff0c;及函数内较大的代码块。 用两个空行包围顶级函数和类定义。类内的方法定…

算法通关村第十关 | 数组中第k个最大元素

1.数组中第k大的数字 题目&#xff1a; LeetCode&#xff1a;数组中的第k个最大元素&#xff0c;给定整数数组nums和整数k&#xff0c;请返回数组中第k个最大的元素&#xff0c;请注意&#xff0c;你需要找的是数组排序后第k个最大的元素&#xff0c;而不是第k个不同的元素。 运…

【【STM32-SPI通信协议】】

STM32-SPI通信协议 STM32-SPI通信协议 •SPI&#xff08;Serial Peripheral Interface&#xff09;是由Motorola公司开发的一种通用数据总线 •四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff09;、MOSI&#xff08;Master Output Slave Input&#xff09;、MISO…

stm32F103R6实现流水灯参考源代码

#include "main.h" #include "gpio.h" void SystemClock_Config(void); void sleep(int a) {int i0,j0;for(i0;i<a;i){for(j0;j<2000;j);}} 真正发挥效果的是这个main函数// int main(void) {int i0;HAL_Init();SystemClock_Config();MX_GPIO_Init()…

4.UE数字人工程运行逻辑及程序逻辑

1.Fay-UE5数字人工程导入 2.UE数字人语音交互 3.UE基本操作及数字人工程模块组成&#xff08;UE数字人系统教程&#xff09; 一、3个状态&#xff1a;鸡汤广告、交互&#xff08;聊天与否&#xff09;、跳舞 1、启动即开始循环鸡汤广告模式 2、第一次交互&#xff08;助理版…

gromacs教程练习1

gromacs能在win上运行&#xff0c;还是个开源的软件&#xff0c;这都很值得入手学习 记录下gromacs教程的练习情况&#xff1a; Lysozyme in water 水中的溶菌酶&#xff0c;嗯&#xff0c;估计就是把蛋白处理后放在显试溶剂里跑MD这个模拟。 1、文件的准备&#xff1a; 1、…

JVM虚拟机:初始化的介绍

本文重点 我们前面学习了三个步骤: 装载 连接 初始化 初始化 初始化的时候,会为静态成员变量赋值初始值,它有两种方式: ①声明类变量是指定初始值 ②使用静态代码块为类变量指定初始值 例子 最后输出的结果为3,它的过程是这样的: main方法中输出T.count,由于count是…

产品经理如何提高用户画像效果?SIKT模型

产品经理做用户画像&#xff0c;最担心被业务方反馈&#xff1a;没效果。这往往是由用户画像与业务场景脱节造成的。那么我们该如何从业务场景出发&#xff0c;让用户画像更有效&#xff1f;一般来说&#xff0c;我们可以采用SIKT模型解决这个问题。 用户画像 ​ 1、SIK…

使用CLI添加磁盘到VM

登录 https://portal.azure.com/#home&#xff0c;点击右上角的控制台图标 &#xff0c;打开CLI 在控制台中输入如下指令&#xff0c;在NetworkWatcherRG创建一个名字为TEST的虚拟机&#xff0c;使用的镜像是Win2019datacenter&#xff0c;username是aaa,password是1234567890A…

SpringBoot 操作Redis、创建Redis文件夹、遍历Redis文件夹

文章目录 前言依赖连接 RedisRedis 配置文件Redis 工具类操作 Redis创建 Redis 文件夹查询数据遍历 Redis 文件夹 前言 Redis 是一种高性能的键值存储数据库&#xff0c;支持网络、可基于内存亦可持久化的日志型&#xff0c;而 Spring Boot 是一个简化了开发过程的 Java 框架。…

JDBC Vertica Source Connector 使用文档

支持以下引擎 Spark Flink SeaTunnel Zeta 关键特性 批处理 精确一次性处理 列投影 并行处理 支持用户自定义拆分 支持查询 SQL 并实现投影效果 描述 通过 JDBC 读取外部数据源数据。 支持的数据源信息 DatasourceSupported versionsDriverUrlMavenVerticaDifferent depen…

SAP和APS系统超级BOM核对(SAP配置BOM攻略八)

2023年是华为自动驾驶上路元年&#xff0c;8月问界M5的自驾版已经开通了第一批五大城市的自动驾驶功能&#xff0c;年底逐步开放的城市会多达60个。问界M9会也会在年底发布&#xff0c;而M9的生产工厂也在紧锣密鼓的建设中。 APS (Advanced Planning Scheduling) 高级计划与排…

SD WebUI 扩展:prompt-all-in-one

sd-webui-prompt-all-in-one 是一个基于 Stable Diffusion WebUI 的扩展&#xff0c;旨在提高提示词/反向提示词输入框的使用体验。它拥有更直观、强大的输入界面功能&#xff0c;它提供了自动翻译、历史记录和收藏等功能&#xff0c;它支持多种语言&#xff0c;满足不同用户的…

【自用】云服务器 docker 环境下 HomeAssistant 安装 HACS 教程

一、进入 docker 中的 HomeAssistant 1.查找 HomeAssistant 的 CONTAINER ID 连接上云服务器&#xff08;宿主机&#xff09;后&#xff0c;终端内进入 root &#xff0c;输入&#xff1a; docker ps找到了 docker 的 container ID 2.config HomeAssistant 输入下面的命令&…

1 树 1.1 树的基本概念 1.1.1 什么是树&#xff1f; 树是n(n > 0)个结点的有限集。当n 0时&#xff0c;称为空树。在任意一颗非空树上应该满足&#xff1a; 有且仅有一个特定的称为根的结点当n>1时&#xff0c;其余结点可分为m&#xff08;m>0&#xff09;个互不相…

webrtc学习(六)重要信令级时序图

一.四个重要信令 1.用户登录信令 SignIn 2..用户登出信令 SignOut 3..用户等待信令 wait信令是指从服务器的消息队列中获取暂存的中转消息&#xff0c;比如说sdp消息&#xff0c;对于信令服务器来说&#xff0c;他没有办法给用户推送消息&#xff0c;只能是用户推送消息给…

Leetcode151 翻转字符串中的单词

给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能会存在前导空格、尾随空格…

元素在div中水平居中

先看一下行级元素在div中水平居中&#xff1b; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>div demo </title> <style> body {background-color:#d0e4fe; }</style> </head><body>&…

Python基础语法入门(第二十一天)——异常处理

在Python中&#xff0c;异常处理是一种机制&#xff0c;用于捕获和处理在程序执行过程中发生的错误。 Python中的异常处理可以使用try-except语句块来实现。try语句块可能包含可能出现错误的代码段&#xff0c;而except语句块包含处理错误的代码段。当try语句块中的代码发生错…