dump 分析模式之 INCORRECT STACK TRACE - djm2005dy的专栏 - 博客频道 - CSDN.NET
初学者常犯的错误是认为 WinDbg 的 !analyze 和 kv 给出的信息是准确的.
WinDbg 只是一个工具, 有时候会缺少一些必要的信息来得到正确的栈信息, 因此我们需要自己明辨正确的与错误的栈信息. 我称之为 Incorrect Stack Trace, 它通常有以下特征:
- WinDbg给出警告: "Following frames may be wrong"
- 栈底函数不是 kernel32!BaseThreadStart (用户模式)
- 无意义的函数调用
- 反汇编后的函数的代码很奇怪, 或不像编译器生成的代码
- ChildEBP 和 RetAddr 的地址没有意义
考虑以下栈信息:
0:011> k
ChildEBP RetAddr
WARNING: Frame IP not in any known module. Following frames may be wrong.
0184e434 7c830b10 0×184e5bf
0184e51c 7c81f832 ntdll!RtlGetFullPathName_Ustr+0×15b
0184e5f8 7c83b1dd ntdll!RtlpLowFragHeapAlloc+0xc6a
00099d30 00000000 ntdll!RtlpLowFragHeapFree+0xa7
以上栈信息基本具备了错误栈信息的所有性质. 初看像是堆破坏, 因为运行时的堆分配与释放函数出现在了栈中. 但如果我们再想想就会发现 HeapFree 函数不应调用 HeapAlloc 函数, 而接下来更不应该调用 GetFullPathName. 所以这个栈信息是无意义的.
那我们能怎样呢? 检视 raw 栈信息并构造出真正的栈. 我们可以轻松地从 BaseThreadStart+0×34 开始遍历所有帧直到没有任何函数调用了或都已到栈顶. 当一个函数被调用的时候 EBP 会像下图那样连起来 (如果没有被优化掉, 对于大多数编译成立).
0:011> !teb
TEB at 7ffd8000
ExceptionList: 0184ebdc
StackBase: 01850000
StackLimit: 01841000
...
0:011> dds 01841000 01850000
01841000 00000000
…
…
…
0184eef0 0184ef0c0184eef4 7615dff2 localspl!SplDriverEvent+0×21
0184eef8 00bc3e08
...
0184ef0c 0184ef300184ef10 7615f9d0
localspl!PrinterDriverEvent+0×46
0184ef14 00bc3e08
0184ef18 00000003
...
0184ef2c 00bafcc0
0184ef30 0184f3f80184ef34 7614a9b4 localspl!SplAddPrinter+0×5f3
0184ef38 00c3ec58
...
0184ff30 0184ff840184ff34 77c75286 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×3a
0184ff38 0184ff4c
0184ff3c 77c75296 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×4a
0184ff40 7c82f2fc ntdll!RtlLeaveCriticalSection
...
0184ff84 0184ff8c0184ff88 77c5778f RPCRT4!RecvLotsaCallsWrapper+0xd
0184ff8c 0184ffac0184ff90 77c5f7dd RPCRT4!BaseCachedThreadRoutine+0×9d
...
0184ffac 0184ffb80184ffb0 77c5de88 RPCRT4!ThreadStartRoutine+0×1b
0184ffb4 00088258
0184ffb8 0184ffec
0184ffbc 77e6608b kernel32!BaseThreadStart+0×34
接下来我们需要用指定了基址的 k 命令来显示栈信息. 在本例中最后的有效 EBP 地址是 0184eef0.
0:011> k L=0184eef0
ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong.
0184eef0 7615dff2 0×184e5bf 0184ef0c 7615f9d0 localspl!SplDriverEvent+0×21
0184ef30 7614a9b4 localspl!PrinterDriverEvent+0×46
0184f3f8 761482de localspl!SplAddPrinter+0×5f3
0184f424 74067c8f localspl!LocalAddPrinterEx+0×2e
0184f874 74067b76 SPOOLSS!AddPrinterExW+0×151
0184f890 01007e29 SPOOLSS!AddPrinterW+0×17
0184f8ac 01006ec3 spoolsv!YAddPrinter+0×75
0184f8d0 77c70f3b spoolsv!RpcAddPrinter+0×37
0184f8f8 77ce23f7 RPCRT4!Invoke+0×30
0184fcf8 77ce26ed RPCRT4!NdrStubCall2+0×299
0184fd14 77c709be RPCRT4!NdrServerCall2+0×19
0184fd48 77c7093f RPCRT4!DispatchToStubInCNoAvrf+0×38
0184fd9c 77c70865 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0×117
0184fdc0 77c734b1 RPCRT4!RPC_INTERFACE::DispatchToStub+0xa3
0184fdfc 77c71bb3 RPCRT4!LRPC_SCALL::DealWithRequestMessage+0×42c
0184fe20 77c75458 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0×127
0184ff84 77c5778f RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×430
0184ff8c 77c5f7dd RPCRT4!RecvLotsaCallsWrapper+0xd
栈信息现在看起来有意义多了, 但我们仍然没有看到 BaseThreadStart+0×34. 默认情况下 WinDbg 只显示一定数量的栈帧. 所以我们需要指定栈帧的数量, 比如 100:
0:011> k L=0184eef0 100
ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong.
0184eef0 7615dff2 0×184e5bf
0184ef0c 7615f9d0 localspl!SplDriverEvent+0×21
0184ef30 7614a9b4 localspl!PrinterDriverEvent+0×46
...
0184ffac 77c5de88 RPCRT4!BaseCachedThreadRoutine+0×9d
0184ffb8 77e6608b RPCRT4!ThreadStartRoutine+0×1b
0184ffec 00000000 kernel32!BaseThreadStart+0×34
现在我们的栈信息看起来更好了. 还有一个完整的示例在 Manual Stack Track Reconstruction, 本书第 157 页.
此外, incorrect stack trace 也会发生在没有符号信息的时候. 这种情况下, 通常栈帧之间会有找不到符号的警告:
STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be wrong.
00b2f42c 091607aa mydll!foo+0×8338
00b2f4cc 7c83ab9e mydll!foo+0×8fe3
00b2f4ec 7c832d06 ntdll!RtlFindNextActivationContextSection+0×46
00b2f538 001a5574 ntdll!RtlFindActivationContextSectionString+0xe1
00b2f554 7c8302b3 0×1a5574
00b2f560 7c82f9c1 ntdll!RtlpFreeToHeapLookaside+0×22
00b2f640 7c832b7f ntdll!RtlFreeHeap+0×20e
001dd000 00080040 ntdll!LdrUnlockLoaderLock+0xad
001dd00c 0052005c 0×80040
001dd010 00470045 0×52005c
0052005c 00000000 0×470045
WinDbg中有一些很好的命令像dpu (检视unicode字符串)和dpa (检视ASCII字符串)以及其它 d 开头的命令如dpp. 我们可以使用这些命令来看看栈上是否有指针指向了字符串.
例如:
0:143> !teb
TEB at 7ff2b000
...
StackBase: 05e90000
StackLimit: 05e89000
...
...
...
0:143> dpu 05e89000 05e90000
05e8f58c 00120010 ""
...
...
...
05e8f590 77e7723c "Debugger"
05e8f594 00000000
05e8f598 08dc0154
05e8f59c 01000040
05e8f5a0 05e8f5dc "G:\WINDOWS\system32\faultrep.dll"
05e8f5a4 0633adf0 ""
05e8f5a8 00000000
05e8f5ac 00000001
05e8f5b0 00000012
...
05e8f5d4 0633adfc "drwtsn32 -p %ld -e %ld -g"
...
...
...
当然这些命令不仅能对栈地址空间起作用, 也能用在普通的内存段上.
dump 分析模式之 INCORRECT STACK TRACE - djm2005dy的专栏 - 博客频道 - CSDN.NET的更多相关文章
- Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET
OSNIT_百度百科 Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET Salt Stack 官方文档翻译 分类: 自动运维 2013-04-02 11 ...
- 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 百篇博客分析OpenHarmony源码 | v37.03
百篇博客系列篇.本篇为: v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...
- 鸿蒙源码分析系列(总目录) | 百万汉字注解 百篇博客分析 | 深入挖透OpenHarmony源码 | v8.23
百篇博客系列篇.本篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o 百篇博客.往期回顾 在给OpenHarmony内核源码加注过程中,整理出以下 ...
- v82.01 鸿蒙内核源码分析 (协处理器篇) | CPU 的好帮手 | 百篇博客分析 OpenHarmony 源码
本篇关键词:CP15 .MCR.MRC.ASID.MMU 硬件架构相关篇为: v65.01 鸿蒙内核源码分析(芯片模式) | 回顾芯片行业各位大佬 v66.03 鸿蒙内核源码分析(ARM架构) | A ...
- 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05
百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...
- Java 抓取 thread dump (Full Thread Stack Trace) 方法汇总
顾名思义,表示一个时间点上,显示进程里面每一个线程的 stack trace,以及线程之间关联,比如等待 常用来定位一些 不响应,CPU 很高,内存使用很高问题 汇总表格如下 工具 操作系统 Java ...
- 三、jdk工具之jstack(Java Stack Trace)
目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...
- 性能分析之-- JAVA Thread Dump 分析综述
性能分析之-- JAVA Thread Dump 分析综述 一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工 ...
- 性能分析之– JAVA Thread Dump 分析
最近在做性能测试,需要对线程堆栈进行分析,在网上收集了一些资料,学习完后,将相关知识整理在一起,输出文章如下. 一.Thread Dump介绍 1.1什么是Thread Dump? Thread Du ...
随机推荐
- ValidateRequest问题
1,在出现该错误的页面头部的page中加入ValidateRequest="false",那么该页面的任何一次Post提交都不会再验证提交内容的安全性.如: <%@ Page ...
- 实战之中兴ZXHN F460光猫破解超级密码+开启无线路由功能
本文面向小白用户,即使你不懂电脑看完你也会破解光猫,网上有些文章的操作方法是错误的.按照我这篇文章,只要型号对,那么肯定没问题!电信光纤入户,家里用的是电信送的中兴查看 ZXHN F460 中的全部文 ...
- EntityFrameWork使用
1.简单查询: SQL: ? 1 SELECT * FROM [Clients] WHERE Type=1 AND Deleted=0 ORDER BY ID EF: ? 1 2 3 4 5 6 7 ...
- Python的第六天
常用模块的学习 一.time & datetime模块 时间相关的操作,时间有三种表示方式: 时间戳 1970年1月1日之后的秒,即:time.time() 格式化 ...
- Java lamda Stream
Intermediate:一个流可以后面跟随零个或多个 intermediate 操作.其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用.这类操作都是惰性化的( ...
- java动态绑定的一点注意
动态绑定只是针对对象的方法,对于属性无效.因为属性不能被重写. show me code: public class Father{ public String name = "父亲属性&q ...
- vim常用操作
vim filename 编辑一个文件 在一般模式里按yy是复制的意思(复制当前行),按yy之前先按相应的数字键就是复制光标所在行到指定的行,然后按p粘贴在一般模式里按dd是删除的意思(也叫做剪切), ...
- 由system.currentTimeMillis() 获得当前的时间
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部.该类位于java.lang包. currentTimeMillis方法 public static long currentTim ...
- 创建javascript对象的几种方式
ECMAScript提供的对象有:String.Date.Array.Boolean.Math.Number.RegExp.Global 程序中需要用到很多自定义的js对象 1.直接创建 var ob ...
- 由于C++编译器的分析机制所导致的声明问题
假设我们想声明一个STL的vector类型的变量,读入文件里的信息: std::ifstream in("data.txt"); std::vector<int> da ...
18
0 热度