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