[英]C++ - Get Starting Address of a function from Ending Address / Get size of a function
I am using /Gh and /GH compiler option of visual studio to profile a bunch of code.我正在使用 Visual Studio 的 /Gh 和 /GH 编译器选项来分析一堆代码。 Two methods used are _penter and _pexit which are called when a function is entered or exited in the code being profiled.使用的两种方法是 _penter 和 _pexit,它们在被分析的代码中进入或退出函数时调用。 Since I need specific functions being profiled/debugged, I use an already defined array FuncTable which contains the addresses of the functions I need to instrument with their names as string.由于我需要对特定函数进行分析/调试,因此我使用了一个已定义的数组FuncTable ,其中包含我需要使用其名称作为字符串进行检测的函数的地址。 So when a function is entered, the pStack[0] , which basically contains the register contents, contains the address to current line of the code being executed.因此,当输入函数时,基本上包含寄存器内容的pStack[0]包含正在执行的代码的当前行的地址。 Similarly when a function is exited, pStack[0] contains the address of last line of the code.类似地,当函数退出时, pStack[0]包含代码最后一行的地址。
THE ISSUE : When a function is entered (_penter is called), I get the address of first line of the function in pStack[0] and hence I can get the function's address by subtracting a constant(-5) and save that to my list to be retrieved later in the _pexit function.问题:当一个函数被输入时(_penter 被调用),我得到了 pStack[0] 中函数第一行的地址,因此我可以通过减去一个常量(-5)来得到函数的地址并将它保存到我的稍后在 _pexit 函数中检索的列表。 But since in _pexit I am getting address to the last line of the function, I need to find the size of the function in order to subtract that size from the address in pStack[0] to reach the starting address of the function and then compare that address to the ones saved in my list.但是由于在 _pexit 中我得到了函数最后一行的地址,我需要找到函数的大小,以便从 pStack[0] 中的地址中减去该大小以到达函数的起始地址,然后进行比较该地址指向我列表中保存的地址。 Pasted below is the code.下面贴上代码。
void _stdcall EnterFunc0(unsigned * pStack)
{
void * pCaller;
pCaller = (void *)(pStack[0] - 5); // pStack[0] is first line, -5 for function address
Signature * funct = FuncTable;
while (funct->function)
{
const BYTE * func = (const BYTE *)funct->function;
if ((func == (const BYTE *)pCaller) || ((*func == 0xE9) && ((func + *(DWORD *)(func + 1) + 5) == (const BYTE *)pCaller)))
{
Stack_Push(funct->name, funct->returnType, true, pCaller);
}
funct++;
}
}
extern "C" __declspec(naked) void __cdecl _penter()
{
_asm
{
pushad // save all general purpose registers
mov eax, esp // current stack pointer
add eax, 32 // stack pointer before pushad
push eax // push pointer to return address as parameter to EnterFunc0
call EnterFunc0
popad // restore general purpose registers
ret // start executing original function
}
}
void _stdcall ExitFunc0(unsigned * pStack)
{
if (startRecording)
{
StackEntry * start = top;
while (start != NULL)
{
//**HERE I NEED TO COMPARE THE ADDRESS OF THE FUNCTION WITH THE ONE ALREADY IN MY STACK**
if ((void *)(pStack[0] - sizeOfTheFunction) == start->Address)
{
OutputDebugString("Function Found\n");
}
start = start->next;
}
}
}
extern "C" __declspec(naked) void __cdecl _pexit()
{
_asm
{
pushad // save all general purpose registers
mov eax, esp // current stack pointer
add eax, 32 // stack pointer before pushad
push eax // push pointer to return address as parameter to EnterFunc0
call ExitFunc0
popad // restore general purpose registers
ret // start executing original function
}
}
You already know the address in your _pexit() function, it was handed to you in the _penter() function.您已经知道 _pexit() 函数中的地址,它是在 _penter() 函数中传递给您的。 All you have to do is support nested function calls.您所要做的就是支持嵌套函数调用。 An std::stack<> is good for that. std::stack<> 对此有好处。 Use push() to save the address in _penter, retrieve it with top() in your _pexit function and call pop().使用 push() 将地址保存在 _penter 中,使用 _pexit 函数中的 top() 检索它并调用 pop()。
No need to know the function body size at all anymore.根本不需要知道函数体的大小。
Since the compiler ensures that _penter
and _pexit
are called at the start and end of every function, you can be certain that upon a call to _pexit
, the function pointer on top of the stack created by _penter
always points to the current function.由于编译器确保在每个函数的开始和结束时调用_penter
和_pexit
,您可以确定在调用_pexit
,由_penter
创建的堆栈顶部的函数指针始终指向当前函数。 There is no need to search for it.没有必要搜索它。
(This should be true unless you call one of the functions manually, which you shouldn't do, or have a multi-threaded program. In the latter case you should create a private stack per thread. Of course, you'll also have to add a Stack_Pop
invocation to _pexit
, but I assume that you planned on doing that anyway.) (这应该是正确的,除非您手动调用其中一个函数,您不应该这样做,或者有一个多线程程序。在后一种情况下,您应该为每个线程创建一个私有堆栈。当然,您也将拥有将Stack_Pop
调用添加到_pexit
,但我假设您无论如何都打算这样做。)
It turns out I was looking at the problem the wrong way.事实证明,我以错误的方式看待问题。 I solved the problem by getting symbol information using SymFromAddress method, from dbghelp.lib .我通过使用SymFromAddress方法从dbghelp.lib获取符号信息解决了这个问题。 Once I got the name of the method, I was able to compare it with the information that I stored in _penter.一旦我得到了方法的名称,我就能够将它与我存储在 _penter 中的信息进行比较。
SYMBOL_INFO * mysymbol;
HANDLE process;
char temp[MAX_TEMP_LENGTH] = " ";
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
mysymbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
mysymbol->MaxNameLen = 255;
mysymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
SymFromAddr(process, (DWORD64)((void *)pStack[0]), 0, mysymbol);
OutputDebugString(mysymbol->Name);
OutputDebugString("\n");
Configuration Properties > C/C++ > Command Line
Add compiler option to Additional Options
box将编译器选项添加到Additional Options
框
Add flag /Gh for _penter hook为 _penter 钩子添加标志 /Gh
Add flag /GH for _pexit hook为 _pexit 钩子添加标志 /GH
Code I use for tracing / logging我用于跟踪/记录的代码
#include <intrin.h>
extern "C" void __declspec(naked) __cdecl _penter(void) {
__asm {
push ebp; // standard prolog
mov ebp, esp;
sub esp, __LOCAL_SIZE
pushad; // save registers
}
// _ReturnAddress always returns the address directly after the call, but that is not the start of the function!
PBYTE addr;
addr = (PBYTE)_ReturnAddress() - 5;
SYMBOL_INFO* mysymbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
mysymbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
mysymbol->MaxNameLen = 255;
mysymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
SymFromAddr(process, (DWORD64)((void*)addr), 0, mysymbol);
myprintf("Entered Function: %s [0x%X]\n", mysymbol->Name, addr);
_asm {
popad; // restore regs
mov esp, ebp; // standard epilog
pop ebp;
ret;
}
}
extern "C" void __declspec(naked) __cdecl _pexit(void) {
__asm {
push ebp; // standard prolog
mov ebp, esp;
sub esp, __LOCAL_SIZE
pushad; // save registers
}
// _ReturnAddress always returns the address directly after the call, but that is not the start of the function!
PBYTE addr;
addr = (PBYTE)_ReturnAddress() - 5;
SYMBOL_INFO* mysymbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
mysymbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
mysymbol->MaxNameLen = 255;
mysymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
SymFromAddr(process, (DWORD64)((void*)addr), 0, mysymbol);
myprintf("Exit Function: %s [0x%X]\n", mysymbol->Name, addr);
_asm {
popad; // restore regs
mov esp, ebp; // standard epilog
pop ebp;
ret;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.