Question

Desktop Windows OSs have a "StackWalk64" function, upon which Jochen Kalmbach made a library for decoding the call stack into something human-readable.

I need a similar tool, but for Windows CE. WinCE has a function to get the call stack, GetThreadCallStack, but once I have the raw return addresses, how do I

  1. Determine the module (DLL or EXE) from each program counter?
  2. Determine the function that contains the address, using my .map or .pdb files?

PS. If it helps anyone, I also found OS-agnostic code for walking the ARM call stack. Apparently it's really hard to do reliably!

Was it helpful?

Solution

Well, I figured out half of it. You need to call 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;

but for some reason the header file for it is not included in Windows CE SDKs. Therefore you need to declare it manually:

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
}

And then to decode the call stack you would have to (1) figure out the module (EXE or DLL) of each return address, and (2) figure out the function within that module.

I asked another question about getting the module from a code address; and in theory it would be possible to parse a map file to figure out which function (in that module) the address belongs to (thanks ctacke for the link).

OTHER TIPS

I also use GetThreadCallStack, it works quite well. In general wince is worst platform with worst tools when it comes to debugging. All BS on msdn about doctorwatson require to be partner or to use platform builder. What about regular developers who need to resolve source of crashes at runtime of release apps?! At the time of digital age and computers these "cool" tricks with map files sound pretty retarded; that kind of task is perfectly suitable for computers. The only way to get call stack on wince is GetThreadCallStack. The "OS-agnostic code" mentioned by the original poster does not work on wince. It was good enough for the author to make it work with his compiler/os/cpu combo, but it doesn't work for wince (in particular, it doesn't handle LDR instructions that restores PC register). I wasted some time to make that code work, in general I decided to skip it and pile of waste: that kind of code has to written by the os or compiler manufacturer, it's very difficult to make it working perfect for all possible types of generated code.

For those who refuse to use all that mess with map files I can recommend a tool that can help you avoid that step. John Robbins's CrashFinder.exe can do that part for you. Also, when you get callstack from GetThreadCallStack, print addresses with topmost byte cleared:

unsigned addr = addr1 & 0x00ffffff;

Then, in crash finder you need to open exe file of your wince app, and you can query the addresses and it will show you function names if the addresses are within your app. Usually, if crash happens somewhere inside winapi, I need to manually enter each address from callstack until I find the last one that was in my app.

These articles all discuss converting an address to a line of code in source and might be helpful:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top