CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 4 of 4

Thread: Using StackWalk

  1. #1
    Join Date
    Apr 1999
    Posts
    10

    Using StackWalk

    Does anyone know how to use the StackWalk function? The documentation is not that clear. A short example would be greatly appreciated.

    Thanks!

    Chuck Grady


  2. #2
    Join Date
    May 1999
    Posts
    3

    Re: Using StackWalk

    Here's an example that I cobbled together from various sources. It's a function that you can call to find the symbolic name of the function that called the one your calling from. I hope that the wordwrap doesn't mess it up too badly.

    //****************************************************************************
    // FILE : ShowStack.C
    // DATE: 03/29/99
    // AUTHOR : Michael Sullivan (Z92943)
    //
    // PURPOSE: This file implements a stack trace using the ImageHlp dll.
    // The one function GetCallingFunctionName will return the text name
    // of the function that called the function calling GetCallingFunctionName.
    // ie Function A calls Function B.
    // Function B needs the text name "Function A" so
    // Function B calls GetCallingFunctionName which returns
    // "Function A"
    // PARAMETERS: OUT CString callingFunctionName
    //
    //****************************************************************************

    #include "stdafx.h"
    #include <windows.h>
    #include <imagehlp.h> // link with imagehlp.lib as well...
    #include <stdio.h>
    #include <stdlib.h>
    #include <winerror.h>
    // SymCleanup()
    typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
    tSC pSC = NULL;

    // SymFunctionTableAccess()
    typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD AddrBase );
    tSFTA pSFTA = NULL;

    #ifdef NT50
    // SymGetLineFromAddr()
    typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD dwAddr,
    OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE Line );
    tSGLFA pSGLFA = NULL;
    #endif

    // SymGetModuleBase()
    typedef DWORD (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD dwAddr );
    tSGMB pSGMB = NULL;

    // SymGetModuleInfo()
    typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD dwAddr, OUT PIMAGEHLP_MODULE ModuleInfo );
    tSGMI pSGMI = NULL;

    // SymGetOptions()
    typedef DWORD (__stdcall *tSGO)( VOID );
    tSGO pSGO = NULL;

    // SymGetSymFromAddr()
    typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD dwAddr,
    OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_SYMBOL Symbol );
    tSGSFA pSGSFA = NULL;

    // SymInitialize()
    typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
    tSI pSI = NULL;

    // SymSetOptions()
    typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
    tSSO pSSO = NULL;

    // StackWalk()
    typedef BOOL (__stdcall *tSW)( DWORD MachineType, HANDLE hProcess,
    HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord,
    PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
    PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
    PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
    PTRANSLATE_ADDRESS_ROUTINE TranslateAddress );
    tSW pSW = NULL;

    // UnDecorateSymbolName()
    typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
    DWORD UndecoratedLength, DWORD Flags );
    tUDSN pUDSN = NULL;

    #define gle GetLastError()


    #define sizeof_Name 128
    #define sizeof_CONTEXT sizeof(CONTEXT)+96
    #define sizeof_STACKFRAME sizeof(STACKFRAME)+16
    #define sizeof_symbol sizeof(IMAGEHLP_SYMBOL)+sizeof_Name


    int GetCallingFunctionName(CString &callingFunctionName)
    {
    HANDLE hProc, hThread;
    CONTEXT *cxt;
    IMAGEHLP_SYMBOL *sym;
    STACKFRAME *frm;
    DWORD machType, symDisp, lastErr, filepathlen;
    BOOL stat;
    int i;
    char filepath[MAX_PATH], *lastdir, *pPath;

    HINSTANCE hImagehlpDll = NULL;

    // we load imagehlp.dll dynamically because the NT4-version does not
    // offer all the functions that are in the NT5 lib
    hImagehlpDll = LoadLibrary( "imagehlp.dll" );
    if ( hImagehlpDll == NULL )
    {
    printf( "LoadLibrary( \"imagehlp.dll\" ): gle = %lu\n", gle );
    return 0;
    }

    pSC = (tSC) GetProcAddress( hImagehlpDll, "SymCleanup" );
    pSFTA = (tSFTA) GetProcAddress( hImagehlpDll, "SymFunctionTableAccess" );
    pSGMB = (tSGMB) GetProcAddress( hImagehlpDll, "SymGetModuleBase" );
    pSGMI = (tSGMI) GetProcAddress( hImagehlpDll, "SymGetModuleInfo" );
    pSGO = (tSGO) GetProcAddress( hImagehlpDll, "SymGetOptions" );
    pSGSFA = (tSGSFA) GetProcAddress( hImagehlpDll, "SymGetSymFromAddr" );
    pSI = (tSI) GetProcAddress( hImagehlpDll, "SymInitialize" );
    pSSO = (tSSO) GetProcAddress( hImagehlpDll, "SymSetOptions" );
    pSW = (tSW) GetProcAddress( hImagehlpDll, "StackWalk" );
    pUDSN = (tUDSN) GetProcAddress( hImagehlpDll, "UnDecorateSymbolName" );

    if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
    pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
    pSW == NULL || pUDSN == NULL )
    {
    puts( "GetProcAddress(): some required function not found." );
    FreeLibrary( hImagehlpDll );
    }



    // Initialize the IMAGEHLP package to decode addresses to symbols
    //

    // Get image filename of the main executable

    filepathlen = GetModuleFileName ( NULL, filepath, sizeof(filepath));
    if (filepathlen == 0)
    printf ("NtStackTrace: Failed to get pathname for program\n");

    // Strip the filename, leaving the path to the executable

    lastdir = strrchr (filepath, '/');
    if (lastdir == NULL)
    lastdir = strrchr (filepath, '\\');
    if (lastdir != NULL)
    lastdir[0] = '\0';

    // Initialize the symbol table routines, supplying a pointer to the path

    pPath = filepath;
    if (strlen (filepath) == 0)
    pPath = NULL;

    hProc = GetCurrentProcess ();
    hThread = GetCurrentThread ();
    if ( !pSI(hProc, pPath, TRUE) )
    printf ("NtStackTrace: failed to initialize symbols\n");

    // Allocate and initialize frame and symbol structures

    frm = (STACKFRAME*)malloc (sizeof_STACKFRAME);
    memset (frm, 0, sizeof(STACKFRAME));

    sym = (IMAGEHLP_SYMBOL*)malloc (sizeof_symbol);
    memset (sym, 0, sizeof_symbol);
    sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
    sym->MaxNameLength = sizeof_Name-1;


    // Initialize the starting point based on the architecture of the current machine

    machType = IMAGE_FILE_MACHINE_I386;

    // The CONTEXT structure is not used on x86 systems

    cxt = NULL;

    // Initialize the STACKFRAME to describe the current routine

    frm->AddrPC.Mode = AddrModeFlat;
    frm->AddrStack.Mode = AddrModeFlat;
    frm->AddrFrame.Mode = AddrModeFlat;

    // If we were called from an exception handler, the exception
    // structure would contain an embedded CONTEXT structure. We
    // could initialize the following addresses from the CONTEXT
    // registers passed to us.

    // For this example, use _asm to fetch the processor register values

    _asm mov i, esp // Stack pointer (CONTEXT .Esp field)
    frm->AddrStack.Offset = i;

    _asm mov i, ebp // Frame pointer (CONTEXT .Ebp field)
    frm->AddrFrame.Offset = i;

    // We'd like to fetch the current instruction pointer, but the x86 IP
    // register is a bit special. Use roughly the current offset instead
    // of a dynamic fetch (use offset because address should be past the prologue).

    // _asm mov i, ip // ip is a special register, this is illegal
    // frm->AddrPC.Offset = i;

    frm->AddrPC.Offset = ((DWORD) &GetCallingFunctionName) + 0x08c;



    // The top stack frame is the call to this routine itself -
    // the next is the routine that called us, and the third is
    // the one that called our caller. That's the one we want to
    // return.


    for (i=0; i<3; i++)
    {

    // Call the routine to trace to the next frame

    stat = pSW( machType, hProc, hThread, frm, cxt, NULL, pSFTA, pSGMB, NULL );
    if ( !stat )
    {
    lastErr = GetLastError ();
    if (lastErr == ERROR_NOACCESS | lastErr == ERROR_INVALID_ADDRESS)
    printf (" <done>\n"); // Normal end-of-stack code
    else
    printf (" <stack walk terminated with error %d>\n",
    lastErr);
    break;
    }
    }

    // Decode the closest routine symbol name

    if ( pSGSFA( hProc, frm->AddrPC.Offset, &symDisp, sym ) )
    callingFunctionName = sym->Name;
    else
    {
    lastErr = GetLastError ();
    if (lastErr == ERROR_INVALID_ADDRESS) // Seems normal for last frame on Intel
    callingFunctionName = "<No Symbol Available>";
    else
    callingFunctionName.Format("<no symbol available - error %d>",lastErr);
    }



    free (cxt); // If on Intel, freeing the NULL CONTEXT is a no-op...
    free (frm);
    free (sym);

    return 0;
    }


  3. #3
    Join Date
    Oct 2009
    Posts
    1

    Re: Using StackWalk

    Calling SatckWalk is not working for release mode. I think this is because release mode does not have the pdb(symbol files). Correct me if wrong.
    Also let know how can we get the stack trace in release mode in when excpetion is thrown.

    Thanks in advance for ur help....

    Regards
    Sang

  4. #4
    Join Date
    Aug 1999
    Location
    <Classified>
    Posts
    6,882

    Re: Using StackWalk

    Well it would only not show the function names, but it will work for release mode too.
    Regards,
    Ramkrishna Pawar

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured