调试Release程序--Dump文件方式

合集下载

Release版程序调试技巧

Release版程序调试技巧

Release版程序调试技巧环境及工具:windows 9x/2000/xp,VC 6.0(SP6)Win32Dasm 8.93CrashFinder在软件产品的测试过程中,以及发布之后,程序可能会由于一般保护错(GPF)而崩溃。

即程序中访问了禁止访问的内存。

这时,程序一般情况下无法继续运行,只能结束。

在安装了调试器(比如VC)的系统中,会弹出一个错误对话框,显示类似:“0x12345678”指令引用的”0x000000123”内存。

该内存不能为”written(read)”终止单击确定,调试单击取消。

没有调试器的系统中一般会出现一个Dr. watson窗口,内容类似。

通常,我们遇到这个问题时只能大致地从程序运行(上下文)情况来粗略推断错误,但实际上有更好的解决办法。

在开发过程中,编译release版本的程序(包括EXE、DLL、OCX等二进制程序)时,要建立相关的mapfile,即映像文件。

方法如下(VC):(1)选择release版本;(2)Project settings => C/C++ => Debug Info,选“Line Number Only”;(3)Project settings => link => 选中“Generate mapfile”;(4)Project settings => link => Project Option中,输入:/mapinfo:lines这样,编译后就会生成一个*.map的文本文件,其中包含了release版本程序的相关信息。

当程序出现GPF时,记下指令地址,然后可以在map文件中的Rva+Base 段查找相关的信息。

比如:H1接口程序,出错指令为0x0040d7a0,在map文件中,可发现:0001:0000c730 ?RefreshDevList@@YGIPAX@Z 0040d730 f FFServer.obj其中0040d730是小于0040d7a0的最大地址,则可初步断定是在RefreshDevList函数中出的问题。

Windows调试工具入门2(WinDbg基本调试器设置)

Windows调试工具入门2(WinDbg基本调试器设置)

Windows调试工具入门2—基本调试器设置设置Windows调试工具入门-2本篇介绍Windows调试工具的基本设置和基本操作方法。

这里我们会用一个测试程序一步一步说明如何使用WinDbg开始调试工作。

首先用VC建立一个名为TestDebug1的控制台项目,并生成它。

、源码和可执行映像路径设置符号、一、符号使用WinDbg开始调试工作之前,最重要的就是配置好各种环境了。

这使得调试器可以正确识别调试目标中的各种变量、函数等等,使得我们能够进行符号化调试或者源码调试,而不是只能在一堆汇编代码中转圈。

首先来看一下未设置环境之前的样子。

使用刚才说的TestDebug1项目,为了对比更清晰,用Release进行编译,链接选项中选中生成map文件和调试信息,如下:在C/C++选项卡中设置如下:程序代码如下:#include "stdafx.h"#include <stdio.h>int main(int argc, char* argv[]){printf( "TestDebug1.cpp");return 0;}编译之后,将Release目录下的TestDebug1.pdb剪切到其他目录下(如果没有这样做,由于编译出来的程序中包含了符号文件路径,调试器可以直接使用exe中的信息找到pdb文件,而不需要设置路径)。

在map文件中可以看到像下面这样的内容:0001:00000000 _main 00401000 f TestDebug1.obj说明main函数位于401000地址处。

通过WinDbg的File->Open Executeable菜单打开TestDebug1.exe,可以在调试器命令窗口中看到下面的内容:可以看到,调试器自动中断下来的位置并不是程序入口点,这是由WinDbg实现造成的,这里先不管它。

调试器命令窗口中可以看到,我们还没有设置符号路径,所以WinDbg目前还找不到TestDebug1.exe的任何符号文件。

gdb调试coredump原理

gdb调试coredump原理

gdb调试coredump原理GDB调试coredump原理引言:在开发过程中,我们经常会遇到程序崩溃的情况。

为了定位程序崩溃的原因,我们需要进行调试。

而在调试过程中,有一种特殊的情况,叫做coredump。

当一个程序发生严重错误或崩溃时,操作系统会生成一个core文件,记录程序崩溃时的内存状态。

通过调试这个core文件,我们可以更加方便地找到程序的问题所在。

本文将以gdb调试coredump为主题,详细介绍其原理和使用方法。

一、什么是coredump?Coredump指的是当一个程序因为错误而异常终止时,操作系统将程序的内存状态保存到一个特殊的文件中,即core文件。

这个core文件包含了程序崩溃时的内存状态、寄存器的状态以及函数、变量的信息。

对于GDB 来说,这个core文件就是一个可调试的文件,我们可以使用GDB来调试这个文件,进一步定位程序错误的原因。

二、生成coredump文件的配置生成coredump文件的配置主要涉及到操作系统的配置和程序的编译配置。

1. 操作系统配置大多数Unix-like系统默认是开启coredump功能的,但有时会被禁用。

我们可以通过下面的命令来查看系统是否开启了coredump功能:ulimit -c如果输出为0,则表示未开启,大于0则表示开启。

我们可以通过下面的命令来开启coredump功能,并设置生成的core文件大小:ulimit -c unlimitedulimit -c <size>其中,<size>指的是core文件的大小,单位为字节。

2. 编译配置在编译程序时,我们需要添加-g选项来启用调试信息的产生。

例如,我们可以使用gcc编译C程序时,添加如下的命令行选项:gcc -g -o program program.c通过以上配置,就可以在程序崩溃时生成core文件。

三、使用GDB调试coredump文件1. 命令行方式通过命令行方式使用GDB调试coredump文件非常简单,只需指定coredump文件和可执行文件即可。

Linux crash工具

Linux crash工具

什么是 crash如前文所述,当 linux 系统内核发生崩溃的时候,可以通过 kdump 等方式收集内核崩溃之前的内存,生成一个转储文件 vmcore。

内核开发者通过分析该 vmcore 文件就可以诊断出内核崩溃的原因,从而进行操作系统的代码改进。

那么 crash 就是一个被广泛使用的内核崩溃转储文件分析工具,掌握 crash 的使用技巧,对于定位问题有着十分重要的作用。

回页首使用 crash 的先决条件由于 crash 用于调试内核崩溃的转储文件,因此使用 crash 需要依赖如下条件:1. kernel 映像文件 vmlinux 在编译的时候必须指定了 -g 参数,即带有调试信息。

2. 需要有一个内存崩溃转储文件(例如 vmcore),或者可以通过 /dev/mem 或/dev/crash 访问的实时系统内存。

如果 crash 命令行没有指定转储文件,则 crash 默认使用实时系统内存,这时需要 root 权限。

3. crash 支持的平台处理器包括:x86, x86_64, ia64, ppc64, arm, s390, s390x ( 也有部分 crash 版本支持 Alpha 和 32-bit PowerPC,但是对于这两种平台的支持不保证长期维护 )。

4. crash 支持 2.2.5-15(含)以后的 Linux 内核版本。

随着 Linux 内核的更新,crash 也在不断升级以适应新的内核。

回页首crash 安装指南要想使用 crash 调试内核转储文件,需要安装 crash 工具和内核调试信息包。

不同的发行版安装包名称略有差异,这里仅列出 RHEL 和 SLES 发行版对应的安装包名称如下:表 1. crash 工具和内核调试包系统版本crash 工具名称内核调试信息包RHEL6.2 crash kernel-debuginfo-commonkernel-debuginfoSLES11SP2 crash kernel-default-debuginfokernel-ppc64-debuginfo以 RHEL 为例,安装 crash 及内核调试信息包的步骤如下:rpm -ivh crash-5.1.8-1.el6.ppc64.rpmrpm -ivh kernel-debuginfo-common-ppc64-2.6.32-220.el6.ppc64.rpmrpm -ivh kernel-debuginfo-2.6.32-220.el6.ppc64.rpm回页首启动 crash启动参数说明使用 crash 调试转储文件,需要在命令行输入两个参数:debug kernel 和 dump file,其中 dump file 是内核转储文件的名称,debug kernel 是由内核调试信息包安装的,不同的发行版名称略有不同,以 RHEL 和 SLES 为例:RHEL6.2:/usr/lib/debug/lib/modules/2.6.32-220.el6.ppc64/vmlinuxSLES11SP2:/usr/lib/debug/boot/vmlinux-3.0.13-0.27-ppc64.debug使用 crash -h 或 man crash 可以查看 crash 支持的一系列选项,这里仅以常用的选项为例说明如下:-h:打印帮助信息-d:设置调试级别-S:使用 /boot/System.map 作为默认的映射文件-s:不显示版本、初始调试信息等,直接进入命令行-i file:启动之后自动运行 file 中的命令,再接受用户输入crash 报告分析crash 命令启动后,会产生一个转储文件的分析报告摘要,如下图所示。

debug模式和release模式区别

debug模式和release模式区别

什么是debug模式,,release模式?收藏经常有人问Debug 运行正常但Release 失败的问题。

以往的讨论往往是经验性的,并没有指出会这样的真正原因是什么,要想找出真正的原因通常要凭运气。

最近我看了一些这方面的帖子,拿来与大家共享。

--------------------------------------本文主要包含如下内容:1. Debug 和Release 编译方式的本质区别2. 哪些情况下Release 版会出错2. 怎样“调试” Release 版的程序--------------------------------------关于Debug和Release之本质区别的讨论一、Debug 和Release编译方式的本质区别Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。

Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。

Debug 和Release 的真正秘密,在于一组编译选项。

下面列出了分别针对二者的选项(当然除此之外还有其他一些,如/Fd /Fo,但区别并不重要,通常他们也不会引起Release 版错误,在此不讨论)Debug 版本:/MDd /MLd 或/MTd 使用Debug runtime library(调试版本的运行时刻函数库) /Od 关闭优化开关/D "_DEBUG" 相当于#define _DEBUG,打开编译调试代码开关(主要针对assert函数) /ZI 创建Edi t and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译/GZ 可以帮助捕获内存错误/Gm 打开最小化重链接开关,减少链接时间Release 版本:/MD /ML 或/MT 使用发布版本的运行时刻函数库/O1 或/O2 优化开关,使程序最小或最快/D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数) /G F 合并重复的字符串,并将字符串常量放到只读内存,防止被修改实际上,Debug 和Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。

dump参数

dump参数

dump参数dump参数是指在计算机程序中用来将数据从内存中转储到外部文件或设备的一种操作。

在软件开发和调试过程中,dump参数常常用于记录程序运行时的状态信息,以便后续分析和排查问题。

本文将从dump参数的定义、使用场景和注意事项等方面进行阐述。

一、dump参数的定义在计算机编程中,dump参数是指将内存中的数据转储到外部文件或设备的操作。

它可以把程序在运行时的状态信息保存下来,以便后续分析和调试。

通过使用dump参数,开发人员可以获取程序在运行过程中的变量值、函数调用栈、异常信息等关键数据,从而更好地理解程序的运行情况。

1. 调试程序:当程序发生异常或崩溃时,使用dump参数可以将程序的状态信息保存下来,以便后续进行调试。

通过分析dump文件,开发人员可以定位问题所在,并进行修复。

2. 性能分析:在对程序进行性能优化时,使用dump参数可以记录程序运行时的性能数据,如CPU占用率、内存使用情况等。

通过分析dump文件,开发人员可以找出性能瓶颈,并进行优化。

3. 安全分析:当程序受到攻击或存在安全漏洞时,使用dump参数可以记录攻击的痕迹和关键信息。

通过分析dump文件,安全专家可以了解攻击者的行为,进而采取相应的安全措施。

4. 数据恢复:在程序运行过程中,如果发生意外情况导致数据丢失或损坏,使用dump参数可以将内存中的数据保存下来,以便后续进行数据恢复。

三、dump参数的注意事项1. dump文件的大小:由于dump文件包含了程序在运行时的所有状态信息,因此文件大小通常会很大。

在使用dump参数时,需要注意磁盘空间是否足够,并确保dump文件的保存路径正确。

2. dump文件的保密性:由于dump文件中包含程序的关键信息,如变量值、函数调用栈等,因此需要妥善保管,避免泄露给未授权的人员。

3. dump文件的分析:分析dump文件需要一定的专业知识和工具支持。

开发人员在使用dump参数时,需要了解如何使用相关工具进行分析,并能够准确地定位问题所在。

linux,人为产生dump文件的方法

linux,人为产生dump文件的方法
在Linux系统中,可以通过以下方法人为产生dump文件:
1. 使用gcore命令:gcore命令可以在运行中的进程中生成一个core 文件,可以用于后续的调试分析。

例如,要生成进程ID为12345的进程的dump文件,可以使用以下命令:
```
gcore 12345
```
该命令将在当前目录下生成一个名为core.12345的dump文件。

2. 使用kill命令:可以使用kill命令发送一个特殊的信号给某个进程,使其生成core文件。

例如,要生成进程ID为12345的进程的dump文件,可以使用以下命令:
```
kill -SIGQUIT 12345
```
该命令将发送SIGQUIT信号给进程,进程会生成一个core文件。

3. 使用gdb调试器:可以使用gdb调试器来附加到一个正在运行的进程,并在其中生成core文件。

首先,使用ps命令找到要调试的进程的进程ID,然后使用gdb命令附加到该进程。

例如,要生成进
程ID为12345的进程的dump文件,可以使用以下命令:
```
gdb -p 12345
```
然后,在gdb的交互界面中,可以使用generate-core-file命令来生成core文件。

无论使用哪种方法,生成的dump文件都可以用于调试和分析程序的崩溃问题。

请注意,在生产环境中,应谨慎使用这些方法,并确保在产生dump文件之前已经备份了重要的数据。

coredump文件的生成方式

coredump文件的生成方式
Core dump文件是在程序发生严重错误(如段错误、内存访问
越界等)时,操作系统将程序当前的内存状态以文件的形式保存下
来的一种机制。

生成core dump文件的方式可以通过以下几种途径:
1. 通过ulimit命令设置core dump文件大小限制,可以使用ulimit命令来设置core dump文件的大小限制,使用ulimit -c unlimited命令可以将core dump文件的大小限制设置为无限制,
这样当程序发生错误时就会生成core dump文件。

2. 在程序中使用系统调用设置,在程序中可以通过调用系统函
数来设置生成core dump文件的方式,比如使用ulimit函数设置core dump文件大小限制,或者使用prctl函数设置生成core dump
文件的路径等。

3. 通过操作系统的配置文件设置,在一些操作系统中,可以通
过修改配置文件(如/etc/security/limits.conf)来设置生成
core dump文件的大小限制和路径等参数。

4. 使用特定的调试工具,在调试程序时,可以使用特定的调试
工具(如gdb)来设置程序发生错误时生成core dump文件,通过gdb工具可以设置生成core dump文件的路径和大小限制等参数。

总的来说,生成core dump文件的方式可以通过操作系统的设置、程序中的系统调用、配置文件的修改以及调试工具的使用等途径来实现。

不同的操作系统和调试工具可能会有不同的设置方法,需要根据具体情况进行选择和配置。

Dump文件分析(转发)

Dump⽂件分析(转发)原⽂:本⽂主要介绍Dump⽂件结构,理解Dump⽂件对于分析线程⾼占⽤、死锁、内存溢出等⾼级问题有⾮常重要的指导意义。

什么是Dump⽂件Dump⽂件是进程的内存镜像。

可以把程序的执⾏状态通过调试器保存到dump⽂件中。

Dump⽂件是⽤来给程序编写⼈员调试程序⽤的,这种⽂件必须⽤专⽤⼯具软件打开。

如何⽣成Dump⽂件使⽤命令:jstack pid可以查看到当前运⾏的java进程的dump信息。

Dump⽂件结构⾸先浏览⼀下dump⽂件的⽂本内容:Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.77-b03 mixed mode):"Attach Listener" #37 daemon prio=9 os_prio=0 tid=0x00007f87b42b7000 nid=0x680f waiting on condition [0x0000000000000000]ng.Thread.State: RUNNABLE"Druid-ConnectionPool-Destory-331358539" #36 daemon prio=5 os_prio=0 tid=0x00007f87a4278800 nid=0x67e4 waiting on condition [0x00007f87b8dce000] ng.Thread.State: TIMED_WAITING (sleeping)at ng.Thread.sleep(Native Method)at com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:1724)"Druid-ConnectionPool-Create-331358539" #35 daemon prio=5 os_prio=0 tid=0x00007f87a4022000 nid=0x67e3 waiting on condition [0x00007f87ce86a000] ng.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000b3804848> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:1629)"Abandoned connection cleanup thread" #31 daemon prio=5 os_prio=0 tid=0x00007f87e0d91800 nid=0x672b in Object.wait() [0x00007f87cd2c2000]ng.Thread.State: TIMED_WAITING (on object monitor)at ng.Object.wait(Native Method)at ng.ref.ReferenceQueue.remove(ReferenceQueue.java:143)- locked <0x00000000b422d1e8> (a ng.ref.ReferenceQueue$Lock)at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)"DestroyJavaVM" #30 prio=5 os_prio=0 tid=0x00007f87e0008800 nid=0x670b waiting on condition [0x0000000000000000]ng.Thread.State: RUNNABLE"http-nio-8081-AsyncTimeout" #28 daemon prio=5 os_prio=0 tid=0x00007f87e016e800 nid=0x6727 waiting on condition [0x00007f87b94cf000]ng.Thread.State: TIMED_WAITING (sleeping)at ng.Thread.sleep(Native Method)at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1211)at ng.Thread.run(Thread.java:745)"http-nio-8081-Acceptor-0" #27 daemon prio=5 os_prio=0 tid=0x00007f87e0166000 nid=0x6726 runnable [0x00007f87b95d0000]ng.Thread.State: RUNNABLEat sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)- locked <0x00000000b410d480> (a ng.Object)at .NioEndpoint$Acceptor.run(NioEndpoint.java:455)at ng.Thread.run(Thread.java:745)"http-nio-8081-ClientPoller-0" #26 daemon prio=5 os_prio=0 tid=0x00007f87e0292800 nid=0x6725 runnable [0x00007f87b96d1000]ng.Thread.State: RUNNABLEat sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)- locked <0x00000000b410d6c0> (a sun.nio.ch.Util$2)- locked <0x00000000b410d6b0> (a java.util.Collections$UnmodifiableSet)- locked <0x00000000b410d668> (a sun.nio.ch.EPollSelectorImpl)at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)at .NioEndpoint$Poller.run(NioEndpoint.java:793)at ng.Thread.run(Thread.java:745)"http-nio-8081-exec-10" #25 daemon prio=5 os_prio=0 tid=0x00007f87e028c000 nid=0x6724 waiting on condition [0x00007f87b97d2000]ng.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000b410d898> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at ng.Thread.run(Thread.java:745)其中每个空⾏⽤于分隔⼀个线程,每个线程的信息是以堆栈信息的⽅式展开,显⽰了⽬前正在调⽤的⽅法以及所在的代码⾏。

dump文件的函数参数

dump文件的函数参数一、什么是dump文件?dump文件是程序在运行过程中,将内存中的数据以二进制的形式保存到磁盘上的一种文件格式。

它包含了程序在运行过程中的所有内存信息,包括变量的值、函数的调用栈、堆栈信息等。

通过分析dump文件,可以了解程序在运行过程中的状态,帮助程序员快速定位和解决问题。

二、为什么需要使用dump文件?在程序开发过程中,经常会遇到各种各样的bug和崩溃问题。

当程序出现崩溃时,我们通常无法立即找到问题的原因,这时候使用dump文件就非常有帮助了。

通过分析dump文件,可以还原出程序在崩溃时的内存状态,帮助我们定位问题所在。

三、如何生成dump文件?生成dump文件的方法有很多种,下面介绍两种常用的方法:1. 使用操作系统提供的工具:在Windows操作系统中,可以通过配置系统参数或使用命令行工具来生成dump文件。

例如,在Windows 7及以上版本中,可以通过配置系统参数来指定在程序崩溃时自动生成dump文件。

2. 使用调试工具:在程序调试过程中,可以使用调试工具生成dump文件。

例如,在Visual Studio中,可以通过在代码中插入调试断点或使用异常处理机制来生成dump文件。

dump文件的函数参数是指在生成dump文件时,对相关函数的调用所传递的参数信息。

这些参数信息对于分析问题和定位错误非常重要。

下面介绍几个常见的dump文件函数参数:1. 栈指针(Stack Pointer):栈指针是指向程序当前栈帧的指针,它指向了当前函数的返回地址和函数的局部变量。

通过栈指针,可以获取函数的调用栈信息,从而了解函数的调用关系和参数传递。

2. 堆指针(Heap Pointer):堆指针是指向堆内存区域的指针,堆内存是动态分配的内存,例如通过malloc()函数分配的内存。

通过堆指针,可以获取堆内存的状态信息,帮助我们分析内存泄漏等问题。

3. 函数参数(Function Arguments):函数参数是指函数在调用时传递的参数值。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。

因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash 的现场很难保留和重现。

目前有一些方法可以解决:崩溃地址+ MAP文件;MAP 文件;SetUnhandledExceptionFilter + Minidump。

本文重点解决Minidump方式。

一、Minidump文件生成1、Minidump概念minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。

实际上,如果你在系统属性-> 高级-> 启动和故障恢复-> 设置-> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。

我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。

而且为了符合其mini的特性,dump文件是压缩过的。

2、生成minidump文件通过drwtsn32、NTSD、CDB等调试工具生成Dump文件,drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。

根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。

3、自动生成Minidump文件当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。

MSDN中描述为:Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。

生成dump文件类(minidump.h)#pragma once#include<windows.h>#include<imagehlp.h>#include<stdlib.h>#pragma comment(lib, "dbghelp.lib")inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName){if(pModuleName == 0){return FALSE;}WCHAR szFileName[_MAX_FNAME] = L"";_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);if(wcsicmp(szFileName, L"ntdll") == 0)return TRUE;return FALSE;}inline BOOL CALLBACK MiniDumpCallback(PVOIDpParam,const PMINIDUMP_CALLBACK_INPUT pInput,PMINIDUMP_CALLBACK_OUTPUTpOutput){if(pInput == 0 || pOutput == 0)return FALSE;switch(pInput->CallbackType){case ModuleCallback:if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)if(!IsDataSectionNeeded(pInput->Module.FullPath))pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);case IncludeModuleCallback:case IncludeThreadCallback:case ThreadCallback:case ThreadExCallback:return TRUE;default:;}return FALSE;}//创建Dump文件inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName) {HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)){MINIDUMP_EXCEPTION_INFORMATION mdei;mdei.ThreadId = GetCurrentThreadId();mdei.ExceptionPointers = pep;mdei.ClientPointers = FALSE;MINIDUMP_CALLBACK_INFORMATION mci;mci.CallbackRoutine =(MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;mci.CallbackParam = 0;MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);CloseHandle(hFile);}}LPTOP_LEVEL_EXCEPTION_FILTER WINAPIMyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter){return NULL;}BOOL PreventSetUnhandledExceptionFilter(){HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));if (hKernel32 == NULL)return FALSE;void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");if(pOrgEntry == NULL)return FALSE;unsigned char newJump[ 100 ];DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp farvoid *pNewFunc = &MyDummySetUnhandledExceptionFilter;DWORD dwNewEntryAddr = (DWORD) pNewFunc;DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;newJump[ 0 ] = 0xE9; // JMP absolutememcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));SIZE_T bytesWritten;BOOL bRet= WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);return bRet;}LONG WINAPI UnhandledExceptionFilterEx(struct_EXCEPTION_POINTERS*pException){TCHAR szMbsFile[MAX_PATH] = { 0 };::GetModuleFileName(NULL, szMbsFile, MAX_PATH);TCHAR* pFind = _tcsrchr(szMbsFile, '\\');if(pFind){*(pFind+1) = 0;_tcscat(szMbsFile, _T("CreateMiniDump.dmp"));CreateMiniDump(pException,szMbsFile);}// TODO: MiniDumpWriteDumpFatalAppExit(-1, _T("Fatal Error"));return EXCEPTION_CONTINUE_SEARCH;}//运行异常处理void RunCrashHandler(){SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);PreventSetUnhandledExceptionFilter();}//测试实现文件// 一个有函数调用的类//class CrashTest{public:void Test(){Crash();}private:void Crash(){// 除零,人为的使程序崩溃//int i = 13;int j = 0;int m = i / j;strcpy(NULL,"adfadfg");}};int_tmain(int argc, _TCHAR* argv[]){//设置异常处理函数RunCrashHandler();CrashTest test;test.Test();getchar();return 0;}注意事项1、需要配置debug选项,在C/C++选项→常规→调试信息格式(设置为程序数据库(/Zi));在连接器选项—>调试→生成调试信息(设置为是);C/C++选项→优化→禁用。

相关文档
最新文档