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. ValidateRequest问题

    1,在出现该错误的页面头部的page中加入ValidateRequest="false",那么该页面的任何一次Post提交都不会再验证提交内容的安全性.如: <%@ Page ...

  2. 实战之中兴ZXHN F460光猫破解超级密码+开启无线路由功能

    本文面向小白用户,即使你不懂电脑看完你也会破解光猫,网上有些文章的操作方法是错误的.按照我这篇文章,只要型号对,那么肯定没问题!电信光纤入户,家里用的是电信送的中兴查看 ZXHN F460 中的全部文 ...

  3. EntityFrameWork使用

    1.简单查询: SQL: ? 1 SELECT * FROM [Clients] WHERE Type=1 AND Deleted=0 ORDER BY ID EF: ? 1 2 3 4 5 6 7 ...

  4. Python的第六天

    常用模块的学习 一.time & datetime模块 时间相关的操作,时间有三种表示方式: 时间戳               1970年1月1日之后的秒,即:time.time() 格式化 ...

  5. Java lamda Stream

    Intermediate:一个流可以后面跟随零个或多个 intermediate 操作.其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用.这类操作都是惰性化的( ...

  6. java动态绑定的一点注意

    动态绑定只是针对对象的方法,对于属性无效.因为属性不能被重写. show me code: public class Father{ public String name = "父亲属性&q ...

  7. vim常用操作

    vim filename 编辑一个文件 在一般模式里按yy是复制的意思(复制当前行),按yy之前先按相应的数字键就是复制光标所在行到指定的行,然后按p粘贴在一般模式里按dd是删除的意思(也叫做剪切), ...

  8. 由system.currentTimeMillis() 获得当前的时间

    System类代表系统,系统级的很多属性和控制方法都放置在该类的内部.该类位于java.lang包. currentTimeMillis方法 public static long currentTim ...

  9. 创建javascript对象的几种方式

    ECMAScript提供的对象有:String.Date.Array.Boolean.Math.Number.RegExp.Global 程序中需要用到很多自定义的js对象 1.直接创建 var ob ...

  10. 由于C++编译器的分析机制所导致的声明问题

    假设我们想声明一个STL的vector类型的变量,读入文件里的信息: std::ifstream in("data.txt"); std::vector<int> da ...