I've got simple C++ Windows program that prints stack trace. Tried different codes I found on internet and still getting same results. When optimizations are off, things get displayed correctly. Once I turn them on(or switch from Debug build to Release build in VS), specifically I use /O2(but doesn't work with other optimization flags too), only main function gets printed on screen even though there should be more functions on stack. I thought that maybe that function gets inlined but I think that this isn't the case, I can turn any optimization setting on, like force inline anywhere possible etc. and just works fine, once I turn on /O2, /O1 etc. it shows just main. PDB files are generated so that shouldn't cause any problems.
I'd appreciate any help, or if anyone knows some other way/library to show stack trace.
Output with optimizations off, you can see func2 and func3 displayed correctly:
Line: 78 | Function name: func2 | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 83 | Function name: func3 | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 88 | Function name: main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 78 | Function name: invoke_main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 288 | Function name: __scrt_common_main_seh | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 331 | Function name: __scrt_common_main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 17 | Function name: mainCRTStartup | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 0 | Function name: BaseThreadInitThunk | Module name: C:\WINDOWS\System32\KERNEL32.DLL
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
L
Output with /O2 flag, func2 and func3 are missing:
Line: 88 | Function name: main | Module name: D:\ConsoleApplication3\Release\ConsoleApplication3.exe
Line: 288 | Function name: __scrt_common_main_seh | Module name: D:\ConsoleApplication3\Release\ConsoleApplication3.exe
Line: 0 | Function name: BaseThreadInitThunk | Module name: C:\WINDOWS\System32\KERNEL32.DLL
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
This is code I am currently using, this runs only on x86:
#include <windows.h>
#include <iostream>
#include <dbghelp.h>
void stacktrace()
{
DWORD machine = IMAGE_FILE_MACHINE_I386;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context = {};
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
SymInitialize(process, NULL, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES);
STACKFRAME frame = {};
frame.AddrPC.Offset = context.Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Esp;
frame.AddrStack.Mode = AddrModeFlat;
while (StackWalk(machine, process, thread, &frame, &context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
{
DWORD64 functionAddress;
std::string moduleName;
std::string functioName;
std::string file;
unsigned int _line = 0;
functionAddress = frame.AddrPC.Offset;
DWORD moduleBase = SymGetModuleBase(process, frame.AddrPC.Offset);
char moduleBuff[MAX_PATH];
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduleBuff, MAX_PATH))
{
moduleName = moduleBuff;
}
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 255];
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
symbol->SizeOfStruct = (sizeof IMAGEHLP_SYMBOL) + 255;
symbol->MaxNameLength = 254;
if (SymGetSymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
{
functioName = symbol->Name;
}
DWORD offset = 0;
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (SymGetLineFromAddr(process, frame.AddrPC.Offset, &offset, &line))
{
file = line.FileName;
_line = line.LineNumber;
}
std::cout
<< "Line: " << _line
<< " | Function name: " << functioName
<< " | Module name: " << moduleName
<< std::endl;
}
SymCleanup(process);
}
void func2()
{
stacktrace();
}
void func3()
{
func2();
}
int main()
{
func3();
system("pause");
return 0;
}