locked
DbgHelp StackWalk64 stuck on frame for KiFastSystemCallRet RRS feed

  • Question

  • I've been working on some code for unmanaged C++ to obtain a stack dump following an exception such as an access violation. Many years ago, I had written something which used ImageHlp under VS 6 and it seemed to work fine. After updating to later versions of Visual Studio, things kind of went off the rails. I'm now trying to resurrect the code in a VS 2005 project on XP, using the *64 calls and DbgHelp. Portions work - I can get line numbers/symbols where one would expect (for the address where the exception occurred), but the stack walk is broken... all I get is an address for KiFastSystemCallRet. I'm building with "omit frame pointer" set to "No" (so frame pointers should be there for StackWalk64 to follow), and I've installed the latest platform SDK suitable for VS2005/XP, building against the appropriate dbghelp.h and dbghelp.lib, loading what should be the appropriate dbghelp.dll...

    static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD64 dwPCAddress)
    {
    	// Designed for use with StackWalk
    	return SymFunctionTableAccess64(hProcess, dwPCAddress);
    }
    void GetStackDump(DWORD dwInitialAddress)
    {
    	HANDLE hProcess = ::GetCurrentProcess();
    	HANDLE hThread = ::GetCurrentThread();
    	CONTEXT threadContext;
    	threadContext.ContextFlags = CONTEXT_FULL;
    	if (::GetThreadContext(hThread, &threadContext))
    	{
    		STACKFRAME64 stackFrame;
    		memset(&stackFrame, 0, sizeof(stackFrame));
    		stackFrame.AddrPC.Mode = AddrModeFlat;
    		DWORD dwMachType;
    #if defined(_M_IX86)
    		dwMachType                  = IMAGE_FILE_MACHINE_I386;
    		// program counter, stack pointer, and frame pointer
    		stackFrame.AddrPC.Offset    = threadContext.Eip;
    		stackFrame.AddrStack.Offset = threadContext.Esp;
    		stackFrame.AddrStack.Mode   = AddrModeFlat;
    		stackFrame.AddrFrame.Offset = threadContext.Ebp;
    		stackFrame.AddrFrame.Mode   = AddrModeFlat;
    #elif defined(_M_MRX000)
    		// only program counter
    		dwMachType                  = IMAGE_FILE_MACHINE_R4000;
    		stackFrame.AddrPC. Offset    = treadContext.Fir;
    #elif defined(_M_ALPHA)
    		// only program counter
    		dwMachType                  = IMAGE_FILE_MACHINE_ALPHA;
    		stackFrame.AddrPC.Offset    = (unsigned long) threadContext.Fir;
    #elif defined(_M_PPC)
    		// only program counter
    		dwMachType                  = IMAGE_FILE_MACHINE_POWERPC;
    		stackFrame.AddrPC.Offset    = threadContext.Iar;
    #elif
    #error("Unknown Target Machine");
    #endif
    		for (int nFrame=0; nFrame < 1024; nFrame++)
    		{
    			if (!StackWalk64(dwMachType, hProcess, hProcess,
    				&stackFrame, &threadContext, NULL,
    				FunctionTableAccess, GetModuleBase, NULL))
    			{
    				break;
    			}
    			// Get the caller address
    			void* caller_address = (void*)(stackFrame.AddrPC.Offset); 
    			// store caller_address for use in calls to routines such as SymGetModuleInfo64
    			// SymGetLineFromAddr64, SymGetSymFromAddr64, etc.
    		}
    	}
    }

    ... so no matter what test case I try, why do I only get the appearance of a couple of frames, none of which represents the actual call stack?

    Tuesday, September 25, 2012 2:38 AM

Answers

  • I think you are using dghelp.dll.  Did you look at this code from pinvoke

    http://www.pinvoke.net/default.aspx/dbghelp/MiniDumpWriteDump.html

    The code is using the msdn documentation fro this webpage

    http://msdn.microsoft.com/en-us/library/ms680360(v=vs.85).aspx

    Read the remarks at the bottom of the page to see if they apply to your problem.

    also see StackWalk64 documentation

    http://msdn.microsoft.com/en-us/library/ms680650(v=vs.85).aspx

    The StackWalk64 function provides a portable method for obtaining a stack trace. Using the StackWalk64 function is recommended over writing your own function because of all the complexities associated with stack walking on platforms. In addition, there are compiler options that cause the stack to appear differently, depending on how the module is compiled. By using this function, your application has a portable stack trace that continues to work as the compiler and operating system change.

    The first call to this function will fail if the AddrPC, AddrFrame, and AddrStack members of the STACKFRAME64 structure passed in the StackFrame parameter are not initialized.

    All DbgHelp functions, such as this one, are single threaded. Therefore, calls from more than one thread to this function will likely result in unexpected behavior or memory corruption. To avoid this, you must synchronize all concurrent calls from more than one thread to this function.

    This function supersedes the StackWalk function. For more information, see Updated Platform Support. StackWalk is defined as follows in DbgHelp.h.


    jdweng

    • Marked as answer by Mike Feng Wednesday, September 26, 2012 10:56 AM
    Tuesday, September 25, 2012 6:55 AM

All replies

  • I think you are using dghelp.dll.  Did you look at this code from pinvoke

    http://www.pinvoke.net/default.aspx/dbghelp/MiniDumpWriteDump.html

    The code is using the msdn documentation fro this webpage

    http://msdn.microsoft.com/en-us/library/ms680360(v=vs.85).aspx

    Read the remarks at the bottom of the page to see if they apply to your problem.

    also see StackWalk64 documentation

    http://msdn.microsoft.com/en-us/library/ms680650(v=vs.85).aspx

    The StackWalk64 function provides a portable method for obtaining a stack trace. Using the StackWalk64 function is recommended over writing your own function because of all the complexities associated with stack walking on platforms. In addition, there are compiler options that cause the stack to appear differently, depending on how the module is compiled. By using this function, your application has a portable stack trace that continues to work as the compiler and operating system change.

    The first call to this function will fail if the AddrPC, AddrFrame, and AddrStack members of the STACKFRAME64 structure passed in the StackFrame parameter are not initialized.

    All DbgHelp functions, such as this one, are single threaded. Therefore, calls from more than one thread to this function will likely result in unexpected behavior or memory corruption. To avoid this, you must synchronize all concurrent calls from more than one thread to this function.

    This function supersedes the StackWalk function. For more information, see Updated Platform Support. StackWalk is defined as follows in DbgHelp.h.


    jdweng

    • Marked as answer by Mike Feng Wednesday, September 26, 2012 10:56 AM
    Tuesday, September 25, 2012 6:55 AM
  • Thanks... I think I just spotted the error in my code... in my call to StackWalk64, I specify hProcess as both the process handle AND thread handle!

    Wednesday, September 26, 2012 12:54 AM