I am using Stackdumps with Win32, to write all return adresses into my logfile. I match these with a mapfile later on (see my article [Post Mortem Debugging][1]).
EDIT:: Problem solved - see my own answer below.
With Windows x64 i do not find a reliable way to write only the return adresses into the logfile. I tried several ways:
Trial 1: Pointer Arithmetic:
CONTEXT Context;
RtlCaptureContext(&Context);
char *eNextBP = (char *)Context.Rdi;
for(ULONG Frame = 0; eNextBP ; Frame++)
{
char *pBP = eNextBP;
eNextBP = *(char **)pBP; // Next BP in Stack
fprintf(LogFile, "*** %2d called from %016LX (pBP at %016LX)
", Frame,
(ULONG64)*(char **)(pBP + 8), (ULONG64)pBP);
}
This works fine in the debug version - but it crashes in the release version. The value of Context.Rdi has no usable value there. I did check for differences in the compiler settings (visual Studio 2005). I have not found anything suspicious.
Trial 2: Using StackWalk64
RtlCaptureContext(&Context);
STACKFRAME64 stk;
memset(&stk, 0, sizeof(stk));
stk.AddrPC.Offset = Context.Rip;
stk.AddrPC.Mode = AddrModeFlat;
stk.AddrStack.Offset = Context.Rsp;
stk.AddrStack.Mode = AddrModeFlat;
stk.AddrFrame.Offset = Context.Rbp;
stk.AddrFrame.Mode = AddrModeFlat;
for(ULONG Frame = 0; ; Frame++)
{
BOOL result = StackWalk64(
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
GetCurrentProcess(), // __in HANDLE hProcess,
GetCurrentThread(), // __in HANDLE hThread,
&stk, // __inout LP STACKFRAME64 StackFrame,
&Context, // __inout PVOID ContextRecord,
NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
SymFunctionTableAccess64, // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
SymGetModuleBase64, // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
NULL // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
fprintf(gApplSetup.TraceFile, "*** %2d called from %016LX STACK %016LX FRAME %016LX
", Frame, (ULONG64)stk.AddrPC.Offset, (ULONG64)stk.AddrStack.Offset, (ULONG64)stk.AddrFrame.Offset);
if(! result)
break;
}
This does not only dump the return addresses, but the WHOLE STACK. I receive about 1000 lines in my log file using this approach. I can use this, but i have to search trough the lines and some data of the stacks happens to be a valid code address.
Trial 3: Using Backtrace
static USHORT (WINAPI
*s_pfnCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG) = 0;
if (s_pfnCaptureStackBackTrace == 0)
{
const HMODULE hNtDll = ::GetModuleHandle("ntdll.dll");
reinterpret_cast<void*&>(s_pfnCaptureStackBackTrace)
= ::GetProcAddress(hNtDll, "RtlCaptureStackBackTrace");
}
PVOID myFrames[128];
s_pfnCaptureStackBackTrace(0, 128, myFrames, NULL);
for(int ndx = 0; ndx < 128; ndx++)
fprintf(gApplSetup.TraceFile, "*** BackTrace %3d %016LX
", ndx, (ULONG64)myFrames[ndx]);
Results in no usable information.
Has anyone implemented such a stack walk in x64 that does only write out the return adresses in the stack? Ive seen the approaches [StackTrace64][2], [StackWalker][3] and other ones. They either do not compile or they are much too much comlicated. It basically is a simple task!
Sample StackDump64.cpp
#include <Windows.h>
#include <DbgHelp.h>
#include <Winbase.h>
#include <stdio.h>
void WriteStackDump()
{
FILE *myFile = fopen("StackDump64.log", "w+t");
CONTEXT Context;
memset(&Context, 0, sizeof(Context));
RtlCaptureContext(&Context);
RtlCaptureContext(&Context);
STACKFRAME64 stk;
memset(&stk, 0, sizeof(stk));
stk.AddrPC.Offset = Context.Rip;
stk.AddrPC.Mode = AddrModeFlat;
stk.AddrStack.Offset = Context.Rsp;
stk.AddrStack.Mode = AddrModeFlat;
stk.AddrFrame.Offset = Context.Rbp;
stk.AddrFrame.Mode = AddrModeFlat;
for(ULONG Frame = 0; ; Frame++)
{
BOOL result = StackWalk64(
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
GetCurrentProcess(), // __in HANDLE hProcess,
GetCurrentThread(), // __in HANDLE hThread,
&stk, // __inout LP STACKFRAME64 StackFrame,
&Context, // __inout PVOID ContextRecord,
NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
SymFunctionTableAccess64, // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
SymGetModuleBase64, // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
NULL // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);
fprintf(myFile, "*** %2d called from %016I64LX STACK %016I64LX AddrReturn %016I64LX
", Frame, stk.AddrPC.Offset, stk.AddrStack.Offset, stk.AddrReturn.Offset);
if(! result)
break;
}
fclose(myFile);
}
void funcC()
{
WriteStackDump();
}
void funcB()
{
funcC();
}
void funcA()
{
funcB();
}
int main(int argc, char *argv[])
{
funcA();
}
Running this sample results in the follwing log file content:
*** 0 called from 000000014000109E STACK 000000000012F780 AddrReturn 0000000140005798
*** 1 called from 000000001033D160 STACK 000000000012F788 AddrReturn 00000001400057B0
*** 2 called from 00000001400057B0 STACK 000000000012F790 AddrReturn 0000000000000001
*** 3 called from 0000000000000002 STACK 000000000012F798 AddrReturn 00000001400057B0
*** 4 called from 0000000000000002 STACK 000000000012F7A0 AddrReturn 000000000012F7F0
*** 5 called from 000000000012F7F0 STACK 000000000012F7A8 AddrReturn 0000000000000000
*** 6 called from 0000000000000000 STACK 000000000012F7B0 AddrReturn 000007FF7250CF40
*** 7 called from 000007FF7250CF40 STACK 000000000012F7B8 AddrReturn 000007FF7250D390
*** 8 called from 000007FF7250D390 STACK 000000000012F7C0 AddrReturn 000007FF725B6950
*** 9 called from 000007FF725B6950 STACK 000000000012F7C8 AddrReturn CCCCCCCCCCCCCCCC
*** 10 called from CCCCCCCCCCCCCCCC STACK 000000000012F7D0 AddrReturn 000000001033D160
*** 11 called from 000000001033D160 STACK 000000000012F7D8 AddrReturn CCCCCCCCCCCCCCCC
*** 12 called from CCCCCCCCCCCCCCCC STACK 000000000012F7E0 AddrReturn CCCCCCCCCCCCCCCC
*** 13 called from CCCCCCCCCCCCCCCC STACK 000000000012F7E8 AddrReturn CCCCCCCCCCCCCCCC
*** 14 called from CCCCCCCCCCCCCCCC STACK 000000000012F7F0 AddrReturn 0000000000000000
*** 15 called from 0000000000000000 STACK 000000000012F7F8 AddrReturn 0000000000000000
*** 16 called from 0000000000000000 STACK 000000000012F800 AddrReturn 0000000000000000
*** 17 called from 0000000000000000 STACK 000000000012F808 AddrReturn 0000000000000000
*** 18 called from 0000000000000000 STACK 000000000012F810 AddrReturn 0000000000000000
*** 19 called from 0000000000000000 STACK 000000000012F818 AddrReturn 0000000000000000
*** 20 called from 0000000000000000 STACK 000000000012F820 AddrReturn 00001F800010000F
*** 21 called from 00001F800010000F STACK 000000000012F828 AddrReturn 0053002B002B0033
*** 22 called from 0053002B002B0033 STACK 000000000012F830 AddrReturn 00000206002B002B
*** 23 called from 00000206002B002B STACK 000000000012F838 AddrReturn 0000000000000000
*** 24 called from 0000000000000000 STACK 000000000012F840 AddrReturn 0000000000000000
*** 25 called from 0000000000000000 STACK 000000000012F848 AddrReturn 0000000000000000
*** 26 called from 0000000000000000 STACK 000000000012F850 AddrReturn 0000000000000000
*** 27 called from 0000000000000000 STACK 000000000012F858 AddrReturn 0000000000000000
*** 28 called from 0000000000000000 STACK 000000000012F860 AddrReturn 0000000000000000
*** 29 called from 0000000000000000 STACK 000000000012F868 AddrReturn 0000000000000246
*** 30 called from 0000000000000246 STACK 000000000012F870 AddrReturn 000000000012F7F0
*** 31 called from 000000000012F7F0 STACK 000000000012F878 AddrReturn 0000000000000000
*** 32 called from 0000000000000000 STACK 000000000012F880 AddrReturn 0000000000000000
*** 33 called from 0000000000000000 STACK 000000000012F888 AddrReturn 000000000012F888
*** 34 called from 000000000012F888 STACK 000000000012F890 AddrReturn 0000000000000000
*** 35 called from 0000000000000000 STACK 000000000012F898 AddrReturn 0000000000000000
*** 36 called from 0000000000000000 STACK 000000000012F8A0 AddrReturn 000000000012FE10
*** 37 called from 000000000012FE10 STACK 000000000012F8A8 AddrReturn 0000000000000000
*** 38 called from 0000000000000000 STACK 000000000012F8B0 AddrReturn 0000000000000000
*** 39 called from 0000000000000000 STACK 000000000012F8B8 AddrReturn 0000000000000000
*** 40 called from 0000000000000000 STACK 000000000012F8C0 AddrReturn 0000000000000246
*** 41 called from 0000000000000246 STACK 000000000012F8C8 AddrReturn 0000000000000000
*** 42 called from 0000000000000000 STACK 000000000012F8D0 AddrReturn 0000000000000000
*** 43 called from 0000000000000000 STACK 000000000012F8D8 AddrReturn 0000000000000000
*** 44 called from 0000000000000000 STACK 000000000012F8E0 AddrReturn 0000000000000000
*** 45 called from 0000000000000000 STACK 000000000012F8E8 AddrReturn 0000000000000000
*** 46 called from 0000000000000000 STACK 000000000012F8F0 AddrReturn 000000000000027F
*** 47 called from 000000000000027F STACK 000000000012F8F8 AddrReturn 0000000000000000
*** 48 called from 0000000000000000 STACK 000000000012F900 AddrReturn 0000000000000000
*** 49 called from 0000000000000000 STACK 000000000012F908 AddrReturn 0000FFFF00001F80
*** 50 called from 0000FFFF00001F80 STACK 000000000012F910 AddrReturn 0000000000000000
*** 51 called from 0000000000000000 STACK 000000000012F918 AddrReturn 0000000000000000
*** 52 called from 0000000000000000 STACK 000000000012F920 AddrReturn 0000000000000000
*** 53 called from 0000000000000000 STACK 000000000012F928 AddrReturn 0000000000000000
*** 54 called from 0000000000000000 STACK 000000000012F930 AddrReturn 0000000000000000
*** 55 called from 0000000000000000 STACK 000000000012F938 AddrReturn 0000000000000000
*** 56 called from 0000000000000000 STACK 000000000012F940 AddrReturn 0000000000000000
*** 57 called from 0000000000000000 STACK 000000000012F948 AddrReturn 0000000000000000
*** 58 called from 0000000000000000 STACK 000000000012F950 AddrRet