【C++软件调试技术】C++软件开发维护过程中典型调试问题的解答与总结

news2024/9/24 7:16:47

目录

1、引发C++软件异常的常见原因有哪些?

2、排查C++软件异常的常用方法有哪些?

3、为什么要熟悉常见的异常内存地址?

4、调试时遇到调用IsBadReadPtr或者IsBadWritePtr引发的异常,该如何处理?

5、如何排查GDI对象泄露问题?

6、如何排查内存泄露问题?

7、如何排查死循环(高CPU占用)问题?

8、如何排查数据格式化时的崩溃问题?

9、如何排查堆内存被破坏问题?

10、如何排查线程堵塞或卡死问题?

11、如何排查程序中的资源泄露问题?

12、如何排查第三方库注入引发的异常问题?

13、如何排查库与库之间不匹配问题?

14、如何排查程序启动异常(启动报错、崩溃、卡死)问题?

15、使用Windbg分析软件异常有哪些方式?

16、为什么有的异常捕获不到?

17、常用的开源异常捕获库有哪些?

18、异常捕获库捕获不到异常时,该怎么办?

19、生成dump文件的方式有哪些?

20、为什么要加载pdb文件?为什么要加载系统库的pdb文件?


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html
       最近在C++软件调试交流群中,很多人问了开发维护过程中遇到的多个调试问题,这两天正好有时间,对这些常见的问题进行一个梳理和解答。本文以问答的方式进行展开,罗列了C++软件日常开发和维护中遇到的多个软件调试问题及有代表性的场景,给出详细的处置思路和处理办法,以供大家借鉴和参考!希望大家在了解这些内容以后,能从容地应对开发维护过程中遇到的各种问题。

1、引发C++软件异常的常见原因有哪些?

       引发C++软件异常的常见原因有:访问空指针与野指针、内存越界(栈内存越界、堆内存越界和全局内存越界)、内存访问违例、线程栈溢出、堆内存被破坏、内存泄露、死循环、多线程死锁、待格式化参数与格式化符号不匹配、库与库之间的不匹配等。

       我之前根据多年的C++软件异常排查实践,对这些引发C++软件异常的常见原因进行了详细总结,可查看文章:

引发C++软件异常的常见原因分析与总结(实战经验分享)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124996473了解这些常见原因之后,我们在排查问题时可能会快速找到可疑点和排查方向,能有限地提高我们排查问题的效率!

2、排查C++软件异常的常用方法有哪些?

       了解引发C++软件异常的常见原因之后,我们还要掌握排查C++软件异常的常用手段与方法。

       排查问题的常用方法有:使用常用工具去辅助分析(比如程序启动失败、启动报错、库加载失败、死循环与高CPU占用问题等)、使用IDE开发工具调试(Debug调试、Release调试和附加到进程调试)、添加打印日志、分块注释代码、数据断点监测内存、历史版本比对法、Windbg分析(静态分析dump文件、动态调试目标进程)、使用反汇编工具IDA查看汇编代码辅助分析等。

       我之前根据多年的C++软件异常排查实践,对这些排查手段和方法进行了详细的总结,可查看文章:

排查C++软件异常的常见思路与方法(实战经验总结)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/120629327掌握这些排查软件异常的常用手段与方法之后,在遇到新的问题时我们的排查思路会更开阔、更高效,必要时需要将多种排查方法结合起来使用。


         在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量已达到420多个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据近几年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的实战问题分析实例,带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术!


3、为什么要熟悉常见的异常内存地址?

       一般我们只需要了解0xcccccccc、0xcdcdcdcd、0xfeeefeee和0xdddddddd这4个内存地址异常值:

当我们调试代码时遇到这些内存地址异常值后,可以大概知道是什么原因引起的,以这个为线索,就可以迅速地分析并定位问题。

        对于0xcccccccc和0xcdcdcdcd,在 debug 模式下,Visual Studio会把未初始化的栈内存全部填充成0xcccccccc,当成字符串看就是“烫烫烫烫……”;Visual Studio会把未初始化的堆内存全部填充成 0xcdcdcdcd,当成字符串看就是 “屯屯屯屯……”。这两类特殊的字符串,很多人应该都见到过。所以在debug调试时遇到有变量的值为0xcccccccc 或0xcdcdcdcd,一般是变量没有初始化引起的。

        对于0xfeeefeee,是Debug下用来标记堆上已经释放掉的内存,即已经释放的堆内存中会被填充成0xfeeefeee。注意,如果指针指向的内存被释放了,指针变量本身的地址是没做改变的,还是其之前指向的内存的地址,只是其指向的堆内存中被填充成0xfeeefeee。

        对于0xdddddddd,是Debug下用来标记堆上已经释放掉的内存,即已经释放的堆内存会被填充成0xdddddddd。0xfeeefeee也是Debug下用来填充已经释放的堆内存,但0xdddddddd和0xfeeefeee的使用场景应该是有区别的,具体区别我也不太清楚。

之前在项目问题中看到的基本都是0xfeeefeee,没见到过0xdddddddd,但前段时间在Debug下调试代码时遇到了,代码中访问了已经释放的内存,内存中都被置为0xdddddddd,这还是第一次遇到0xdddddddd异常值!正是通过0xdddddddd的说明,得知这个0xdddddddd是用来填充已经释放的堆内存,以这个为线索,快速地定位了问题!

        关于上述异常地址的详细说明,可以参见文章:

C++ 中常见异常内存地址的说明(0xcccccccc、0xcdcdcdcd、0xfeeefeee 和 0xdddddddd 等)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128285918

4、调试时遇到调用IsBadReadPtr或者IsBadWritePtr引发的异常,该如何处理?

       IsBadReadPtr和IsBadWritePtr最开始是为了判断内存地址是否是可读可写的,但这两个API函数已经被官方废弃了,已经不再具有最开始那种判断作用了,强烈建议大家不要再使用这两个API函数!

       一些老的代码中可能还会调用IsBadReadPtr和IsBadWritePtr,比如我们项目中调用了一个第三方的dll库,这个库是好几年前的版本。我是怎么知道第三方库中调用了IsBadReadPtr和IsBadWritePtr函数的呢?看了我接下来说的内容就知道了!

       当代码执行到IsBadReadPtr和IsBadWritePtr函数调用的地方会产生一个异常,如果当前正在调试代码,则会让调试器中断下来。比如我们在用Visual Studio调试代码或者正在使用Windbg动态调试程序,会让调试器Visual Studio或Windbg中断下来。

        程序产生异常,如果在调试状态下,都会让调试器中断下来,怎么知道是调用IsBadReadPtr和IsBadWritePtr的呢?其实很简单,调试器中断下来后直接查看此时的函数调用堆栈就知道了,堆栈中能看到这两个函数的调用。

        当我们使用Visual Studio或者Windbg调试时,代码执行到IsBadReadPtr和IsBadWritePtr调用处,会抛出一个异常,调试器中断下来,没有经验的人以为程序产生崩溃了,其实不然,这个异常是非致命性的,可以跳过去,程序还可以继续运行。

异常根据严重程度可分为致命性异常和非致命性异常。致命性异常是不可恢复的,会导致程序发生崩溃闪退。非致命性的异常,则是可以跳过去的,程序可以继续运行,不会导致程序的崩溃和闪退。

       如果在用Visual Studio调试代码遇到这个异常中断,按下F5可以将异常中断跳过去。如果是在用Windbg调试目标进程,则输入命令g就可以将异常中断跳过去。注意,如果代码中多次调用了IsBadReadPtr和IsBadWritePtr,则需要多次跳过去。

       之前我写过关于IsBadReadPtr和IsBadWritePtr相关案例的文章,需要的话,可以去查看:

使用Windbg排查C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/129892952

5、如何排查GDI对象泄露问题?

       所谓的GDI对象泄露,就是GDI对象使用完成后没有释放,导致泄露。在Windows系统中,一个进程的GDI对象总数为1万个,当进程的GDI对象总数接近或达到这个上限,则会导致GDI绘图失败,甚至引发程序崩溃。

       GDI对象泄露在UI程序编程中经常遇到,如果存在GDI对象泄露,在Windows任务管理器中可以看到GDI对象总数在持续的上涨。但任务管理器中看不到具体是哪一种GDI对象在不断增长。可以使用GDIView工具,可以看到给类GDI对象的数目,这样就能看到具体是哪个对象在增长,这样结合代码的修改记录,就能很快定位泄露的地方了。

       之前写过使用GDIView排查GDI对象泄露的分析实例,可以去查看文章:

使用GDIView工具排查GDI对象泄漏导致程序UI界面绘制异常的问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128625868

6、如何排查内存泄露问题?

       所谓的内存泄露就是动态申请的内存,在使用完后没有去释放,导致泄露。内存泄露在C++程序中比较常见。

       对于大型项目,代码量比较大,业务复杂,内存泄露排查起来会比较费劲!有多个工具和方法去排查,比如可以使用Windbg中的umdh. exe工具、使用Windbg中的堆内存信息查看命令、使用Visual Leak Detector工具、甚至使用Visual Studio 2019开始集成的google出品的专用内存分析工具AddressSanitizer。此外像BounderCheck这种老的工具,若干年前就已经停止维护了,已经不支持新版本的Visual Studio了,也就没法使用了。

       有时有的内存泄露问题,很难排查,用一个工具和方法分析不出来,可以多尝试几个工具和方法,直到分析出来为止!

       使用Visual Leak Detector(简称VLD)排查内存泄露的案例文章:

​ 使用Visual Leak Detector排查内存泄漏 icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135472681 ​       使用其他工具分析内存泄露的案例,可以查看内存泄露专栏中的文章:

​ C++内存泄漏排查专题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12370029.html ​

7、如何排查死循环(高CPU占用)问题?

       代码中发生了死循环,一直在执行循环体中的代码,会有一个典型的现象,进程的CPU占用会比较高。

       为什么死循环会导致CPU占用高的问题呢?其实很好理解,因为代码一直在不停歇地执行循环体中代码,一直在占用CPU时间片,所以导致CPU占用高。其实是表现为进程中的某个线程占用的CPU高,因为死循环的代码是执行在某个线程中的,所以这个线程占用的CPU高。

        这种死循环问题排查起来很简单,先用Process Explorer查看哪个线程占用CPU高。然后将Windbg附加到进程上,然后通过占用CPU高的那个线程的id,在windbg中切换到该线程中,输入kn命令查看该线程当前的函数调用堆栈,然后对照着代码就能确定发生死循环的代码位置了。在Process Explorer中也可以查看函数调用堆栈,但看的不准确,并且有时要看相关变量的值去确定为什么发生死循环,这些只能在Windbg中查看,在Process Explorer中是查看不到的。

       我之前写过使用Process Explorer和Windbg排查死循环的案例,可以查看文章:

使用Process Explorer/Process Hacker和Windbg高效排查软件高CPU占用问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135822428

8、如何排查数据格式化时的崩溃问题?

        一般我们在打印日志时需要将相关变量的值格式化到字符串中,然后将字符串打印出来。在格式化时,时常会用到遇到异常崩溃问题。

        一种最简单的场景是,待格式化参数与对应的格式化符不匹配导致了异常。比如一个int类型的参数,却使用了%s的格式化符,比如:

int i = 1;
char szBuf[256] = { 0 };
sprintf( szBuf, "%s", i );

格式化函数内部会去解析出设置的格式化符,然后到栈上传过来的对应位置的待格式化参数。格式化函数解析到%s,到栈上拿到对应的参数,然后把参数值与%s对应,即把参数值当成字符串首地址来处理,在此示例代码中,把参数i的值1,当成字符串首地址,即到 0x00000001地址的内存中把字符串读出来去格式化,而这个0x00000001地址值很小,属于64KB的小地址内存区(空指针地址内存区),这个区域的内存是禁止访问的,所以产生了内存违例,引发崩溃。

        这种场景下问题排查很简单,只要看看格式化符与待格式化参数是否匹配即可发现问题。一般这类问题,可能是写代码时手误,讲格式化符号用错了。

       还有一类场景隐藏的比较深,本质上也是格式化符与待格式化参数类型不匹配的问题。比如一个int64的参数,却使用了32位整型对应的%d,导致格式化函数内部再从栈上取对应位置的数据(传入被调用函数的参数是压到栈上传递过来的)时取的数据长度有问题,导致格式化符取数据错位问题,可能会引发崩溃。这类问题一般很难一眼看出来,之前我就帮同事排查过一个类似的问题,详细分析排查过程可以见文章:

UINT64整型数据在格式化时使用了不匹配的格式化符%d导致其他参数无法打印的问题排查icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/132549186

9、如何排查堆内存被破坏问题?

       堆内存被越界破坏,是最难查的一类内存问题。当堆内存被破坏时,程序会到处“乱崩溃”,一会崩溃在这里,一会崩溃在那里,有时崩溃在new一个对象或一段内存地方,有时崩溃在delete对象或内存地方。

       为啥会出现胡乱崩溃的问题呢?因为越界将堆内存头部或尾部区域给篡改了,而系统管理堆内存就是通过头部和尾部的信息来管理的,一旦被篡改,导致堆内存管理出问题,导致后续申请或释放堆内存产生异常。

       堆内存被破坏,排查起来比较困难,Windows平台上没有专用的内存检测工具,只能通过注释代码逐步缩小排查范围去查。而Linux平台上则有专用的内存检测工具Valgrind和AddressSanitizer。好在Visual Studio 2019 19.6以后的版本引入了google的AddressSanitizer,大家后面遇到问题可以试用一下。因为我们项目组从上到下统一使用的是Visual Studio 2017,所以不能使用。

       以前项目中遇到一个内存越界篡改堆内存头信息导致delete去释放堆内存时产生了异常,相关文章如下:

C++堆内存错误:C运行时库检测到向堆内存头部写入了内容icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/121800292

10、如何排查线程堵塞或卡死问题?

       一般线程堵塞或卡死可能是两个原因导致的,一个是多线程之间发生了死锁,一个是线程中发生了死循环。一旦线程发生堵塞,线程相关的业务没法顺利执行,导致软件业务出现异常。

       对于死循环问题的排查,上面已经讲过了。对于多线程死锁,如果是临界区死锁,也可以在Windbg中查看发生死锁的临界区锁信息,可以快速地定位。如果是非临界区锁,排查起来比较麻烦,可以将所有线程的函数调用堆栈都打印出来,然后结合代码,判断出哪个线程发生了死锁。一般添加打印日志,也能辅助定位死锁发生的位置。

       对于使用Windbg分析临界区死锁问题,可以查看我以前写的文章:

使用Windbg分析多线程临界区死锁问题分享icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128532743

11、如何排查程序中的资源泄露问题?

        程序中的GDI对象泄露、内存泄露和句柄泄露,都属于资源泄露。GDI对象泄露和内存泄露比较常见,我上面已经详细的讲解了。对于句柄泄露,我们在项目中遇到过,代码中频繁创建线程,任务很快执行完线程退出,但没有关闭线程句柄,导致后续创建线程失败,业务出现异常。

        对于资源泄露,之前写了专题文章,可以查看:

深入探究 C++ 程序中的资源泄漏问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/133631728

12、如何排查第三方库注入引发的异常问题?

       有些第三方程序(比如输入法和安全软件)会有模块注入到我们的程序进程中,可能会导致我们的程序出现异常。我们在项目中遇到过几次。

       对于输入法注入,输入法之所以能支持在所有程序中输入文字,是因为他有专门的注入模块,会注入到所有的进程中。到这种注入可能会引发异常,比如会导致软件时不时的卡顿,导致软件发生死锁,我们在项目中遇到过。对于死锁,我们在Windbg显示的发生死锁的那个线程的函数调用堆栈中看到了输入法的模块,正因为输入法接口调用触发的!

        对于第三方安全软件注入,第三方安全软件就是通过注入到进程中对进程进行监控的。如果注入模块发生内存泄露或者崩溃,会直接影响到我们的软件进程,因为它位于我们的进程空间中!这个我们在项目中都遇到过,相关文章可以查看:

第三方模块远程注入到软件中引发软件异常的若干实战案例分享icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/134545223

13、如何排查库与库之间不匹配问题?

        库与库之间的不匹配,一般是两个库的版本不一致。可以从头文件的角度去看(底层发布库到我们的软件中),比如只更新了API头文件但库没更新库文件,再比如只更新了库文件却没有更新API头文件。API头文件中可能有相关结构体的定义,比如新版本中修改了结构体成员(删除或新增了成员),库的版本不匹配也可能会出问题。

        比如A库依赖B库,A库中调用了B库的接口,A库编译时用到B库的API头文件b. h。编译A库时,因为调用 B库的接口,所以要依赖B库的API头文件b. h。而B库本身编译时,一会依赖其API头文件b. h。如果A库使用的B库与B库的头文件b. h版本不一致,也可能会出问题,编译可能没问题,但运行时可能会出问题。

       当软件出现崩溃时,分析函数调用堆栈时也看不出问题,这时可能是库与库不匹配导致的。根据函数调用堆栈中模块,查看这些模块及头文件在svn上的发布记录(假设库是底层模块开发组打不过来的),并与模块的维护人员确认是否是库的版本问题。

14、如何排查程序启动异常(启动报错、崩溃、卡死)问题?

        程序启动时,系统会先把exe程序依赖的所有dll库加载到程序的进程空间中,最后才会进入exe主程序的main函数,程序才能运行起来。

       如果依赖的库,在电脑系统中找不到,则程序启动时会报缺少库的提示,一般是因为程序打包(生成安装包)忘记把缺少的库打包进安装包导致的。把缺少的库打包进去即可。

       如果程序调用的接口在对应的库找不到,程序启动时会报在某个库找不到接口(可能接口名称边了,也可能是接口参数变了),此时可以用Dependency Walker打开exe主程序文件,看看具体是哪个模块调用了这个接口,确认一下是主调模块有问题,还是被调模块有问题。

       如果是启动过程中发生崩溃,可能是加载某个库时库的初始化代码有问题引发的,程序发生崩溃闪退。这时没有机会将Windbg附加到进程上去分析,因为程序已经崩溃闪退了。此时可以使用Windbg将程序启动起来,一旦程序发生崩溃,Windbg就会感知到,就会中断下来,就可以去分析了。

      《C++软件调试与异常排查从入门到精通》专栏中有专门的章节讲述程序启动异常排查的专题,感兴趣的朋友可以去查看:

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

15、使用Windbg分析软件异常有哪些方式?

       Windbg排查软件异常主要有两种方式,即静态分析dump和动态调试目标进程。当我们有dump文件时,则使用静态分析dump文件的方式。如果没有生成dump文件(可能没捕获到异常),或者从现有的dump文件中分析不出问题时,可以将Windbg附加到目标进程上进行动态调试。

       使用Windbg静态分析dump文件的一般步骤,见文章:

使用Windbg静态分析dump文件的一般步骤详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135484682       使用Windbg动态调试目标进程的一般步骤,见文章:

使用Windbg动态调试目标进程的一般步骤详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135484906

16、为什么有的异常捕获不到?

       应该是程序中只是简单使用API函数SetUnhandleExceptFilter设置异常回调函数去捕获异常,但这种做法是与线程关联的,需要每个线程都设置回调。只在上层模块中调用设置,只作用所在的线程中的,一般无法捕获其他线程中的异常。而进程中包含了多个模块多个线程,所以其他线程中的异常捕获不到。所以会遇到很多时候捕获不到异常的问题。

       只是简单地调用SetUnhandleExceptFilter设置异常回调去捕获异常,是远远不够的!一般我们使用开源的异常捕获库去捕获异常,比如CrashRpt、BreadPad和CrashPad。

17、常用的开源异常捕获库有哪些?

       常见的开源捕获库CrashRpt、BreadPad和CrashPad。其中CrashRpt是Google早期开源的,但通过项目实战发现该库有些时捕获不到发生的异常,才看代码研究其实现机制发现,她是通过将加载模块导入表中创建线程的CreateThread函数hook成自定义的函数,在该函数中给当前线程设置异常回调函数去实现该线程的异常捕获。但只对在异常捕获模块之前加载的模块进行hook,后加载到进程空间中的模块没有hook,所以后加载模块如果发生异常,是捕获不到的。

       后来我们使用了微软开源的detours项目对CrashRpt进行改进,有效地提高了捕获异常的几率。BreadPad是Google开源的Chrome浏览器中的异常捕获模块,最新版本浏览器中已经改为CrashPad。CrashPad默认是支持Windows的,如果用在linux中,则需要使用Linux版本。

18、异常捕获库捕获不到异常时,该怎么办?

       大家在实际项目中会发现,即使使用了开源的异常捕获库(或者经过升级改造的捕获库),有少部分异常还是捕获不到的

       对于捕获不到的异常,则只能将Windbg附加到目标进程上,和目标进程一起跑,一单进程发生异常,会投递给正在附加调试的Windbg,Windbg就会感知到异常并中断下来,就可以直接在Windbg中分析了。如果一时半会看不出来,可以使用. dump命令将异常上下文导出到dump文件中,事后再去静态分析。

       在正在调试的Windbg中使用命令导出的dump文件,属于全dump文件,文件大小接近进程的虚拟内存的大小。Windbg动态调试相对于静态分析,可以多次go多次动态查看函数调用堆栈,还可以添加断点进行断点调试。

19、生成dump文件的方式有哪些?

       生成dump文件的方式主要有三种。

       最常用的方式是通过异常捕获库去自动生成,即异常捕获库捕获到了软件中发生的异常,自动调用系统API函数MiniDumpWriteDump将异常上下文信息保存到dump文件中。

       也可以从Windows任务管理器中导出进程的dump文件。它用在什么场合下呢?比如程序发生异常弹出保存提示框,此时进程还在的,可以导出dump文件。再比如程序发生死循环或死锁时,进程还在的,也可以从任务管理器中导出dump文件。

       还可以从正在调试的Windbg中使用. dump命令导出dump文件。比如我们在使用Windbg动态调试目标进程时,如果一时半会分析不出问题或者出问题的电脑别人还要用(我们不能长时间占用别人的电脑去分析问题),可以导出dump文件,然后事后去分析dump文件即可。

       关于生成dump文件方式的详细说明,可以参见文章:

dump文件类型与dump文件生成方法详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/127991002

20、为什么要加载pdb文件?为什么要加载系统库的pdb文件?

       pdb文件中包含函数及变量的符号信息,加载pdb后在函数调用堆栈中才能看到具体的函数名和代码行号。有时我们需要在Windbg中查看函数中相关变量的值,变量的值可能是关键线索,有pdb中的变量符号才能识别变量,才能看到变量的值。

       pdb文件分软件业务模块的pdb文件和Windows系统库pdb文件。业务模块的pdb需要加载,有时为了搞清楚问题,也要加载系统库pdb的,加载后可以看到系统库中具体调用了哪些接口,可能能找到更为直接的线索。加载pdb后,可能能看到更多行的函数调用,更便于分析问题。

       对于Windows系统库的pdb文件,不需要下载,微软提供了一个在线pdb符号服务器,只需要将这个在线地址设置给Windbg,Windbg在需要时会自动去下载。

       此外,不仅仅Windbg会用到pdb文件,有些分析工具也会用到。比如Process Explorer/Process Hacker、Process Monitor,使用这些工具分析问题时有时需要看函数调用堆栈,需要pdb中的函数符号。再比如使用反汇编工具IDA查看二进制文件的汇编代码,也需要使用到二进制文件的pdb文件中的函数与变量符号。

       关于pdb符号文件的详细说明,可以参见文章:

pdb符号文件详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125508858

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

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

相关文章

JavaScript-2.对话框、函数、数组、Date、DOM

对话框 window对象封装了三个对话框用于与用户交互 提示框:alert(title);确认框:confirm(title);输入框:prompt(title); 确认框 包含两个按钮“确认”/“取消”,点击确定时,返回值为true // 确认框 var bool con…

Python学习笔记16 - 函数

函数的创建和调用 函数调用的参数传递 函数的返回值 函数的参数定义 变量的作用域 递归函数 斐波那契数列 总结

Vitis HLS 学习笔记--硬件卷积加速 Filter2DKernel

目录 加速器功能 Window2D()函数 实现代码 变量解释 ARRAY_PARTITION DEPENDENCE LOOP_TRIPCOUNT ramp_up 更新Window 更新LineBuffer Filter2D()函数 ARRAY_PARTITION window_stream.read() 计算过程 备注 加速器功能 硬件加速单元从全局内存(DDR&a…

PP-LCNet:一种轻量级CPU卷积神经网络

PP-LCNet: A Lightweight CPU Convolutional Neural Network 最近看了一个新的分享,在图像分类的任务上表现良好,具有很高的实践意义。 论文: https://arxiv.org/pdf/2109.15099.pdf项目: https://github.com/PaddlePaddle/Padd…

javaweb在线拍卖系统

项目采用技术栈 htmlcssjs Vue2.js axios.js tomcat Servlet Mybatis Mysql 1.竞拍商品列表 实现多条件分页查询,头部根据是否登录作出不同的判断信息(登录或注销) 2.登录功能 3.竞拍页面 只有登录用户才能竞拍,出价记录需要实现关联用户查询 4.管理员登录增…

如何在Odoo 17 销售应用中使用产品目录添加产品

Odoo,作为一个知名的开源ERP系统,发布了其第17版,新增了多项功能和特性。Odoo 17包中的一些操作简化了,生产力提高了,用户体验也有了显著改善。为了为其用户提供新的和改进的功能,Odoo不断进行改进和增加新…

基于PCIe的智能处理系统研究

引言 人工智能是集合众多方向的综合性学科,在诸多应用领域均取得了显著成果。随着航空领域人工智能技术研究的不断深入,面向开放式机载智能交互场景,人工智能的应用可解决诸多问题。例如智能感知、辅助决策等,可利用人工智能算法对多源传感器捕获的海量信息进行快速处理,仅将处…

4、XTuner微调个人小助手(homework)

基础作业(结营必做) 训练自己的小助手认知(记录复现过程并截图) 1,环境安装 # 如果你是在 InternStudio 平台,则从本地 clone 一个已有 pytorch 的环境: # pytorch 2.0.1 py3.10_cuda11…

Grok-1.5 Vision:X AI发布突破性的多模态AI模型,超越GPT 4V

在人工智能领域,多模态模型的发展一直是科技巨头们竞争的焦点。 近日,马斯克旗下的X AI公司发布了其最新的多模态模型——Grok-1.5 Vision(简称Grok-1.5V),这一模型在处理文本和视觉信息方面展现出了卓越的能力&#x…

李沐36_数据增广——自学笔记

数据增强 增强一个已有的数据集,使得有更多的多样性 1.在语言里面加入各种不同的背景噪音 2.改变图片的颜色和形状 一般是在线生成、随机增强 常见数据增强 1.左右翻转 2.上下翻转(不总可行) 3.切割:从图片中切割一块&…

OpenCV4.9图像金字塔

目标 在本教程中,您将学习如何: 使用 OpenCV 函数 pyrUp()和 pyrDown()对给定图像进行下采样或上采样。 理论 注意 下面的解释属于 Bradski 和 Kaehler 的 Learning OpenCV 一书。 通常,我们需要将图像转换为与原始图像不同的大小。为此…

函数的参数命名和默认参数

在Kotlin中,函数可以有多个参数,记住参数的顺序或者仅靠位置理解他们的作用可能会很具有挑战性,特别是对于接受多个参数或者有相同类型参数的函数。命名参数通过允许开发者指定传递给函数的每个参数的名称来解决这个问题。 有一个用来展示用户…

了解 Vue 工程化开发中的组件通信

目录 1. 组件通信语法 1.1. 什么是组件通信? 1.2. 为什么要使用组件通信? 1.3. 组件之间有哪些关系(组件关系分类)? 1.4. 组件通信方案有哪几类 ? 2. 父子通信流程图 3. 父传子 3.1. 父传子核心流程…

【C++成长记】C++入门 | 类和对象(中) |类的6个默认成员函数、构造函数、析构函数

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:C❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、类的6个默认成员函数 二、构造函数 1、概念 2、特性 三、析构函数 1、概念 2、特性 一、…

LabVIEW专栏六、LabVIEW项目

一、梗概 项目:后缀是.lvproj,在实际开发的过程中,一般是要用LabVIEW中的项目来管理代码,也就是说相关的VI或者外部文件,都要放在项目中来管理。 在LabVIEW项目中,是一个互相依赖的整体,可以包…

51-40 Align your Latents,基于LDM的高分辨率视频生成

由于数据工程、仿真测试工程,咱们不得不进入AIGC图片视频生成领域。兜兜转转,这一篇与智驾场景特别密切。23年4月,英伟达Nvidia联合几所大学发布了带文本条件融合、时空注意力的Video Latent Diffusion Models。提出一种基于LDM的高分辨率视…

【简单讲解如何安装与配置Composer】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

深入探索:Zookeeper+消息队列(kafka)集群

目录 前言 一、Zookeeper概述 1、Zookeeper概念 2、Zookeeper 特点 3、Zookeeper工作机制 4、Zookeeper 选举机制 4.1 第一次启动选举机制 4.2 非第一次启动选举机制 5、Zookeeper 数据结构 6、Zookeeper 应用场景 二、部署 Zookeeper 集群 1、环境部署 2、安装 z…

构建鸿蒙ACE静态库

搭建开发环境 根据说明文档下载鸿蒙全部代码,一般采取第四种方式获取最新代码(请保证代码为最新) 源码获取Windows下载编译环境 MinGW GCC 7.3.0版本 请添加环境变量IDE 可以使用两种 CLion和Qt,CLion不带有环境需要安装MinGW才可以开发,Qt自带MinGW环境&#xff0…

【Canvas与艺术】绘制磨砂黄铜材质Premium Quality徽章

【关键点】 渐变色的使用、斜纹的实现、底图的寻觅 【成果图】 ​​​​​​​ 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><tit…