什么网站容易收录,爱客wordpress源码,wordpress手机视频主题,WordPress去掉由开发目录
1、概述
2、将Windbg附加到已经启动起来的目标进程上#xff0c;或者用Windbg启动目标程序
2.1、将Windbg附加到已经启动起来的目标进程上
2.2、用Windbg启动目标程序
2.3、Windbg关联到目标进程上会中断下来#xff0c;输入g命令将该中断跳过去
3、分析实例说明 …目录
1、概述
2、将Windbg附加到已经启动起来的目标进程上或者用Windbg启动目标程序
2.1、将Windbg附加到已经启动起来的目标进程上
2.2、用Windbg启动目标程序
2.3、Windbg关联到目标进程上会中断下来输入g命令将该中断跳过去
3、分析实例说明
4、分析测试程序的崩溃
4.1、启动程序将Windbg附加到目标进程上
4.2、使用Windbg初步分析崩溃
4.3、找到相关模块的pdb文件设置到Windbg中
4.4、加载pdb后查看包含完整信息的函数调用堆栈
4.5、设置C源代码的路径Windbg会自动跳转到源代码对应的行号上
4.6、有时需要查看函数中变量的值
4.7、使用.dump命令导出包含异常上下文的dump文件
4.8、可以在Windbg中进行断点调试
5、最后 C软件异常排查从入门到精通系列教程专栏文章列表欢迎订阅持续更新...https://blog.csdn.net/chenlycly/article/details/125529931C/C基础与进阶专栏文章持续更新中...https://blog.csdn.net/chenlycly/category_11931267.htmlVC常用功能开发汇总专栏文章列表欢迎订阅持续更新...https://blog.csdn.net/chenlycly/article/details/124272585C软件分析工具从入门到精通案例集锦专栏文章持续更新中...https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术专栏文章持续更新中...https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享专栏文章持续更新中...https://blog.csdn.net/chenlycly/category_2276111.html 软件运行过程中发生的部分崩溃或闪退在软件中安装的异常捕获模块是捕获不到的这种情况下就需要尝试使用Windbg进行动态调试了。前面我们已经讲了Windbg静态分析dump文件的完整过程今天我们就来详细讲述一下如何使用Windbg对目标进程进行动态调试。
1、概述 软件运行过程中发生的大多数崩溃或闪退软件中安装的异常捕获模块比如CrashRpt都能捕获到都会自动生成包含异常上下文的dump文件。我们只需要事后取来dump文件然后用Windbg打开进行静态分析就可以了。 但有少部分崩溃或闪退异常捕获模块是捕获不到的或者是捕获到后产生了二次崩溃没有生成dump文件也就无法使用Windbg进行静态分析了。这个时候就需要使用Windbg的动态调试了。将Windbg附加到目标进程上即Windbg跟着目标进程一起运行一旦目标进程发生异常Windbg能第一时间感知到并中断下来就可以使用kn/kv/kp命令查看到崩溃时的函数调用堆栈就能进行分析排查了。 其实使用Windbg进行动态调试的操作很简单但很多刚入门的新人不太清楚所以我们在此处以一个崩溃实例来详细介绍一下整个操作过程。 关于Windbg的下载安装及详细介绍可以查看我之前写的文章Windbg使用详解https://blog.csdn.net/chenlycly/article/details/120631007 关于Windbg的命令汇总可以查看我之前写的文章
Windbg调试命令汇总https://blog.csdn.net/chenlycly/article/details/51711212
2、将Windbg附加到已经启动起来的目标进程上或者用Windbg启动目标程序 要使用Windbg动态调试要将Windbg关联到目标进程上可以先将程序启动起来然后将Windbg附加到目标进程上也可以用Windbg启动目标程序。两种方式的使用场景略有区别。
2.1、将Windbg附加到已经启动起来的目标进程上 如果目标程序已经启动则可以将Windbg附加到进程上。打开Windbg点击菜单栏File-Attach to a Process...如下所示 在打开的窗口中在进程列表中找到目标程序点击确定完成进程的附加 一般后启动的进程在进程列表最下面。 当程序发生卡死或者弹出系统报错框时再去附加到进程可能也不晚的也能查看到有用的信息。如果客户环境安全保密等级比较高不能远程过去没法使用Windbg去分析可以在此时打开任务管理在进程列表中找到目标进程点击右键在弹出的右键菜单中点击“创建转储文件”菜单项 将进程的全dump文件导出到文件中然后取来这个dump文件再进行分析。关于如何使用Windbg静态分析dump文件我们之前已经讲过了可以查看
使用Windbg静态分析dump文件的一般步骤详解https://blog.csdn.net/chenlycly/article/details/130873143
2.2、用Windbg启动目标程序 有时程序异常崩溃发生在程序启动的过程中在启动程序后再将Windbg附加到进程上就为时已晚了可能程序启动时就崩溃了根本没有机会去附加调试的。当然我们可以在程序初始化时调用MessageBox弹出模态框将程序阻塞住给Windbg附加到进程创造时机。以前我们在讲Visual Studio附加到进程调试时可以使用此方法。对于Windbg动态调试不必这么做的可以直接使用Windbg启动程序的这样就能从程序启动时就去监测程序了。 打开Windbg点击菜单栏File-Open Executable...如下所示 找到目标程序的路径打开目标程序即可。
2.3、Windbg关联到目标进程上会中断下来输入g命令将该中断跳过去 将WIndbg附加到进程上成功或者使用Windbg将目标程序启动起来后Windbg会自动中断一次 输入g命令将此次中断跳过去即可。让Windbg跟着目标进程一起跑如果目标进程运行过程中产生了异常则调试器Windbg会第一时间感知到并中断下来此时可以去查看函数调用堆栈去分析了。 至于为什么将Windbg附加到目标进程成功后会触发一个中断呢原因是 应用层调用DebugActiveProcess发起调试操作系统会触发int 3中断这个中断会分发给当前的调试器WindbgWindbg就产生了一个中断在Windbg中能看到ntdll!DbgBreakPoint函数的调用 3、分析实例说明 为了讲述Windbg动态调试的完整过程我们使用Visual Studio创建了一个基于MFC框架的对话框工程在对话框中添加了一个测试按钮 我们在测试按钮的相应函数中故意添加一段会崩溃的代码如下所示
// 添加的一段测试代码
SHELLEXECUTEINFO *pShExeInfo NULL;
int nVal pShExeInfo-cbSize; // 通过空指针访问结构体成员导致崩溃CString strTip;
strTip.Format( _T(nVal%d.), nVal );
AfxMessageBox( strTip );
代码中使用到的结构体SHELLEXECUTEINFO 定义如下
typedef struct _SHELLEXECUTEINFOW
{DWORD cbSize; // in, required, sizeof of this structureULONG fMask; // in, SEE_MASK_XXX valuesHWND hwnd; // in, optionalLPCWSTR lpVerb; // in, optional when unspecified the default verb is choosenLPCWSTR lpFile; // in, either this value or lpIDList must be specifiedLPCWSTR lpParameters; // in, optionalLPCWSTR lpDirectory; // in, optionalint nShow; // in, requiredHINSTANCE hInstApp; // out when SEE_MASK_NOCLOSEPROCESS is specifiedvoid *lpIDList; // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST SEE_MASK_INVOKEIDLISTLPCWSTR lpClass; // in, valid when SEE_MASK_CLASSNAME is specifiedHKEY hkeyClass; // in, valid when SEE_MASK_CLASSKEY is specifiedDWORD dwHotKey; // in, valid when SEE_MASK_HOTKEY is specifiedunion { HANDLE hIcon; // not used
#if (NTDDI_VERSION NTDDI_WIN2K)HANDLE hMonitor; // in, valid when SEE_MASK_HMONITOR specified
#endif // (NTDDI_VERSION NTDDI_WIN2K)} DUMMYUNIONNAME; HANDLE hProcess; // out, valid when SEE_MASK_NOCLOSEPROCESS specified
} SHELLEXECUTEINFOW, *LPSHELLEXECUTEINFOW;#ifdef UNICODE
typedef SHELLEXECUTEINFOW SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOW LPSHELLEXECUTEINFO;
#else
typedef SHELLEXECUTEINFOA SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOA LPSHELLEXECUTEINFO;
#endif // UNICODE 在测试代码中定义了SHELLEXECUTEINFO结构体指针pShExeInfo并初始化为NULL然后并没有给该指针赋一个有效的结构体对象地址然后使用pShExeInfo访问结构体的cbSize成员的内存因为pShExeInfo中的值为NULL所以结构体cbSize成员的内存地址是结构体对象起始地址的偏移因为结构体对象地址为NULLcbSize成员位于结构体的首位所以cbSize成员就是结构体对象的首地址就是NULL所以就访问64KB小地址内存块的异常引发内存访问违例导致程序发生崩溃闪退。
4、分析测试程序的崩溃
4.1、启动程序将Windbg附加到目标进程上 下面我们就以上面讲到的测试程序为例讲解一下使用Windbg动态调试的完整过程。测试程序如下 在Button1按钮的响应函数中故意添加了一段会引发崩溃的代码代码上面已经给出并进行讲解了。 启动程序后打开Windbg点击菜单栏File-Attach to a Process...在进程列表中找到TestDlg.exe 点击OK按钮即完成附加。 完成附加操作后Windbg会自动中断下来如下所示 目标程序会因Windbg的中断被挂起此时目标程序是没法操作的。此时需要在最下面的命令输入框中输入命令g按下回车键执行该命令让Windbg跳过该中断让目标程序恢复运行。这样目标程序就可以操作了。
4.2、使用Windbg初步分析崩溃 点击程序窗口的Botton1的响应函数即去运行引发崩溃的代码程序产生异常Windbg会感知到异常并中断下来如下所示 从输出的信息中可以看到程序发生了Acess violation内存访问违例的异常并可以看到崩溃时的eax、ebx等各个寄存器中的值并能看到发生崩溃的那条汇编指令。 程序最终是崩溃在某条汇编指令上从汇编指令中我们可以看出是访问了0x0000000内存地址在Windows系统中小于64KB的内存是禁止访问的。这块禁止访问的内存地址是Windows系统故意预留的一块小地址内存区域是为了方便程序员定位问题使用的。一旦访问到该内存区就会触发内存访问违例系统就会强制将进程强制结束掉。 关于64KB禁止访问的小地址内存区域在《Windows核心编程》一书中内存管理的章节有专门的描述相关截图如下所示 4.3、找到相关模块的pdb文件设置到Windbg中 仅仅通过查看崩溃时的各个寄存器的值以及发生崩溃的那条汇编指令是远远不够的我们一般还需要查看崩溃时的函数调用堆栈。 于是我们在Windbg中输入kn命令查看崩溃时的函数调用堆栈如下所示 查看函数调用堆栈的命令除了kn之外还有kv和kp使用kv可以查看到调用函数时的参数信息如下 从函数调用堆栈的最后一帧调用的函数来看程序的崩溃是发生在TestDlg.exe文件模块中不是其他的dll模块。显示的函数地址是相对TestDlg.exe文件模块起始地址的偏移为啥看不到模块中具体函数名称呢那是因为Windbg找不到TestDlg.exe对应的pdb文件pdb文件中包含对应的二进制文件中的函数名称及变量等信息Windbg加载到pdb文件才能显示完整的函数名。 如何才能找到TestDlg.exe文件对应的pdb文件我们可以通过查看TestDlg.exe文件的时间戳找到文件的编译时间通过编译时间找到文件对应的pdb文件。在Windbg中输入lm vm TestDlg*命令可以查看到TestDlg.exe文件的详细信息其中就包含文件的时间戳当前的lm命令中使用m通配符参数所以在TestDlg后面加上了*号 可以看到文件是2023年5月27日17点11分41秒生成的就可以找到对应时间点的pdb文件了。 一般在公司正式的项目中通过自动化软件编译系统每天都会自动编译软件版本并将软件的安装包及相关模块的pdb文件保存到文件服务器中如下所示 这样我们就可以根据模块的编译时间找到对应版本的pdb文件了。 我们找到了TestDlg.exe对应的pdb文件TestDlg.pdb将其所在的路径设置到Windbg中。点击Windbg菜单栏中的File-Symbol File Path...打开设置pdb文件路径的窗口将pdb文件的路径设置进去如下所示 点击OK按钮之前最好勾选上Reload选项这样Windbg就会去自动加载pdb文件了。但有时勾选了该选项好像不会自动去加载我们就需要使用.reload /f TestDlg.exe命令去让Windbg强制去加载pdb文件命令中必须是包含文件后缀的文件全名。 关于pdb符号库文件的说明可以查看我之前写的文章
pdb符号库文件详解https://blog.csdn.net/chenlycly/article/details/125508858 设置完成后我们可以再次运行lm vm TestDlg*命令去看看pdb文件有没有加载进来 如果已经加载进来则会在上图中的位置显示出已经加载进来的pdb文件的完整路径。如上所示。
4.4、加载pdb后查看包含完整信息的函数调用堆栈 加载到TestDlg.exe文件对应的pdb文件之后我们再次执行kn命令就可以包含具体的函数名及及代码的行号信息了如下 0:000 kn # ChildEBP RetAddr 00 009eebf8 785ef632 TestDlg!CTestDlgDlg::OnBnClickedButton10x67 [c:\users\administrator\desktop\testdlg-空指针演示-2\crashdemo_testdlg\testdlg\testdlgdlg.cpp 489] 01 009eec3c 785efd7a mfc100ud0x30f632 02 009eeca0 78649ac3 mfc100ud0x30fd7a 03 009eecdc 78726c54 mfc100ud0x369ac3 04 009eed40 783a977a mfc100ud0x446c54 05 009eed54 78725859 mfc100ud0xc977a 06 009eeec4 787257a2 mfc100ud0x445859 07 009eeee4 78721cf3 mfc100ud0x4457a2 08 009eef64 787222e6 mfc100ud0x441cf3 09 009eef84 7850ad0b mfc100ud0x4422e6 0a 009eefc0 77b8139b mfc100ud0x22ad0b WARNING: Stack unwind information not available. Following frames may be wrong. 0b 009eefec 77b7836a USER32!AddClipboardFormatListener0x4b 0c 009ef02c 77dec81c USER32!GetClassLongW0x7aa 0d 009ef0d0 77b77f6a ntdll!RtlDeactivateActivationContextUnsafeFast0x9c 0e 009ef134 77b7bb2f USER32!GetClassLongW0x3aa 0f 009ef170 77e14f5d USER32!CallNextHookEx0x19f 10 009ef1a8 75ca107c ntdll!KiUserCallbackDispatcher0x4d 11 009ef1ac 77b778cb win32u!NtUserMessageCall0xc 12 009ef210 77b75d8f USER32!GetSystemMetricsForDpi0x15cb 13 009ef230 691e6608 USER32!SendMessageW0x6f 14 009ef250 691e65cd COMCTL32!CCEnableScrollBar0x1028 15 009ef268 69225f33 COMCTL32!CCEnableScrollBar0xfed 16 009ef304 77b8139b COMCTL32!SetWindowSubclass0x3963 17 009ef330 77b7836a USER32!AddClipboardFormatListener0x4b 18 009ef380 77b7b8e9 USER32!GetClassLongW0x7aa 19 009ef414 77b760da USER32!Ordinal27120x1c9 1a 009ef488 77b7a2d8 USER32!DispatchMessageW0x24a 1b 009ef4b8 7875def3 USER32!IsDialogMessageW0x108 我们看到了具体的函数名CTestDlgDlg::OnBnClickedButton1还看到了对应的代码行号489。通过这些信息我们就能到源代码中找到对应的位置了如下所示 是访问了空指针产生的异常。当然上面的代码是我们故意这样写的目的是为了构造一个异常来详细讲解如何使用Windbg进行动态调试跟踪的。
4.5、设置C源代码的路径Windbg会自动跳转到源代码对应的行号上 为了方便查看我们可以直接在Windbg中设置C源码路径这样Windbg会自动跳转到源码对应的位置。点击Windbg菜单栏的File-Source File Path...将源码路径设置进去 然后Windbg会自动跳转到对应的函数及行号上 然后点击函数调用堆栈中每行最前面的数字超链接就可以自动切换到对应的函数中。上图中的函数调用堆栈中很多模块是系统库中的比如mfc100u、User32等这些库是系统库是没有源码的。我们可以点击函数调用堆栈每行前面的序号就会自动跳转到对应的代码中如下
4.6、有时需要查看函数中变量的值 有时我们在排查异常时需要查看函数调用堆栈中某个函数中的变量值去辅助排查。在某些场景下这种操作方式非常有用我们在项目中多次使用过。可以查看函数中局部变量的值也可以查看函数所在类对象的this指针指向的类对象中变量的值。我们要查看哪个函数就点击函数调用堆栈中每一行前面的数字超链接如下所示 我们看到了局部变量pShExeInfo 的值 我们可以点击this对象的超链接就能查看当前函数对应的C类对象中成员变量的值如下 4.7、使用.dump命令导出包含异常上下文的dump文件 比如问题出现在客户的电脑上我们在使用Windbg初步分析后没找出引发崩溃的原因我们不能长时间占用别人的电脑我们可以使用.dump命令将包含异常上下文的信息导出到dump文件中事后让客户将dump文件发给我们我们在公司电脑做进一步分析排查。 使用.dump /ma D:\0604.dmp命令将当前的异常信息保存到D:\0604.dmp文件中命令执行效果如下 会显示dump文件导出成功。 这里有两个概念的区别一个是mini dump文件一个是全dump文件。我们将windbg附加到进程上使用.dump命令导出的dump文件是全dump文件全dump文件中包含了所有的信息可以查看到所有变量的信息。另外通过任务管理器导出的dump文件 也是全dump文件。全dump文件因为包含了所有的信息所以会比较大会达到数百MB甚至上GB的大小。但如果通过安装在程序的异常捕获模块CrashReport导出的dump文件就是非全dump文件是mini dump文件大概只有几MB左右因为异常捕获模块捕获到异常后会自动导出dump文件保存到磁盘上如果都导出体量很大的全dump文件很大量消耗用户的磁盘空间所以我们会设置生成mini dump文件。 在异常捕获模块中我们是通过调用系统API函数MiniDumpWriteDump导出dump文件的我们通过设置不同的函数调用参数去控制生成mini dump文件的。 关于dump文件的分类与dump文件的生成方式可以查看我之前写的文章
dump文件类型与dump文件生成方法详解https://blog.csdn.net/chenlycly/article/details/127991002另外Windbg等工具的下载链接如下 链接https://pan.baidu.com/s/1ID6_0RSYKbiy_tzfYDX3Ew 提取码tn6i 4.8、可以在Windbg中进行断点调试 Windbg中有多个支持断点调试的命令比如 bl用来显示当前设置的断点 bp设置断点 bc清除指定序号的断点。 断点调试是个很重要的功能之前使用过Windbg的断点调试功能解决了多个问题比如我之前写的一篇案例文章
在Windbg中设置断点追踪打开C程序远程调试开关的模块https://blog.csdn.net/chenlycly/article/details/130058430
5、最后 本文详细讲述了使用Windbg动态调试目标进程的一般步骤及完整过程对于C软件调试的初学者来说很有参考价值希望能给大家要提供一些借鉴或帮助。