Windows Phone App的dump文件实例分析-如何从Release版的Dump中手动恢复异常的上下文

这篇文章我们一步一步的讲解如何找到异常发生时候的上下文。

1. 什么是异常上下文

    简单来说,在windows体系的操作系统里面,每个线程都有自己的线程上下文来保存需要的信息,其中包括当前寄存器的值。我们这里需要找到的异常上下文就是当异常发生的时候,异常分发器帮我们保存的当前寄存器的值(也叫寄存器上下文),利用这些信息结合汇编代码的分析,我们就可以进一步的找到发生异常的原因。关于寄存器上下文结构体的定义我们可以在 winnt.h 找到,这里就不一一解释了。

2. Windbg 中的“.cxr + Context Address”命令可以帮助我们恢复异常发生时候寄存器的一手资料,那么我们只需要找到这个上下文的地址就可以交由这个命令来处理了。

3. 如何找到保存上下文的地址?

    当我们使用windbg打开dump file的时候,我们都会看到类似下面的调用堆栈模式:

     

    这个正式异常分发器在帮助我们保存上下文,我们看看RtlDispatchException的函数声明,这里使用”x”命令:

     

    大家已经发现了,这个函数的第二个参数正式我们要找到的上下文的地址。

4. 有了上下文的地址,我们就可以使用”.cxr ”命令进行恢复了。这里第二个参数是00c2e168, 执行”.cxr 00c2e168”命令。

     

5. 这个值真的对吗?恢复了异常发生时的上下文,让我们再看看调用堆栈的变化

   

    这个堆栈和寄存器的的值看起来太诡异了,这不禁让我们对上面的地址产生了怀疑!

6. 想想看这个dump文件是来自于Release版本的App,编译器会在生成release版的可执行文件中进行大量的优化,这种情况下的函数调用会最大程度地使用我们的寄存器来传递参数,而不是靠@esp+0x?来进行。想到了这里,让我们再次回到RtlDispatchException去查看一下。

7. 使用”.frame + index”跳转到调用堆栈中指定的栈帧,并使用”dv”命令查看本地变量

    

    这次我们清晰的看到了寄存器r6和r9里面的内容,正是代码优化的结果。编译器优化了代码使用r6, r9两个寄存器来代替“栈操作”进行了传参。

8. 再次使用”.cxr” 和”k”,这次我们就看到了真正的异常第一发生现场

   

    原来是ldr指令企图加载一个空地址引发了异常。下一篇文章,我们会再次回到这个异常,来具体看一看究竟发生了什么事情。