如何解码Windows CE调用堆栈?

时间:2010-10-28 23:10:05

标签: arm windows-ce decode callstack

桌面Windows操作系统具有“StackWalk64”功能,Jochen Kalmbach将a library for decoding the call stack置于人类可读的东西之上。

我需要一个类似的工具,但对于Windows CE。 WinCE有一个函数来获取调用堆栈GetThreadCallStack,但是一旦我有原始返回地址,我该如何

  1. 确定每个程序计数器的模块(DLL或EXE)?
  2. 使用我的.map或.pdb文件确定包含地址的函数?
  3. PS。如果它对任何人有帮助,我还发现OS-agnostic code用于遍历ARM调用堆栈。显然,可靠的确很难!

3 个答案:

答案 0 :(得分:4)

好吧,我想出了一半。您需要致电GetThreadCallStack ...

CallSnapshot frames[100];

HANDLE hThread = GetCurrentThread();
SetLastError(ERROR_SUCCESS);
int funcCount = GetThreadCallStack(hThread, 100, frames, STACKSNAP_RETURN_FRAMES_ON_ERROR, 0);
bool success = GetLastError() == ERROR_SUCCESS;

但由于某种原因,它的头文件未包含在Windows CE SDK中。因此,您需要手动声明它:

extern "C" {
    typedef struct _CallSnapshot {
        DWORD dwReturnAddr;
    } CallSnapshot;

    typedef struct _CallSnapshotEx {
        DWORD dwReturnAddr;
        DWORD dwFramePtr;
        DWORD dwCurProc;
        DWORD dwParams[4];
    } CallSnapshotEx;

    ULONG GetThreadCallStack (HANDLE hThrd, ULONG dwMaxFrames, LPVOID lpFrames, DWORD dwFlags, DWORD dwSkip);
    ULONG GetCallStackSnapshot (ULONG dwMaxFrames, CallSnapshot lpFrames[], DWORD dwFlags, DWORD dwSkip);

    #define STACKSNAP_FAIL_IF_INCOMPLETE     1
    #define STACKSNAP_EXTENDED_INFO          2
    #define STACKSNAP_INPROC_ONLY            4
    #define STACKSNAP_RETURN_FRAMES_ON_ERROR 8
}

然后解码调用堆栈,您必须(1)找出每个返回地址的模块(EXE或DLL),以及(2)找出该模块中的函数。

我问another question about getting the module from a code address;理论上,可以将地图文件解析为figure out which function (in that module) the address belongs to(感谢链接的ctacke)。

答案 1 :(得分:3)

我也使用GetThreadCallStack,效果很好。一般来说,wince是最糟糕的平台,在调试方面具有最差的工具。关于doctorwatson的msdn上的所有BS都需要成为合作伙伴或使用平台构建器。那些需要在发布应用程序的运行时解决崩溃源的常规开发人员呢?!在数字时代和计算机时,这些"酷"地图文件的技巧听起来相当迟钝;这种任务非常适合计算机。 在wince上获取调用堆栈的唯一方法是GetThreadCallStack。与操作系统无关的代码"原始海报提到的不适用于wince。对于作者来说,使用他的编译器/ os / cpu组合工作已经足够好了,但它对wince没有用处(特别是它不能处理恢复PC寄存器的LDR指令)。我浪费了一些时间来使代码工作,总的来说我决定跳过它并浪费一大堆:那种代码必须由操作系统或编译器制造商编写,很难让它适用于所有人可能的生成代码类型。

对于那些拒绝使用地图文件的所有内容的人,我可以推荐一种可以帮助您避免该步骤的工具。 John Robbins的CrashFinder.exe可以为你做那部分。 此外,当您从GetThreadCallStack获取callstack时,清除最顶层字节的打印地址:

unsigned addr = addr1 & 0x00ffffff;

然后,在崩溃查找器中,您需要打开wince应用程序的exe文件,您可以查询地址,如果地址在您的应用程序中,它将显示功能名称。通常,如果在winapi内部发生崩溃,我需要从callstack手动输入每个地址,直到找到我应用程序中的最后一个地址。

答案 2 :(得分:2)

这些文章都讨论了将地址转换为源代码中的一行代码,可能会有所帮助: