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;
}
