南昌网站建设制作商,食品包装设计理念,wordpress页面音乐,网站建设技术方案模板下载目录
1、dump文件
1.1、dump文件的生成方式
1.2、dump文件的大小
2、pdb符号文件
2.1、pdb文件的路径设置
2.2、pdb文件的时间戳与名称问题
2.3、如何确定要找哪些pdb文件#xff1f;
3、使用Windbg静态分析dump文件以及动态调试程序的一般步骤
4、确定发生异常或崩溃…目录
1、dump文件
1.1、dump文件的生成方式
1.2、dump文件的大小
2、pdb符号文件
2.1、pdb文件的路径设置
2.2、pdb文件的时间戳与名称问题
2.3、如何确定要找哪些pdb文件
3、使用Windbg静态分析dump文件以及动态调试程序的一般步骤
4、确定发生异常或崩溃的业务模块到业务模块的函数中去排查
5、在分析从任务管理器中导出的dump文件时可能需要使用.effmach命令切换一下上下文
5.1、操作系统位数与程序位数
5.2、使用.effmach命令将线程上下文切换到32位
6、Windbg动态调试目标进程时遇到因为调用了IsBadWritePtr或者IsBadReadPtr引发的异常
7、什么时候使用Windbg静态分析什么时候使用Windbg动态调试
7.1、程序发生死循环或死锁问题时
7.2、程序发生异常但异常捕获模块没有捕获到
7.3、异常捕获模块感知到了异常但导出dump文件时产生了二次崩溃dump文件生成失败
7.4、程序运行过程中检测到不正常直接调用abort函数强制结束进程导致程序闪退
7.5、用IDE调试程序时产生异常但看不到有效的函数调用堆栈可以尝试使用Windbg进行动态调试
7.6、程序启动崩溃或失败时
7.7、程序弹出报错提示框时
8、有时可能需要使用反汇编工具IDA查看汇编代码上下文去辅助定位问题
9、熟悉Windbg命令
10、最后 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是微软提供的Windows平台上强大调试器既可以静态分析dump文件也可以动态调试目标程序是排查Windows平台软件异常的利器很好用的问题分析工具。本文根据多年使用Windbg遇到的坑与经验心得给大家完整地总结一下使用Windbg的诸多细节与技巧以供大家借鉴和参考。 1、dump文件 dump文件一般是软件发生异常时导出的包含程序进程异常上下文信息的文件可以在dump文件中查看到发生异常的那条汇编指令及异常发生时的各个寄存器的值也可以查看各个线程信息以及线程的函数调用堆栈甚至可以查看到程序进程内存中相关变量的值。 dump文件是分析软件异常的重要依据和来源大部分情况下的软件异常都是事后使用Windbg静态分析dump文件去排查的。
1.1、dump文件的生成方式 那dump文件是如何生成的呢一般都是调用系统API函数MiniDumpWriteDump生成的。生成dump的方式主要有三种 1通过程序中安装的异常捕获模块去自动生成dump文件。这是生成dump文件最常见、最高效的方式很多软件都会内置异常捕获模块当程序发生异常时异常捕获模块能自动感知到并自动生成dump文件。 那异常捕获模块该如何实现呢一般不用我们自己去实现可以选择开源的CrashRpt、CrashPad和BreakPad稍微改造一下就可以集成到我们的软件中。2从任务管理器中导出dump文件。当程序发生死循环、死锁等卡死问题时或者程序弹出报错提示框时程序进程还在的这点和异常崩溃闪退的场景不同发生崩溃后程序进程就不在了此时可以选择打开系统任务管理器在进程列表中找到目标进程然后右键点击之在弹出的右键菜单中点击“创建转储文件” 即可导出dump文件。3从正在调试的Windbg中使用.dump命令导出dump文件。在程序中安装异常捕获模块去捕获异常只能感知到大部分异常还是有少部分场景捕获不到或者在导出dump时产生了二次崩溃所以也就没有生成dump文件。此时就需要使用Windbg的动态调试了。把Windbg附加到目标进程上和目标进程一起跑一旦程序发生异常调试器Windbg会第一时间感知到并中断下来然后就可以进行分析了。如果一时半会分析不出来问题可以使用.dump命令将进程上下文信息导出到dump文件中。 1.2、dump文件的大小 dump文件一般分小的mini dump文件和大的全dump文件。可以通过设置生成dump文件的API函数MiniDumpWriteDump参数去控制dump文件的大小。一般通过异常捕获模块自动生成的dump文件可能会很频繁这些文件是保存在用户电脑磁盘上此外可能还要考虑到自动上传到运维服务器上所以dump文件不宜太大一般在几百KB到几MB左右。比如可以给MiniDumpWriteDump函数设置如下的参数这样生成的dump文件最多大概几MB左右
HANDLE hDumpFile;
hDumpFile CreateFile(sFile, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);MINIDUMP_EXCEPTION_INFORMATION ExpParam;
ExpParam.ThreadId GetCurrentThreadId();
ExpParam.ExceptionPointers pExceptionPointers;
ExpParam.ClientPointers TRUE;MINIDUMP_TYPE MiniDumpWithDataSegs (MINIDUMP_TYPE)(MiniDumpNormal | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory | MiniDumpWithProcessThreadData | MiniDumpWithThreadInfo);BOOL bMiniDumpSuccessful MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hDumpFile, MiniDumpWithDataSegs, ExpParam, NULL, NULL); 从任务管理器中导出的以及从动态调试的Windbg中导出的都是全dump文件包含了进程的所有内存信息dump文件的大小比较接近程序进程占用的虚拟内存大小。程序占用的虚拟内存用户态的虚拟内存在Windows任务管理器中看不到可以使用Process Explorer工具查看这点我们已经讲过多次了特别是在排查内存泄漏问题时会用到。 有时我们在用Windbg分析dump文件时除了要查看崩溃时的函数调用堆栈可能还要查看堆栈中的函数中的变量值比如函数中局部变量的值、函数所在类的成员变量的值这些值可能是排查问题的关键线索我们在项目中多次遇到了 要查看变量的值得有变量的符号所以要加载相关模块的pdb文件pdb文件中包含了函数、变量等符号信息。mini dump文件比较小只包含了部分变量的内存信息能不能查看到想查看的变量的值需要看运气的。而全dump文件包含了进程所有的内存信息可以查看所有变量的值。可以在展开调用堆栈中的函数时查看变量的值也可以使用x命令去搜索变量比如查看某个模块中的某个全局变量的值 x mediasdk!g_pMainLogic 其中mediasdk是不带后缀名的模块名g_pMainLogic是该模块中的全部变量的名称符号。 关于dump文件的详细说明也可以参看我之前写的文章
dump文件类型与dump文件生成方法详解https://blog.csdn.net/chenlycly/article/details/127991002
2、pdb符号文件 PDB-Program Databse File程序数据库文件存放了二进制文件中所有函数及变量的符号还有一些调试用的信息要查看完整的函数调用信息及变量信息都需要用到pdb文件。pdb文件是在编译工程时产生的它是和对应的模块exe或dll一起生成出来的。在Visual Studio中不管是Debug还是Release下默认都会生成pdb文件相关的配置选项如下 此外本地程序之所以能调试是因为其二进制文件中在本地编译生成时会自动写入对应的pdb文件的绝对路径而pdb文件中存放着用于调试的各种调试信息启动调试时调试器会根据文件中记录的pdb文件路径去加载pdb文件去获取pdb文件中的调试信息。如果手动将pdb删除在没有重新生成的情况下肯定是无法调试的。 要在Windbg中查看函数调用堆栈中的具体函数名及代码的行号以及查看变量的值都需要使用到pdb符号文件。为了方便日后排查问题不同时间点、不同版本的pdb文件要统一维护起来比如我们的自动化编译系统每天会去自动版本然后将各个模块编译生成的pdb文件都拷贝到文件服务器上维护起来如下所示不同时间点的文件放置在不同的文件夹中以方便后期查找 加载pdb符号文件后不仅能在函数调用堆栈中看到具体的函数名和行号甚至有时还会显示多几行的函数调用在实际项目中遇到过这对于问题的分析很有好处。
2.1、pdb文件的路径设置 要让Windbg去加载pdb文件则需要将pdb文件的路径设置给Windbg。在使用Windbg分析问题时会涉及到两类pdb文件一类是我们写的业务模块的pdb文件一类是操作系统的系统库pdb文件。对于我们的业务模块的pdb文件需要根据对应模块的时间戳到保存pdb文件的地方去找对于系统库的pdb文件可以直接在Windbg中设置微软系统库pdb在线服务器下载地址Windbg会根据需要去服务器上自动下载pdb文件的。 点击Windbg菜单栏中的File - Symbol File Path ...打开设置pdb文件路径的窗口如下所示 一般我们设置如下格式的pdb组合文件路径 C:\Users\Administrator\Desktop\pdbdir; srv*f:\mss0616*http://msdl.microsoft.com/download/symbols 这么个一长串组合路径主要由下面两个路径构成路径之间使用分号隔开 1应用程序库的pdb文件路径非系统库 C:\Users\Administrator\Desktop\pdbdir。我们开发的业务模块的pdb文件集中拷贝到该路径中路径名称可以随意设置。 2Windows系统库的pdb文件在线下载路径 srv*f:\mss0616*http://msdl.microsoft.com/download/symbols其中http://msdl.microsoft.com/download/symbols是微软提供的在线系统pdb文件下载服务器放置在公网上大家都可以访问。如果设置了该地址Windbg会自动连接该服务器去自动下载与当前dump文件中用到的系统库版本一致的pdb文件。另外f:\mss0616路径是从微软pdb文件服务器上下载下来的pdb文件在本地机器上的存放路径。 这里需要注意一下有时微软这个服务器会有连接不上或卡顿的情况会直接导致Windbg卡顿。所以遇到Windbg比较安顿的时候可以先将该地址删除掉。但有时我们需要设置该在线地址因为有时我们想去看到底是调用了系统库中的哪个接口触发的崩溃。 为啥要加载系统库的pdb文件呢是为了在函数调用堆栈中看到系统模块中的具体函数名称甚至加载系统pdb文件后可以看到多一两行的函数调用有时系统模块的具体函数调用可能是比较关键的线索我们在项目中多次使用到。 对于dll模块其导出函数的符号对外是公开的可识别的dll模块内部函数对外是不可见的要在函数调用堆栈中看到具体的函数名则需要加载pdb文件pdb文件中包含了所有的函数符号。 2.2、pdb文件的时间戳与名称问题 加载pdb文件是严格校验时间戳文件的生成时间的即使两次编译的代码没有修改两次编译出来的pdb文件都不能交叉使用的。Windbg在加载pdb文件时会严格校验pdb文件的时间戳是否和对应模块一致的如果不一致会加载失败。 此外pdb文件的名称不能随意改动pdb文件名称必须和Visual Studio工程的名称一致否则也会加载失败我们在实际项目中遇到过。比如工程名为videocodec_hp.vcxproj手动将生成的pdb文件的hp后缀去掉即videocodec.pdb会加载失败解决办法很简单将pdb名称改成与工程名称一样的就可以了。
2.3、如何确定要找哪些pdb文件 其实很简单只要根据函数调用堆栈中显示的模块名去找就可以了。但一般不需要去找堆栈中所有模块的pdb文件一般只需要在堆栈中找离崩溃点最新的一两个模块就可以了。当然你想看整个函数调用堆栈中的函数名称则去找堆栈中所有模块的pdb文件。 要找函数调用堆栈中模块的pdb文件先用lm命令查看模块的时间戳生成时间比如 上述命令中的vm是lm命令的参数具体含义可以到Windbg的帮助文档中查看lm命令的说明此处就不再赘述了。通过二进制文件的生成时间到文件服务器上去查找对应时间点的pdb文件事先已经将各个时间点和版本的pdb文件统一放在服务器维护了然后将pdb拷贝到本地电脑上然后将路径设置到Windbg中即可。 注意设置路径时要勾选reload选项 这样Windbg会去自动加载pdb文件。有时可能Windbg会自动加载失败我们需要使用.reload命令去强制加载比如 .reload /f mediasdk.dll 参数/f表示强制加载让Windbg到设置的pdb文件路径中去强制加载pdb。注意该命令中的模块名必须带后缀名且不能带完整的路径。如果pdb文件时间戳不对即使强制加载也会加载不成功因为加载时会严格校验pdb文件与二进制文件的时间戳。使用.reload命令去强制加载只是解决Windbg自动加载pdb失败的问题。 如何确定pdb文件有没有加载成功呢其实很简单只需要重新执行一下lm命令如果加载pdb文件加载成功会将pdb文件的路径显示出来如下所示 如果pdb文件没加载成功则不会显示pdb文件的路径即没看到pdb文件的路径则表示该模块没有加载pdb文件。
3、使用Windbg静态分析dump文件以及动态调试程序的一般步骤 使用Windbg分析软件异常主要有两种方式一种是使用Windbg静态分析dump文件一种是将Windbg附加到目标进程上进行动态调试。初学使用Windbg分析软件异常问题时一般需要了解Windbg静态分析dump文件的一般步骤、了解使用Windbg动态调试目标进程的一般步骤这对于尝试使用Windbg分析问题的初学者很重要。我之前已经写了两篇文章详细介绍这方面内容在此就不再赘述了。 关于使用Windbg静态分析dump文件的一般步骤可以参看我的文章
使用Windbg静态分析dump文件的一般步骤及要点详解https://blog.csdn.net/chenlycly/article/details/130873143 关于使用Windbg动态调试目标进程的一般步骤可以参看我的文章
使用Windbg动态调试目标进程的一般步骤及要点详解https://blog.csdn.net/chenlycly/article/details/131029795
4、确定发生异常或崩溃的业务模块到业务模块的函数中去排查 根据发生异常的那条汇编指令及当时的函数调用堆栈可以确定发生异常的模块。如果异常发生在我们的业务模块中则直接到业务模块中去排查。比如下图 崩溃在业务模块mediasdk.dll的函数中直接到业务模块mediasdk中去排查。 如果异常发生在操作系统的系统库一般系统库是不会有问题的一般都是上面的业务库在调用系统库接口时有问题比如传入了异常的内存地址、传入了无效的参数等。此时需要沿着函数调用堆栈网上看还是要到上面的业务模块中找问题。比如下图 虽然崩溃在系统运行时库ucrtbased.dll中但该系统库本身没问题是上面的mediasdk.dll中在调用系统运行时库ucrtbased.dll接口时传入了有问题的参数导致的。
5、在分析从任务管理器中导出的dump文件时可能需要使用.effmach命令切换一下上下文 此处给大家讲一个场景要分析的dump文件可能是从Windows任务管理器中导出的要分析的目标程序是32位的且当前操作系统是64位的在静态分析dump文件查看函数调用堆栈之前可能需要使用.effmach x86 命令将上下文切换到32位后才能看到有效的函数调用堆栈这点我们在项目中遇到过。
5.1、操作系统位数与程序位数 现在普遍的使用的Windows操作系统都是64位的比如Win10和Win11只有少部分系统是32位的比如部分XP和Win7系统但这些系统已经很少用了。64位操作系统是支持32位程序的即32位程序可以在64位系统中运行但32系统中时不能运行64位程序的。 很多软件为了既能在32位系统中运行也能在64位系统中运行就直接做成32位程序。当然有些软件也做了两个版本即32位版本和64位版本用户可以根据自己操作系统的位数选择对应的版本去安装。 这里要说明一下32位二进制文件是不能和64位二进制文件混用的比如两个有依赖关系的dll库位数不同基本数据类型的占用的长度不同寻址范围也不同所以不能混用的。如果混用程序启动时会报错的。 程序会依赖系统库程序启动时会将依赖的系统库加载到进程空间中。操作系统为了同时支持32位程序和64位程序分别搞了两套系统库即32位版本系统库位于C:\Windows\SysWOW64路径下和64位版本系统库位于C:\Windows\System32路径下。 关于WOW64的解释 WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows. 简而言之就是32程序运行在64位系统上。 5.2、使用.effmach命令将线程上下文切换到32位 如果32位程序运行在64位操作系统上从任务管理器中导出该32位程序的dump文件用Windbg打开dump文件后输入kn命令查看函数调用堆栈可能会看到一堆“驴头不对马嘴”的函数调用信息比如 堆栈中的函数好像都是系统函数和我们的业务模块没有一点关系。 遇到这种情况就需要使用.effmach X86命令将当前的上下文切换到32位上下文然后重新输入kn就能看到正常的函数调用堆栈了如下 6、Windbg动态调试目标进程时遇到因为调用了IsBadWritePtr或者IsBadReadPtr引发的异常 系统API函数IsBadWritePtr和IsBadReadPtr已经实现不了指定的内存检测功能检测内存是否可读或可写这两个函数已经被Windows官方废弃了 但有些比较老的库可能还在使用这两个API函数。比如我们软件使用的某个第三方dll库中就调用了这两个函数。 在使用Windbg动态调试目标进程中可能会遇到因为调用了IsBadReadPtr或IsBadWritePtr异常中断了下来如下所示 如果要查看是哪个模块调用了IsBadReadPtr或IsBadWritePtr此时直接输入kn命令查看函数调用堆栈就可以看到了如下 这个异常虽然会引发Access violation内存访问违例异常但这个异常不是致命性并不会导致程序崩溃可以输入g命令将当前的异常给跳过去这样Windbg可以继续调试运行。大家在使用Windbg动态调试如果遇到因为这两个函数的调用引发的异常中断则直接输入g命令直接跳过去。 在调试我们的软件时就会遇到这样的异常中断所以对这个异常专门研究了一下并写了相关的记录文章
使用Windbg排查C程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题https://blog.csdn.net/chenlycly/article/details/129892952
7、什么时候使用Windbg静态分析什么时候使用Windbg动态调试 使用Windbg分析软件异常主要有两种方式一种是使用Windbg静态分析dump文件一种是将Windbg附加到目标进程上动态调试两种方式在使用场景上是有一些差异的。 使用Windbg静态分析dump文件是排查软件异常的主要方式。有dump文件时则优先使用Windbg静态分析dump文件如果现有dump文件不足以查出问题或者没有生成dump文件时则需要使用动态调试。下面我们着重看一下哪些场景需要使用动态调试主要看没有生成dump文件的场景。
7.1、程序发生死循环或死锁问题时 当程序运行过程中发生死循环或者死锁时导致线程发生堵塞但程序并没有发生异常崩溃所以不会生成dump文件也就无法使用Windbg进行静态分析的此时可以使用Windbg进行动态调试。动态调试时可以查看各个线程信息可以查看各个线程的函数调用堆栈可以查看相关变量的值可以设置断点进行调试等。 对于UI客户端程序如果死循环或死锁发生在UI主线程中则会直接导致UI主线程的堵塞就会导致UI界面无法操作的问题这样的问题我们在项目中都遇到过。之前写过一个使用Process Explorer和Windbg排查死循环的实例感兴趣的朋友可以去看一下
使用 Process Explorer 和 Windbg 排查软件线程堵塞案例分享https://blog.csdn.net/chenlycly/article/details/135361532
7.2、程序发生异常但异常捕获模块没有捕获到 程序中安装的异常捕获模块并不能捕获到所有场景下的异常有少部分异常是捕获不到的。捕获不到的自然就不会生成dump文件也就没法使用Windbg进行静态分析了。我们在日常项目中也时常会遇到这类场景程序在使用过程中发生闪退或崩溃异常捕获模块没捕获到没有生成dump文件。 一般遇到这类情况都会让测试人员将Windbg附加到目标进程上和目标进程一起跑一旦目标进程在运行过程中发生异常Windbg会第一时间感知到并中断下来此时就可以进行分析了。可以查看发生异常的汇编指令信息并查看此时的函数调用堆栈。
7.3、异常捕获模块感知到了异常但导出dump文件时产生了二次崩溃dump文件生成失败 程序发生了异常异常捕获模块感知到了但在导出dump文件的过程中产生了二次崩溃生成dump文件失败这种情况下也需要使用Windbg进行动态调试。这个场景我们在项目中也遇到过多次。
7.4、程序运行过程中检测到不正常直接调用abort函数强制结束进程导致程序闪退 如果程序在运行过程中监测到不正常直接调用abort函数强制将进程终止了这样给人一种程序发生崩溃闪退的感觉。其实这种情况并没有发生C异常只是调用abort函数直接将进程终止了异常捕获模块也是感知不到的所以也不会产生dump文件。 比如在开源jsoncpp库中如果解析的json节点的类型不匹配会被jsoncpp内部检测到会触发abort函数的调用相关代码截图如下 再比如WebRTC开源库中在监测到malloc动态申请内存失败后也会触发abort函数的调用强行终止进程。估计是因为动态申请内存失败了相关业务无法正常展开了程序活着也没意思了所以就强行终止进程了。相关代码截图如下 上述代码在调用abort函数之前会先调用DebugBreakDebugBreak接口仅仅是让正在调试的调试器中断下来这样我们就有机会感知可能出的问题了。除了DebugBreak接口会让调试器中断下来abort函数内部也会让调试器中断下来具体原因下面会详细讲到 上述两类问题我们在实际项目中都遇到过。遇到这类情况也可以将Widnbg附加到目标进程上进行动态调试尝试着去复现问题。如果程序调用abort函数就会触发Windbg中断下来然后查看函数调用堆栈通过函数调用堆栈就知道是什么函数调用触发的abort函数的调用的。 那为什么调用abort函数会让正在调试的调试器Windbg中断下来呢因为abort函数内部会raise产生一个SIGABRT信号终止异常如果当前正在调试状态会让调试器中断下来。abort函数的内部实现源码如下所示
/***
*void abort() - abort the current program by raising SIGABRT
*
*Purpose:
* print out an abort message and raise the SIGABRT signal. If the user
* hasnt defined an abort handler routine, terminate the program
* with exit status of 3 without cleaning up.
*
* Multi-thread version does not raise SIGABRT -- this isnt supported
* under multi-thread.
*******************************************************************************/
void __cdecl abort (void)
{_PHNDLR sigabrt_act SIG_DFL;#ifdef _DEBUGif (__abort_behavior _WRITE_ABORT_MSG){/* write the abort message */_NMSG_WRITE(_RT_ABORT);}
#endif /* _DEBUG *//* Check if the user installed a handler for SIGABRT.* We need to read the user handler atomically in the case* another thread is aborting while we change the signal* handler.*/sigabrt_act __get_sigabrt();if (sigabrt_act ! SIG_DFL){raise(SIGABRT);}/* If there is no user handler for SIGABRT or if the user* handler returns, then exit from the program anyway*/if (__abort_behavior _CALL_REPORTFAULT){_call_reportfault(_CRT_DEBUGGER_ABORT, STATUS_FATAL_APP_EXIT, EXCEPTION_NONCONTINUABLE);}/* If we dont want to call ReportFault, then we call _exit(3), which is the* same as invoking the default handler for SIGABRT*/_exit(3);
} 关于调用abort函数强行终止进程场景的详细说明可以参见我之前写的文章
C程序中执行abort等操作导致没有生成dump文件的问题案例分析https://blog.csdn.net/chenlycly/article/details/129003869
7.5、用IDE调试程序时产生异常但看不到有效的函数调用堆栈可以尝试使用Windbg进行动态调试 如果使用IDE比如Visual Studio调试代码的过程中产生了异常但在Visual Studio中看不到完整的或者有效的函数调用堆栈分析不出来问题比如刚启动调试时就产生异常或者报错可以尝试着使用Windbg启动程序或者将Windbg附加到已经启动的程序进程上进行动态调试分析。
7.6、程序启动崩溃或失败时 当程序启动崩溃闪退或因为某些原因启动失败时可以尝试使用Windbg启动程序进行动态调试。可能Debug下不好复现也可能即使能复现用IDE调试有可能也不太方便。有可能问题只在客户机器上才会出现没法到客户机器上使用IDE比如Visual Studio调试代码。 安装IDE可能会需要几个小时的时间可能还需要联网在线安装比较耗时。此外客户是否允许在其机器上安装软件还是个未知数。 这些场景下的问题使用Windbg去动态调试分析很方便。 一般双击程序后没反应程序没有启动起来程序可能也没弹出报错提示框一般都是程序启动过程中发生崩溃导致的。我们最近就遇到过这样的问题可以参见我之前的文章VX交流群中也有朋友遇到类似的问题 程序启动时访问了未初始化的类指针引发内存访问违例导致程序崩溃的问题排查文章浏览阅读1w次点赞129次收藏110次。程序启动时访问了未初始化的类指针引发内存访问违例导致程序崩溃的问题排查_每次当我试图访问一个未初始化的指针或者越界访问内存时,程序就会崩溃,https://blog.csdn.net/chenlycly/article/details/134871805 7.7、程序弹出报错提示框时 程序在运行过程中出现异常弹出报错提示框此时进程还在此刻将Windbg附加到进程上还来的及可以直接分析。可能问题很难复现错过了就很难复现了所以要及时地将Windbg附加到进程上分析。即使一时半会分析不出原因也可以将进程上下文导出到dump文件中事后再去分析。
8、有时可能需要使用反汇编工具IDA查看汇编代码上下文去辅助定位问题 有时将现有的函数调用堆栈与C源码对照看很难排查出问题时可能需要借助IDA工具去查看发生崩溃的那条汇编指令的上下文。汇编指令才能最本真最直接地反映出为什么会发生崩溃将汇编代码上下文与C源码对照起来去看借助源码去读懂汇编代码上下文然后根据汇编上下文推断出那句C代码有问题。在阅读发生崩溃的那条汇编指令的上下文时很难直接去阅读汇编代码如果直接去阅读则需要很深的汇编功底和逆向分析能力需要借助汇编代码中的注释需要与C源码对照着看进而去搞懂汇编上下文的含义。 这里需要注意一下生成的Release版本的软件中编译器可能会对C源码进行优化会导致汇编代码可能较难和C代码完全对应起来。比如C源码中有个函数调用编译器直接将函数调用优化掉用几句汇编代码替代了在汇编上下文中看不到调用函数的call指令。之所以要将函数调用优化掉是为了较少函数调用的开销比如参数的入栈与出栈、函数调用时的保护现场与恢复现场等提升代码的执行效率这也正是编译器优化代码的初衷。 比如一个if判断中有多个条件判断 if ( A B C D) 其中A、B、C、D代表不同的表达式包含函数调用的返回值从崩溃堆栈看直到代码崩溃这一行C代码行上但没法确定是崩溃在那个表达式上此时可以通过查看汇编代码去分析去确定哪个表达式出现了异常。 再比如我之前给安卓移动开发组排查的一个崩溃问题是崩溃在底层的C库中安卓系统生成了TombStone崩溃日志文件但该文件中函数调用堆栈只显示了相对于函数的偏移但没有显示具体的行号 即只知道崩溃在这个函数中但不知道具体崩溃在哪一行代码上。后来想到可以使用IDA查看汇编代码上下文和C源码对应起来看看崩溃在哪一行C代码上。用IDA打开发生崩溃的.so动态库文件后来根据TomStone文件中显示的相对函数的偏移找到对应的位置然后根据汇编代码上下文找到了崩溃的那条汇编指令对应的C代码行最终定位了问题。这个案例很有代表性我也写了文章记录了问题的完整排查过程感兴趣的朋友可以去看看
使用IDA查看汇编代码结合安卓系统生成的Tombstone文件分析安卓app程序崩溃问题https://blog.csdn.net/chenlycly/article/details/132283582 此外这个安卓平台的案例中的.so文件是在安卓ARM64平台上编译的老版本的IDA6.1是不识别的没法查看到汇编代码需要使用7.0及以上的IDA才能正常打开我之前也写文章记录了这个问题感兴趣的话可以去看一下
Relocations for this machine are not implementedIDA版本过低导致生成汇编代码失败https://blog.csdn.net/chenlycly/article/details/135076536
9、熟悉Windbg命令 在Windbg中要查看相关信息需要输入Windbg命令去查看所以要熟悉.excr、kn/kv/kp、lm、.relaod、.dump等常用的命令可以到我的文章中查看
Windbg常用命令详解https://blog.csdn.net/chenlycly/article/details/125508027 也可以去大概地了解一下Windbg都有哪些命令可以查看我写的Windbg命令汇总
Windbg调试命令汇总https://blog.csdn.net/chenlycly/article/details/51711212 虽然很多命令在日常工作中很少用到但在个别场景下可能会用到可以大概地了解一下Windbg都支持哪些命令在需要使用的时候再来详细查阅 关于命令及支持的参数的详细说明可以查看Windbg的帮助文章。在Windbg中在菜单栏中点击Help - Index打开chm格式的帮助文档可以在帮助文档中输入命令查看命令的详细说明及命令支持的参数。以.dump命令为例如下所示 输入命令过程中会自动匹配到相关的记录双击其中的条目即可跳转到命令的详细说明页面。
10、最后 本文根据近几年使用Windbg分析软件异常时的使用经验与心得详细总结了使用Windbg过程中的诸多细节与技巧希望能给大家提供一个借鉴或参考。希望大家在了解这些内容之后能够有效地避坑提高使用工具的效率。