How to decode a Windows CE call stack?

Windows desktop operating systems have the "StackWalk64" feature, on which Jochen Kalmbach made a library for decoding a 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 as soon as I have unprocessed return addresses like me

  • Identify a module (DLL or EXE) from each program counter?
  • Define a function that contains the address using my .map or .pdb files?

PS. If this helps someone, I also found OS-agnostic code to jump into the ARM call stack. This seems to be really hard to do reliably!

+4
source share
3 answers

Ok, I understood half of this. 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 the Windows CE SDK. So 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 need to (1) compute the module (EXE or DLL) of each return address and (2) determine the function inside that module.

I asked another question about how to get a module from a coding address ; and theoretically it would be possible to analyze the map file to find out which function (in this module) belongs to the address (thanks to ctacke for link).

+4
source

I also use GetThreadCallStack, it works very well. All in all, this is the worst platform with the worst tools when it comes to debugging. All BSs on msdn about doctorwatson must be partners or use the platform constructor. What about regular developers who need to resolve the source of crashes during release releases? In the digital age and computers, these “cool” map file tricks sound pretty slow; This task is ideal for computers. The only way to get the call stack in 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 work with his / os / cpu combo compiler, but it does not work for wince (in particular, it does not process LDR instructions that restore the PC case). I spent some time for this code to work, in general, I decided to skip it and a lot of waste: this code must be written by the manufacturer of the os or compiler, it is very difficult to make it work perfectly for all possible types of generated code.

For those who refuse to use all this mess with map files, I can recommend a tool that will help you avoid this step. John Robbins CrashFinder.exe can do this part for you. Also, when you get a column from GetThreadCallStack, print the addresses with the highest byte:

 unsigned addr = addr1 & 0x00ffffff; 

Then, in search of failures, you need to open the exe file of your wince application, and you can request addresses, and it will show you the names of the functions if the addresses are in your application. Usually, if an accident occurs somewhere inside winapi, I need to manually enter each address from callstack until I find the last one that was in my application.

+3
source

These articles discuss the conversion of an address to a line of code in the source and may be useful:

+2
source

All Articles