MiniDump文件的创建、分析堆栈信息、定位错误、查看异常处理信息
1、MiniDump文件的创建:
创建miniDump的方法有很多。可以通过MiniDumpCreateDumpWin32Api创建。必要参数为EXCEPTION_POINTERS结构,获取这个结构可以通过在异常出通过GetExceptionInfomation函数API获取这个结构,也可以通过SetUnhandleExceptionFilter函数设置自定义异常处理函数(注意:这个函数是处理系统无法处理的异常时触发的),这个自定义异常处理函数的函数原型为
typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo);
这个里面的参数为系统传入的,其中包括了异常信息,以及上下文句柄。
而写Dump的函数原型为:
BOOL MiniDumpWriteDump( HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam );
其中需要主要的是第三个参数和 第四个参数:第三个参数表示需要在dump文件中记录什么信息。详细解释见MSDN,第四个参数从众多网上例子来看很多都没有在意这个参数。这个参数的结构体原型如下:
typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
DWORD ThreadId;
PEXCEPTION_POINTERS ExceptionPointers;
BOOL ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
ClientPointers指针这个参数到底什么时候为TRUE什么时候为FALSE呢?
MSDN的解释为如果调试进程在内存中为true,否则为false,如果错误地址所在进程在内存中,应该为false,否则为true,总结一句话为,如果要记录内存中的地址相关信息(包括堆栈,偏移地址,断片地址,节表信息等等)应该为FALSE,其他为true。这个参数决定着dump文件的价值。
分析堆栈信息
堆栈信息可以帮助我们快速定位程序所谓位置以及错误发生的原因。有利于程序的错误修复,加快工作效率。如果获取异常程序的堆栈信息呢?
在设置自定义异常处理函数时,传入的异常信息结构中包括了一个CONTEXT结构体的指针。这个指针就是上下文句柄。
这个结构体的原型如下:
typedef struct _CONTEXT {
RD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
这个结构体的详细解释见MSDN。
通过这个结构我们里面的相关信息就可以获取异常程序的堆栈信息。获取堆栈信息的API 函数原型如下:
BOOL IMAGEAPI StackWalk64( DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
第一个参数:表示本机芯片类型,芯片不同也表明取值不一样。
第四个参数表示获取堆栈信息所需要的一些关键信息。
其他参数详情见MSDN。
举例如下:这个例子网上很多,详细信息请将CONTEXT结构和STACKFRAME64结构结合学习。
unsigned long dwImageType=IMAGE_FILE_MACHINE_I386;//设置默认芯片类型为X86
#ifdef _M_IX86
sf.AddrPC.Offset = c.Eip;//当芯片类型为X86是,程序计数器地址的偏移量(或者首地址)取值为CONTEXT结构的Eip成员
sf.AddrPC.Mode = AddrModeFlat;//平面寻址//详细解释见MSDN
sf.AddrStack.Offset = c.Esp;//堆栈偏移
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Offset = c.Ebp;//帧偏移
sf.AddrFrame.Mode = AddrModeFlat;
#elif _M_X64
dwImageType = IMAGE_FILE_MACHINE_AMD64;
sf.AddrPC.Offset = c.Rip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrFrame.Offset = c.Rbp;
sf.AddrFrame.Mode = AddrModeFlat;
sf.AddrStack.Offset = c.Rsp;
sf.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
dwImageType = IMAGE_FILE_MACHINE_IA64;
sf.AddrPC.Offset = c.StIIP;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrFrame.Offset = c.IntSp;
sf.AddrFrame.Mode = AddrModeFlat;
sf.AddrBStore.Offset = c.RsBSP;
sf.AddrBStore.Mode = AddrModeFlat;
sf.AddrStack.Offset = c.IntSp;
sf.AddrStack.Mode = AddrModeFlat;
#endif
获取错误函数API
SymGetSymFromAddr64(
_In_ HANDLE hProcess,
_In_ DWORD64 qwAddr,
_Out_opt_ PDWORD64 pdwDisplacement,
_Inout_ PIMAGEHLP_SYMBOL64 Symbol
);
获取错误错误行的API
BOOL
IMAGEAPI
SymGetLineFromAddr64(
_In_ HANDLE hProcess,
_In_ DWORD64 qwAddr,
_Out_ PDWORD pdwDisplacement,
_Out_ PIMAGEHLP_LINE64 Line64
);
//获取错误模块
BOOL
IMAGEAPI
SymGetModuleInfo64(
_In_ HANDLE hProcess,
_In_ DWORD64 qwAddr,
_Out_ PIMAGEHLP_MODULE64 ModuleInfo
);
这三个API的参数详细解释见MSDN,
第二个参数的取值为为当前程序的程序计时器偏移地址,表示从当前程序的主线程开始获取错误信息。
符号表:
symbolTable是分析dump文件的关键所在,symbol可以帮助更加准确的定位程序错误。因此,在获取堆栈信息获取生成dump文件之前绑定符号表是必须的。绑定的符号表的API如下:
BOOL IMAGEAPI SymInitialize( HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess );
详细解释见MSDN,这里详细讲解第二个参数,符号表路径,如何设置符号表路径呢?可以设置为NULL,具体解释见MSDN,
但如果不为空如何加载呢?
示例如下:
#define SYMPATH "%SYSTEMROOT%;.\\Symbols\\;..\\Symbols\\;..\\..\\Symbols\\;..\\..\\..\\Symbols\\"
ExpandEnvironmentStringsA(SYMPATH, symPath, sizeof(symPath));
这个API的功能是扩展环境变量的取值,通俗一点将就是获取变量值。
至于字符串是什么含义,请查询环境变量相关变量含义。
查询异常处理信息:
首先查询异常信息需要一定的windebug基础。
https://blog.csdn.net/sunboyhch/article/details/37914727
查询具体异常的一般流程为:
miniDump的具体操作流程是这样:
1、打开异常dump文件
2、导入pdb符号文件
3、输入!analyze -v 命令分析出错原因,堆栈信息、出错位置,以及包含错误位置的文件。
4、然后通过文件菜单打开文件。
5、输入.ecxr 关联
6、kp命令。输出详细的错误信息。
第二种方法是
1、直接输入.excr直接通过dump文件的记录的索引关联源文件。
2、输入kp命令查看详细的堆栈错误信息
在异常处理的过程中。还需要了解一些其他的知识,如dos文件头、PE文件格式等等。推荐博客链接如下:
https://blog.csdn.net/chenlycly/article/details/53378196
bool CrashHandleCls::GetLogicalAddress(PVOID pLinearAddress,PTSTR pszModule,DWORD dwModuleNameLen,DWORD_PTR& dwSection,DWORD_PTR& dwOffset){
MEMORY_BASIC_INFORMATION mbi;
if(!::VirtualQuery(pLinearAddress,&mbi,sizeof(mbi)))return false;
DWORD_PTR hModule=(DWORD_PTR)mbi.AllocationBase;//获取页面起始地址
//验证访问权限
if(IsBadReadPtr((const void *)hModule,sizeof(IMAGE_DOS_HEADER))) {
_tcsncpy(pszModule,_T("Unknown"),dwModuleNameLen);
dwSection=0;
dwOffset=0;
return false;
}
//获取完整的路径
if(!::GetModuleFileNameW((HMODULE)hModule,pszModule,dwModuleNameLen))return false;
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule;//转换为DOS文件结构
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hModule + pDosHdr->e_lfanew); //获取PE文件的文件头 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);//定位区块表(节表)
DWORD_PTR dwRVA = (DWORD_PTR)pLinearAddress - hModule;//获取偏移地址
//pNtHdr->FileHeader.NumberOfSections 获取节表总数
for(UINT i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++)
{
DWORD_PTR dwSectionStart = pSection->VirtualAddress;//获取目标在内存中的开始地址(节区的 RVA 地址)
DWORD_PTR dwSectionEnd = dwSectionStart +
max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);//获取目标在内存中的结束地
if((dwRVA >= dwSectionStart) && (dwRVA <= dwSectionEnd)) {
dwSection = i + 1;
dwOffset = dwRVA - dwSectionStart;//获取偏移量
return TRUE;
}
}
dwSection = 0;
dwOffset = 0;
return FALSE;
}
MiniDump文件的创建、分析堆栈信息、定位错误、查看异常处理信息相关推荐
- linux查看显示器名称命令,linux 查看显示器信息Linux下查看硬件信息命令大全
/proc 虚拟的目录,是系统内存的映射.可直接访问这个目录来获取系统信息.其中也包含下面的信息: 主机CPU信息:cpuinfo 主机DMA通道信息:dma 文件系统信息:filesystems 主 ...
- think.class.php错误,thinkphp源码分析(四)—错误及异常处理篇
源码分析 错误及异常处理机制 错误及异常处理机制文件是/thinkphp/library/think/Error.php,在框架引导文件的的基础文件base.php中注册(不知道的可以去看<&l ...
- thinkphp 源码分析(四)—— 错误和异常处理 以及 log 日志
0x01 前言 本来是这样的,继续是smile 师傅的那篇文章,文章中提到了可以用包含日志, 但是一开始我输入: http://127.0.0.1/public/index.php/index/ind ...
- linux 下查看应用版本信息,Linux下查看版本信息
Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等. 1.# uname -a (Linux查看版本当前操作系统内核信息) 2.# cat /proc/vers ...
- ubantu获取信息_Ubuntu 下查看CPU 信息命令
查看当前操作系统内核信息 uname -a Linux redcat 2.6.31-20-generic #58-Ubuntu SMP Fri Mar 12 05:23:09 UTC 2010 i68 ...
- linux查看进程详细信息top,linux查看系统进程信息命令 px,top详解
linux查看系统进程信息命令 px,top详解 发表于:2011-03-10来源:作者:点击数: linux查看系统进程信息命令 px,top详解 软件测试 ps ax命令是显示一个当前系统进程的列 ...
- linux 查看numa信息,Linux中查看NUMA信息
Linux中查看NUMA信息 2015-03-19 本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢. 声明: 本博客欢迎转发,但请保留原作者信息! 新浪 ...
- linux 网卡硬件信息失败,linux 查看硬件信息,网卡、CPU、硬盘
查看网卡型号 [root@server]# lspci | grep Ethernet 00:19.0 Ethernet controller: Intel Corporation 82567V-2 ...
- linux系统查看机器硬件信息,linux系统查看硬件信息的方法
用过Linux系统的人都知道这么一个情况,那就是Linux大部分操作是通过命令实现的,并不像Windows那么直观.linux查看硬件信息也是需要通过命令查询才可以看得到硬件的信息,那linux系统如 ...
最新文章
- c语言fd变量,有哪位大神会用FD程序包计算功能多样性呀,在线等......
- BZOJ 3456 城市规划 (组合计数、DP、FFT)
- linux useradd命令使用示例
- mysql 5.x数据库安装_Ubuntu 12.04 mysql 源码安装--mysql.5.5.x
- 彻底禁用chrome请停用以开发者模式运行的扩展程序弹框
- 利用WireShark破解网站密码
- MAC M1 安装 matlab2020a
- 高二计算机考试题库和答案,2017计算机基础考试题库及答案
- 城市公交类毕业论文文献都有哪些?
- 第三届上海大学生网络安全大赛 流量分析
- sox处理mp3_音频处理利器--SoX
- 网站蜘蛛日志分析解读,SEO站长自查诊断
- 简单爬取小姐姐的照片
- Scala 令人着迷的类设计
- matches()方法的使用规则
- 51单片机 | LED点阵实验 | 点亮一个点 | 显示数字 | 显示图像
- MATLAB中关于patch的用法(涉及vertice,faces等的基础的介绍)
- 别让自己 “墙” 了自己
- 室外无线覆盖解决方案
- 用Python分析完6000 款 App,得出这些结论
热门文章
- Anaconda无法通过activate激活虚拟环境解决方案
- 非常暧昧的两个人(同事)关系突然就疏远
- ms sql java_java连接ms sql server各类问题解析
- 数值计算实验_完整的列表计算程序,计算lnx导数,3种方法计算调和级数
- 数学建模论文写作学习——论文题目、关键词、摘要写作学习
- arguments的用法总结
- JSFL自动绘画_5_黄金分割
- java计算机毕业设计汽车金融人事管理源码+系统+数据库+lw文档+mybatis+运行部署
- ulimit: file size: cannot modify limit: Operation not permitted 修改ulimit -f 时报错
- 2011孕妇奶粉排行榜