dump 分析模式之 INCORRECT STACK TRACE 翻译自 MDA-Anthology Page288 



初学者常犯的错误是认为 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

翻译自 MDA-Anthology1 page167, WINDBG TIPS AND TRICKS. 



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的更多相关文章

  1. Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET

    OSNIT_百度百科 Salt Stack 官方文档翻译 - 一个想做dba的sa - 博客频道 - CSDN.NET Salt Stack 官方文档翻译 分类: 自动运维 2013-04-02 11 ...

  2. 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 百篇博客分析OpenHarmony源码 | v37.03

    百篇博客系列篇.本篇为: v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  3. 鸿蒙源码分析系列(总目录) | 百万汉字注解 百篇博客分析 | 深入挖透OpenHarmony源码 | v8.23

    百篇博客系列篇.本篇为: v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o 百篇博客.往期回顾 在给OpenHarmony内核源码加注过程中,整理出以下 ...

  4. v82.01 鸿蒙内核源码分析 (协处理器篇) | CPU 的好帮手 | 百篇博客分析 OpenHarmony 源码

    本篇关键词:CP15 .MCR.MRC.ASID.MMU 硬件架构相关篇为: v65.01 鸿蒙内核源码分析(芯片模式) | 回顾芯片行业各位大佬 v66.03 鸿蒙内核源码分析(ARM架构) | A ...

  5. 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 百篇博客分析OpenHarmony源码 | v6.05

    百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  6. Java 抓取 thread dump (Full Thread Stack Trace) 方法汇总

    顾名思义,表示一个时间点上,显示进程里面每一个线程的 stack trace,以及线程之间关联,比如等待 常用来定位一些 不响应,CPU 很高,内存使用很高问题 汇总表格如下 工具 操作系统 Java ...

  7. 三、jdk工具之jstack(Java Stack Trace)

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  8. 性能分析之-- JAVA Thread Dump 分析综述

    性能分析之-- JAVA Thread Dump 分析综述       一.Thread Dump介绍 1.1什么是Thread Dump? Thread Dump是非常有用的诊断Java应用问题的工 ...

  9. 性能分析之– JAVA Thread Dump 分析

    最近在做性能测试,需要对线程堆栈进行分析,在网上收集了一些资料,学习完后,将相关知识整理在一起,输出文章如下. 一.Thread Dump介绍 1.1什么是Thread Dump? Thread Du ...

随机推荐

  1. 通过 SMB 直通优化文件服务器的性能

    https://technet.microsoft.com/zh-cn/library/hh831487.aspx Windows Server 2012 内置新增功能,称为 SMB 直通,用来支持使 ...

  2. cygwin和mingw的区别

    之前由于做一些JNI的开发,安装了MinGW,最近有个项目需要用到cygwin,于是就有个疑问,这两个东西有什么区别?在网上看了些资料,在这里复制粘贴一下,以备后查. Unix下编译通过的C代码,在w ...

  3. css 文本显示点点点

    今天有这个需求,百度获取到这个效果,记录下来. text-overflow :ellipsis; //让截断的文字显示为点点.还有一个值是clip意思是截断不显示点点 white-space : no ...

  4. jq插件的传值

    因插件方式写的少,先慢慢记录. 默认的参数值 jQuery.fn.shadow =function(options){ var defaults = { slices : 5, opacity : 0 ...

  5. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: ) { ); ) { throw ne ...

  6. php入门part3

    php函数 php函数和JScript的函数大同小异,这里主要强调一下不同之处. 函数的定义:function函数名(形参类表){ 函数体 } 函数的调用:函数名(实参类表) 在php里函数可以先调用 ...

  7. NLog学习

    一.什么是NLog? NLog((http://www.nlog-project.org)是一个基于.NET平台编写的类库,我们可以使用NLog在应用程序中添加极为完善的跟踪调试代码. NLog允许我 ...

  8. Hadoop总结篇之一------开篇

    从今天开始新的系列:Hadoop总结篇 之前的hadoop学习篇由于是学习过程中随手记下来的一些内容,不具有系统性.所以在这个系列中,将凭着这段时间的研究心得,来记录一些自认为比较重要的东西. 本系列 ...

  9. Thread.join简单介绍

    百度了一下,终于明白了.这个解释最简单: 前提:join()方法肯定是被某个线程调用的.   A线程正在执行,突然执行的时候碰到了B.join(), 那么,A线程就必须要等到B线程执行完之后才能执行. ...

  10. EventBus--介绍

    注意: 1,post()方法里面的类型和onEvent()中的类型要一致., 2,订阅者对象中 必须有 onEvent 的 public 方法     ---public void onEvent(O ...