Advertisement
Swiftkill

Call stack print (Win32\64 Vista+\VS2010

Dec 13th, 2020 (edited)
708
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.00 KB | None | 0 0
  1. #include <Windows.h>
  2. #include <DbgHelp.h> // need  DbgHelp32.lib
  3. #include <string>
  4.  
  5. #define TRACE_MAX_STACK_FRAMES 1024
  6. #define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
  7.  
  8. template <typename I>
  9. std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1)
  10. {
  11.     std::string rc(hex_len,'0');
  12.     for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
  13.         rc[i] = ((w>>j) & 0x0f)["0123456789ABCDEF"];
  14.     return rc;
  15. }
  16.  
  17. // Outputs current frames without (skip_frames+1) frames from top of stack stack.
  18. // not usable for exceptions and uses CaptureStackBackTrace из Windows Vista SDK (default VS2010)
  19. // might need StackWalk64 fore more details about stack.
  20. static bool GetStackWalk( std::string &outWalk, USHORT skip_frames = 0)
  21. {
  22.     // RTTI for .pdb symbols. Might want this in global scope
  23.     static struct SymServer {
  24.         bool good;
  25.         SymServer() : good(false) {
  26.             // deferred load, allow 32bit, undecorate names.
  27.             ::SymSetOptions( SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME );
  28.             // Microsoft symbol servers.
  29.             good = ::SymInitialize( ::GetCurrentProcess(),
  30.                 NULL, //  user path to .pdb
  31.                 TRUE ) == TRUE;
  32.         }
  33.         ~SymServer() { ::SymCleanup( ::GetCurrentProcess() ); }
  34.     } SymServerGuard;
  35.  
  36.     if(!SymServerGuard.good) return false;
  37.     auto hProcess = ::GetCurrentProcess();
  38.  
  39.     // up to TRACE_MAX_STACK_FRAMES
  40.     PVOID addrs[ TRACE_MAX_STACK_FRAMES ] = { };
  41.     // 1st frame is GetStackWalk.
  42.     USHORT usFrames = CaptureStackBackTrace( 1 + skip_frames, TRACE_MAX_STACK_FRAMES - skip_frames, addrs, NULL );
  43.  
  44.     outWalk.append("=== Stack backtrace:\n");
  45.  
  46.     for (long long i = 0; i < usFrames; i++) {
  47.         // buffer for SYMBOL_INFO with string of 1024 bytes.
  48.         ULONG64 buffer[ (sizeof( SYMBOL_INFO ) + TRACE_MAX_FUNCTION_NAME_LENGTH + sizeof( ULONG64 ) - 1) / sizeof( ULONG64 ) ] = { 0 };
  49.        
  50.         SYMBOL_INFO *info = new (buffer) SYMBOL_INFO;
  51.         info->SizeOfStruct = sizeof( SYMBOL_INFO );
  52.         info->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
  53.  
  54.         DWORD64 displacement = 0;
  55.         IMAGEHLP_LINE64 line =  { sizeof(IMAGEHLP_LINE64) };
  56.  
  57.         // frame number
  58.         outWalk.append(std::to_string(i)).append( ". " );
  59.        
  60.         DWORD disp = 0;
  61.         // Attempt to get information about the symbol and add it to our output parameter.
  62.         if(::SymFromAddr( hProcess, DWORD64(addrs[ i ]), &displacement, info ))
  63.         {
  64.            // attempt to get line info, if it present      
  65.            if (::SymGetLineFromAddr64(hProcess, DWORD(addrs[ i ]), &disp, &line))
  66.            {
  67.                outWalk.append( info->Name, info->NameLen ).append(" : 0x").append(n2hexstr(line.Address))
  68.                    .append("\n\t\"").append(line.FileName).append("\" line: ").append(std::to_string((long long)line.LineNumber))
  69.                    .append(" + ").append(std::to_string((long long)disp));
  70.            }
  71.            else
  72.            {
  73.                outWalk.append( info->Name, info->NameLen );
  74.            }
  75.         }
  76.         outWalk.append( "\n" );
  77.     }
  78.  
  79.     return true;
  80. }
  81.  
  82. // Test thing
  83. struct S {
  84.     S() {
  85.     std::string s;
  86.     GetStackWalk(s);
  87.  
  88.     std::cout  << s << std::endl;
  89.     }
  90. } s;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement