1

So, working with Visual Studio 2008 developing native C++ code for a Windows CE 6.0 platform. Consider the following multithreaded application:

#include "stdafx.h"

void IncrementCounter(int& counter)
{
    if (++counter >= 1000)
    {
        counter = 0;
    }
}

unsigned long ThreadFunction(void* arguments)
{
    int threadCounter = 0;

    while (true)
    {
         Sleep(20);

         IncrementCounter(threadCounter);
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{

    CreateThread(
                    NULL,       
                    0,          
                    (LPTHREAD_START_ROUTINE)ThreadFunction, 
                    NULL,       
                    0,          
                    NULL        
                 );


    int mainCounter = 0;

    while (true)
    {
        Sleep(20);

        IncrementCounter(mainCounter);
    }

    return 0;
}

When I build this to run on my Windows 7 dev. machine and run a debug session from Visual Studio with a breakpoint on the counter = 0; statement, execution will eventually break and two threads will be displayed in the "Threads" debug window. I can switch back and forth between the two threads using either a double-click or right-click->"Switch to Thread" and see a call stack and browse source and inspect symbols (for the call stack frames within my application code) for both threads. However when I do the same on Windows CE connecting via. ActiveSync/WMDC (have tried on both our custom CE 6.0 hardware with an in-house OS and SDK, and an old Windows mobile 5.0 PDA with the stock MS SDK) I can see a call stack and browse source for the thread in which the break has taken place (where the current execution point is within my application code), however I don't get anything useful for the other thread, which is currently blocked in kernel space waiting it's sleep timeout.

Anyone know whether it's possible to get this working better on Windows CE? I'm guessing it might be something to do with the debugger not knowing where to find .pdb symbol files for the WinCE kernel elements, or perhaps do I need to be running a Debug OS?

Windows CE 6 remote debugging. No call stack when pause program describes the same issue, but doesn't really provide a solution

thanks

Richard

Community
  • 1
  • 1
Richard Lang
  • 456
  • 4
  • 15

1 Answers1

0

Probably its because of missing pdb file for coredll.dll. If you are creating image for your device you will have access to this file, otherwise I am afraid its platform dependent.

You can find here that this issue is considered to be by design in VS2005 so maybe its the same for VS2008:

http://connect.microsoft.com/VisualStudio/feedback/details/190785/unable-to-debug-windows-mobile-application-that-is-in-a-system-call

In following link you can find some instructions for finding call stack using platform builder for "Thread That Is Not Running"

https://distrinet.cs.kuleuven.be/projects/SEESCOA/internal/workpackages/workpackage6/Task6dot2/ESCE/classes/331.pdf

Since I'am using only VS 2005 I cannot confirm if its of any help.

If logging is not sufficient (as was suggested in the SO link you provided), to find call stack for a thread like in your example I suggest using GetThreadCallStack function. Here is a step by step procedure:

1 - Add following code to your project:

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

#define STACKSNAP_EXTENDED_INFO 2

DWORD dwGUIThread;
void DumpGUIThreadCallStack() {
  HINSTANCE hCore = LoadLibrary(_T("coredll.dll"));
  typedef ULONG (*GETTHREADCALLSTACK)(HANDLE hThrd, ULONG dwMaxFrames, LPVOID lpFrames[], DWORD dwFlags,DWORD dwSkip);
  GETTHREADCALLSTACK pGetThreadCallStack = (GETTHREADCALLSTACK)GetProcAddress(hCore, _T("GetThreadCallStack"));
  if ( !pGetThreadCallStack )
    return;

  #define MAX_FRAMES 40
  CallSnapshotEx  lpFrames[MAX_FRAMES];
  DWORD dwCnt = pGetThreadCallStack((HANDLE)dwGUIThread, MAX_FRAMES, (void**)lpFrames, STACKSNAP_EXTENDED_INFO, 0);

  TCHAR szBuff[64];
  for ( DWORD i = 0; i < dwCnt; ++i ) {
    wsprintf(szBuff, L"[%d] %p\n", i, lpFrames[i].dwReturnAddr);
    OutputDebugString(szBuff);
  }
}

it will dump in Output window call frames return addresses (sample output is in point 3).

2 - initialize dwGUIThread in WinMain:

dwGUIThread = GetCurrentThreadId();

3 - execute DumpGUIThreadCallStack(); before actuall breakpoint inside ThreadFunction. It will write to output window text similar to this:

[0] 8C04D2C4
[1] 8C04D34C
[2] 40026D48
[3] 000111F4 <--- 1
[4] 00011BAC <--- 2
[5] 4003C2DC

1 and 2 are return addresses that you are interested in, and you want to find symbols nearest to them.

4 - while inside debugger switch to disassembly mode (right click on source file and choose 'Go to disassembly'). In this mode at the top of the window you will see Address: line. You should copy paste to it addresses from output window, in my case 000111F4 will direct me to following lines:

      while (true)
      {
          Sleep(20);
000111F0  mov         r0, #0x14 
000111F4  bl          0001193C  // <--- 1

          IncrementCounter(mainCounter);

which gives you what your GUI thread is actually doing.


Visual Studio Debugger allows to execute functions from immediate window, but I was unable to call DumpGUIThreadCallStack, I am always getting 'Error: function evaluation not supported'.

To find nearest symbols for frame return addresses you can also use .map files together with .cod files (/FAcs compiled sources), there are some good tutorials on that on google.

Above example was tested with the use of VS 2005 and Standard SDK 5.0, on WCE6.0 (end user) device.

marcinj
  • 48,511
  • 9
  • 79
  • 100