c++windowsvisual-c++

Tracing all functions in my program


Like the title says, I want to trace ALL functions calls in my application (from inside).

I tried using "_penter" but I get either a recursion limit reached error or an access violation when I try to prevent the recursion.

Is there any way to achieve this ?

Update

What I tried:

extern "C"
{
    void __declspec(naked) _cdecl _penter()
    {
        _asm {
            push    eax
            push    ecx
            push    edx
            mov     ecx, [esp + 0Ch]
            push    ecx
            mov     ecx, offset Context::Instance
            call    Context::addFrame
            pop     edx
            pop     ecx
            pop     eax
            ret
        }
}

class Context
{
 public:
    __forceinline void addFrame(const void* addr) throw() {}

    static thread_local Context Instance;
};

sadly this still gives a stack overflow due to recursion


Solution

  • but I get either a recursion limit reached error

    this can be if inside Context::addFrame implementation compiler also insert call _penter which recursive call Context::addFrame.

    but how __forceinline you can ask ? nothing. c/c++ compiler to insert a copy of the function body into each place the function is called from code which is generated by this compiler. c/c++ compiler can not insert a copy of the function body into code, which he not compile itself. so when we call function marked as __forceinline from assembler code - function will be called in usual way but not expanded in place. so your __forceinline simply have no effect and sense

    you need implement Context::addFrame (and all functions which it call) in separate c++ file (let be context.cpp) compiled without /Gh option.

    you can set /Gh for all files in project, except context.cpp

    if exist too many cpp files in project - you can set /Gh for project, but how then remove it for single file context.cpp ? exist one original way - you can copy <cmdline> for this file and that set custom build tool for it Command Line- CL.exe <cmdline> $(InputFileName) (not forget remove /Gh) and Outputs - $(IntDir)\$(InputName).obj. original by perfect work.

    so in context.cpp you can have next code:

    class Context
    {
    public:
        void __fastcall addFrame(const void* addr);
    
        int _n;
    
        static thread_local Context Instance;
    };
    
    thread_local Context Context::Instance;
    
    void __fastcall Context::addFrame(const void* addr)
    {
    #pragma message(__FUNCDNAME__)
    
        DbgPrint("%p>%u\n", addr, _n++);
    }
    

    if Context::addFrame call some another internal function (explicit or implicit) - put it also in this file, which compile without /Gh

    the _penter better implement in separate asm file, but not as inline asm (this not supported in x64 anyway)

    so for x86 you can create code32.asm ( ml /c /Cp $(InputFileName) -> $(InputName).obj)

    .686p
    
    .MODEL flat
    
    extern ?addFrame@Context@@QAIXPBX@Z:proc
    extern ?Instance@Context@@2V12@A:byte
    
    _TEXT segment 'CODE'
    
    __penter proc
        push edx
        push ecx
        mov edx,[esp+8]
        lea ecx,?Instance@Context@@2V12@A
        call ?addFrame@Context@@QAIXPBX@Z
        pop ecx
        pop edx
        ret
    __penter endp
    
    _TEXT ends
    end
    

    note - you need save only rcx and rdx (if you use __fastcall , except context.cpp, functions)

    for x64 - create code64.asm ( ml64 /c /Cp $(InputFileName) -> $(InputName).obj)

    extern ?addFrame@Context@@QEAAXPEBX@Z:proc
    extern ?Instance@Context@@2V12@A:byte
    
    _TEXT segment 'CODE'
    
    _penter proc
        mov [rsp+8],rcx
        mov [rsp+16],rdx
        mov [rsp+24],r8
        mov [rsp+32],r9
        mov rdx,[rsp]
        sub rsp,28h
        lea rcx,?Instance@Context@@2V12@A
        call ?addFrame@Context@@QEAAXPEBX@Z
        add rsp,28h
        mov r9,[rsp+32]
        mov r8,[rsp+24]
        mov rdx,[rsp+16]
        mov rcx,[rsp+8]
        ret
    _penter endp
    
    _TEXT ENDS
    end