Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7551385
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 30, 20262026-05-30T10:28:50+00:00 2026-05-30T10:28:50+00:00

I am working on a class which I would like to use to log

  • 0

I am working on a class which I would like to use to log the current Call Stack on computers with Windows Vista/7. (Very similar to “Walking the callstack” http://www.codeproject.com/Articles/11132/Walking-the-callstack).

First I used RtlCaptureContext to get the current context record then I used StackWalk64 to get the individual stack frames. Now, I realized that the Program counter in STACKFRAME64.AddrPC actually changes for a specific code line whenever I close my program and start it again. For some reason I thought that the PC-Address for a specific code line would stay the same as long as I don’t change the source code and recompile it again.

I need the PC-Address to use SymFromAddr and SymGetLineFromAddr64 to get information about the called function, code file and line number. Unfortunately that only works as long as the Program-Debug-Database (PDB-File) is around, but I am not allowed to provide that to the client.

My plan was to record the PC-Addresses of the call stack (whenever it is needed) and then send it from the client to me. So that I could use my PDB-Files to find out which functions were called but that of course only works if the PC-Addresses are unique identifiers. Since they change every time I start the program, I cannot use that approach.

Do you know a better way to read the call stack or to overcome the problem with the changing program counter?

I think one possible solution could be to always get the PC-Address of a known location and use that as a reference to determine only the offset between different PC-Addresses. That appears to work, but I am not sure if that is a valid method and will always work.

Thank you very much for your help! I will publish the final (encapsulated) solution in codeproject.com and IF YOU LIKE I will say that you helped me.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-30T10:28:52+00:00Added an answer on May 30, 2026 at 10:28 am

    Using information form CONTEXT you can find function section and offset in PE image. For example, you can use this info to get function name from .map file generated by linker.

    1. Get CONTEXT struct. You are interested in program counter member. Since CONTEXT is platform-dependent, you have to figure it out for yourself. You do it already when you initialize, for example STACKFRAME64.AddrPC.Offset = CONTEXT.Rip for x64 Windows. Now we start stack walk and use STACKFRAME64.AddrPC.Offset, filled by StaclkWalk64 as our starting point.

    2. You need to translate it to Relative Virtual Address (RVA) using allocation base address: RVA = STACKFRAME64.AddrPC.Offset - AllocationBase. You can get AllocationBase using VirtualQuery.

    3. Once you have that, you need to find into which Section this RVA falls and subtract section start address from it to get SectionOffset: SectionOffset = RVA - SectionBase = STACKFRAME64.AddrPC.Offset - AllocationBase - SectionBase. In order to do that you need to access PE image header structure (IMAGE_DOS_HEADER, IMAGE_NT_HEADER, IMAGE_SECTION_HEADER) to get number of sections in PE and their start/end addresses. It’s pretty straightforward.

    That’s it. Now you have section number and offset in PE image. Function offset is the highest offset smaller than SectionOffset in .map file.

    I can post code later, if you like.

    EDIT: Code to print function address (we assume x64 generic CPU):

    #include <iostream>
    #include <windows.h>
    #include <dbghelp.h>
    
    void GenerateReport( void )
    {
      ::CONTEXT lContext;
      ::ZeroMemory( &lContext, sizeof( ::CONTEXT ) );
      ::RtlCaptureContext( &lContext );
    
      ::STACKFRAME64 lFrameStack;
      ::ZeroMemory( &lFrameStack, sizeof( ::STACKFRAME64 ) );
      lFrameStack.AddrPC.Offset = lContext.Rip;
      lFrameStack.AddrFrame.Offset = lContext.Rbp;
      lFrameStack.AddrStack.Offset = lContext.Rsp;
      lFrameStack.AddrPC.Mode = lFrameStack.AddrFrame.Mode = lFrameStack.AddrStack.Mode = AddrModeFlat;
    
      ::DWORD lTypeMachine = IMAGE_FILE_MACHINE_AMD64;
    
      for( auto i = ::DWORD(); i < 32; i++ )
      {
        if( !::StackWalk64( lTypeMachine, ::GetCurrentProcess(), ::GetCurrentThread(), &lFrameStack, lTypeMachine == IMAGE_FILE_MACHINE_I386 ? 0 : &lContext,
                nullptr, &::SymFunctionTableAccess64, &::SymGetModuleBase64, nullptr ) )
        {
          break;
        }
        if( lFrameStack.AddrPC.Offset != 0 )
        {
          ::MEMORY_BASIC_INFORMATION lInfoMemory;
          ::VirtualQuery( ( ::PVOID )lFrameStack.AddrPC.Offset, &lInfoMemory, sizeof( lInfoMemory ) );
          ::DWORD64 lBaseAllocation = reinterpret_cast< ::DWORD64 >( lInfoMemory.AllocationBase );
    
          ::TCHAR lNameModule[ 1024 ];
          ::GetModuleFileName( reinterpret_cast< ::HMODULE >( lBaseAllocation ), lNameModule, 1024 );
    
          PIMAGE_DOS_HEADER lHeaderDOS = reinterpret_cast< PIMAGE_DOS_HEADER >( lBaseAllocation );
          PIMAGE_NT_HEADERS lHeaderNT = reinterpret_cast< PIMAGE_NT_HEADERS >( lBaseAllocation + lHeaderDOS->e_lfanew );
          PIMAGE_SECTION_HEADER lHeaderSection = IMAGE_FIRST_SECTION( lHeaderNT );
          ::DWORD64 lRVA = lFrameStack.AddrPC.Offset - lBaseAllocation;
          ::DWORD64 lNumberSection = ::DWORD64();
          ::DWORD64 lOffsetSection = ::DWORD64();
    
          for( auto lCnt = ::DWORD64(); lCnt < lHeaderNT->FileHeader.NumberOfSections; lCnt++, lHeaderSection++ )
          {
            ::DWORD64 lSectionBase = lHeaderSection->VirtualAddress;
            ::DWORD64 lSectionEnd = lSectionBase + max( lHeaderSection->SizeOfRawData, lHeaderSection->Misc.VirtualSize );
            if( ( lRVA >= lSectionBase ) && ( lRVA <= lSectionEnd ) )
            {
              lNumberSection = lCnt + 1;
              lOffsetSection = lRVA - lSectionBase;
              break;
            }
          }    
          std::cout << lNameModule << " : 000" << lNumberSection << " : " << reinterpret_cast< void * >( lOffsetSection ) << std::endl;
        }
        else
        {
          break;
        }
      }
    }
    
    void Run( void );
    void Run( void )
    {
     GenerateReport();
     std::cout << "------------------" << std::endl;
    }
    
    int main( void )
    {
      ::SymSetOptions( SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS );
      ::SymInitialize( ::GetCurrentProcess(), 0, 1 );
    
      try
      {
        Run();
      }
      catch( ... )
      {
      }
      ::SymCleanup( ::GetCurrentProcess() );
    
      return ( 0 );
    }
    

    Notice, our call stack is (inside out) GenerateReport()->Run()->main().
    Program output (on my machine, path is absolute):

    D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000002F8D
    D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 00000000000031EB
    D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000003253
    D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000007947
    C:\Windows\system32\kernel32.dll : 0001 : 000000000001552D
    C:\Windows\SYSTEM32\ntdll.dll : 0001 : 000000000002B521
    ------------------
    

    Now, call stack in terms of addresses is (inside out) 00002F8D->000031EB->00003253->00007947->0001552D->0002B521.
    Comparing first three offsets to .map file content:

    ...
    
     0001:00002f40       ?GenerateReport@@YAXXZ     0000000140003f40 f   FMain.obj
     0001:000031e0       ?Run@@YAXXZ                00000001400041e0 f   FMain.obj
     0001:00003220       main                       0000000140004220 f   FMain.obj
    
    ...
    

    where 00002f40 is closest smaller offset to 00002F8D and so on. Last three addresses refer to CRT/OS functions that call main (_tmainCRTstartup etc) – we should ignore them…

    So, we can see that we are able to recover stack trace with help of .map file. In order to generate stack trace for thrown exception, all you have to do is to place GenerateReport() code into exception constructor (in fact, this GenerateReport() was taken from my custom exception class constructor code (some part of it it) ) .

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm working on a simulation in Qt (C++), and would like to make use
My use-case: I already have a working ASP.NET application I would like to implement
I am working on an application in which I would like to implement paging.
I have gotten everything working for my class in which I am using Tomcat
I'm currently working on an oophp application. I have a site class which will
I'm working with a CMS, Joomla, and there's a core class which renders a
I am working with a wrapper class for CFHTTPMessage , which contains a CFHTTPMessageRef
I have a design problem which I would like some input on. Here are
I would like to use WMI (in C++) to configure a static IPv6 address.
I would like to exchange objects between two python interpreters working on the same

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.