BianChengNan's Blog

Coding is hard, you can make it easy!


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

调试实战 | 记一次有教益的递归栈查看(续)

发表于 2024-01-06 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

在上篇文章中介绍了在 windbg 中如何查看非常深的调用栈 —— 使用 kN 命令指定栈帧数。kN 虽好,但最多只能查看 0xffff 个栈帧。如果栈帧数量比 0xffff 还多,该如何查看呢?本文将介绍几种查看方法。

阅读全文 »

调试实战 | 记一次有教益的递归栈查看

发表于 2024-01-06 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

最近,遇到了一个由于递归导致的卡死问题。这个问题非常有意思,值得总结。

你知道什么情况下无限递归会卡死,而不崩溃吗?你知道递归层数过多时,如何找到导致递归调用的函数吗?你知道如何快速找到关键线程吗?你知道如何附加到一个正在被调试的进程吗?你知道如何在 windbg 中显示指定数量的栈帧吗?

带着这些疑问,一起来看看这个非常有意思的问题吧。

说明: 文章末尾有这些问题的答案,可以直接跳到末尾查看。

阅读全文 »

调试实战 | 从转储文件找出抛出的异常 —— 实战

发表于 2023-12-31 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

我在上一篇文章中介绍了定位抛出异常的理论知识,本文会通过几个实例介绍各种情况下的定位方法。有调试符号如何定位?没有调试符号如何定位?32 位程序如何定位?64 位程序又该如何定位?

其实,32 位程序和 64 位程序定位过程大同小异,只不过在解析过程中需要注意,很多关键字段在 64 位程序中是偏移,需要加上模块基址得到虚拟地址后才能使用,而在 32 位程序中对应的字段就是虚拟地址,可以直接使用。

没有调试符号的时候定位异常类型会比较困难,需要根据上一篇文章中总结的步骤一步步的找到异常类型。有调试符号的情况会比较容易,有很多简便的查看方法。

一起来实战吧!

阅读全文 »

调试实战 | 从转储文件找出抛出的异常 —— 理论

发表于 2023-12-30 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

最近在分析转储文件时,遇到了一个由 throw 抛出的异常。尽管在 windbg 中使用 !analyze -v 迅速知道了异常码是 0xe06d7363(对应的 ASCII 码是 .msc),但是根据异常码并不能确定具体抛出来的是哪种异常。针对这种情况,确定具体的异常类型才有意义。

本篇文章会简单介绍与抛出异常相关的内容,包括关键的函数及结构体。下一篇文章会通过实例介绍几种典型情况(有调试符号 / 没有调试符号 / 32 位程序 / 64 位程序)下的定位方法。

阅读全文 »

调试实战 | 谁在偷偷占用我的文件?原来是我自己

发表于 2023-12-24 | 更新于: 2024-12-21 | 分类于 调试实战
字数统计: | 阅读时长 ≈ 分钟

缘起

之前基于 .net 官方提供的 FileSystemWatcher 写了一个文件变化监听工具,具体参考这篇文章 。主要解决了以下三个问题:

  1. 事件触发时,文件可能还不能被访问。
  2. 如果监听选项设置的过多,有可能会多次触发文件变化事件。
  3. 监听过滤器不够灵活,我没找到同时监听多种特定文件类型的方法(比如,同时只监听 .docx 和 .bmp 文件)。

为了解决问题1,我在调用用户注册的回调函数前,会先调用 WaitUntilCanAccess() 来确保文件是可访问状态。没想到在测试过程中发现了一个意想不到的问题。本文记录了解决这个问题的过程。

阅读全文 »

开发常识 | 彻底理清 CreateFile 读写权限与共享模式的关系

发表于 2023-12-23 | 更新于: 2024-12-21 | 分类于 开发
字数统计: | 阅读时长 ≈ 分钟

前言

前一阵子,我在编写文件变化监控程序的时候遇到了文件被占用的问题。很早之前写过一篇关于 CreateFile 函数的 dwDesiredAccess 和 dwShareMode 参数的笔记。我发现之前的理解不够全面、准确。为了更好的理解这两个参数的作用,我搜索了大量资料,编写了测试程序及测试脚本,参考了 xp 源码,终于搞清楚这两个参数的作用。简而言之,需要遵循以下两个规则:

规则 1:后续的访问权限与先前的共享模式不能冲突。

规则 2:后续的共享模式与先前的访问权限不能冲突。

如果你对下面的几个问题有明确的答案并且清楚的知道原因,那么可以跳过本文了。

  1. 第一次以读访问权限,写共享模式打开文件,会成功吗?
  2. 如果第一次打开成功了,第二次以写访问权限,读共享模式打开。会成功吗?
  3. 如果第二次打开成功了,第三次以读 / 写 / 读写访问权限,读写共享模式打开,会成功吗?
  4. 第一次以读访问权限,写共享模式打开文件,第二次以写访问权限,读写共享模式打开。第三次以写访问权限,读写共享模式打开,会成功吗?
阅读全文 »

如何确定线程栈的基址?

发表于 2023-10-29 | 更新于: 2024-12-21 | 分类于 调试实战 , 工具
字数统计: | 阅读时长 ≈ 分钟

缘起

很早之前,我遇到过几个与栈相关的问题,当时总结过几篇关于线程栈的文章,分别是 《栈大小可以怎么改?》、《栈局部变量优化探究,意外发现了 vs 的一个 bug ?》、《栈又溢出了》、《有趣的异常》。在这几篇总结中,简单的总结了栈溢出的原因,设置线程栈大小的方法。但是还有一点没弄清楚:操作系统是怎么知道一个线程的栈大小的?一定记录在某个位置了,否则就不能正确的在栈溢出的时候抛出异常了。不能根据 PE 头中的字段判断,因为在创建线程的时候可以指定线程栈大小。TEB 中的 StackLimit 是真正的栈底吗?带着这些疑问一起来刨根问底吧~

友情提示:结论在文章末尾。

阅读全文 »

调试实战 | 记一次有教益的 MFC 程序崩溃分析

发表于 2023-10-22 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

实际项目中,resource.h 文件中的控件太多太乱了,合并代码的时候非常痛苦。为了解决这个问题,需要对 resource.h 中的 ID 进行整理。根据之前整理的成果,很快把控件 ID 按对话框分类整理好了。没想到测试的时候遇到了各种崩溃,废了好大劲儿才解决。究其原因,是对 MFC 资源管理机制认识不够深刻。尝试创建某个模块内的对话框的时候,意外地找到了其它模块中的对话框资源。MFC 到底是怎么查找资源模块的呢?应该如何排查这种问题呢?一起来看看吧。

阅读全文 »

如何查找已注册消息的名称?

发表于 2023-10-22 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

TL;DR

在 Windows 中,通过 RegisterWindowMessage() 注册的消息,其消息 ID 在 0xC000 ~ 0xFFFF 之间。可以使用 GetClipboardFormatName() 根据消息 ID 反向查找已注册消息的名称。

阅读全文 »

调试实战 | 解决另外一个链接错误

发表于 2023-10-22 | 更新于: 2024-12-21 | 分类于 调试
字数统计: | 阅读时长 ≈ 分钟

缘起

最近,在加班的过程中遇到一个链接错误 —— fatal error LNK1120: 1 unresolved externals。这种错误是老朋友了,对我这种常年写 bug 的老手来说,完全不是事儿,轻松+愉快。

根据以下的排查思路基本上能解决大多数链接错误:

既然报了链接错误,说明编译已经通过了,问题基本出现在库文件上。

有可能是找不到库文件(缺少库,或者库文件搜索路径不对),可以先确认工程配置是否正确或者使用 /verbose:lib 查看链接过程。

也可能是库文件不对(没包含对应的导出符号),可以通过 dumpbin /exports error.lib > error.txt 查看 lib 库中的导出符号。按照以上步骤排查基本上可以解决绝大多数链接错误。

好的,让我们一起来实战一下吧。

阅读全文 »
123…14
BianChengNan

BianChengNan

134 日志
33 分类
221 标签
RSS
GitHub 知乎 博客园
© 2019 — 2024 BianChengNan | 全博客共 字
0%