Я использую / Gh и / GH опцию компилятора Visual Studio для профилирования группы кода. Используются два метода: _penter и _pexit, которые вызываются при входе или выходе функции в профилируемом коде. Поскольку мне нужно профилировать / отлаживать определенные функции, я использую уже определенный массив FuncTable который содержит адреса функций, которые мне нужны для инструмента с их именами в виде строки. Поэтому, когда функция введена, pStack [0], который в основном содержит содержимое регистра, содержит адрес текущей строки исполняемого кода. Точно так же, когда выход из функции, pStack [0] содержит адрес последней строки кода.
ПРОБЛЕМА: Когда функция введена (вызывается _penter), я получаю адрес первой строки функции в pStack [0], и, следовательно, я могу получить адрес функции, вычитая константу (-5), и сохранить ее в своем списке, чтобы быть найденным позже в функции _pexit. Но поскольку в _pexit я получаю адрес до последней строки функции, мне нужно найти размер функции, чтобы вычесть этот размер из адреса в pStack [0], чтобы получить начальный адрес функции, а затем сравнить этот адрес для тех, которые сохранены в моем списке. Ниже приведен код.
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
}
}
Вы уже знаете адрес в своей функции _pexit (), он был передан вам в функции _penter (). Все, что вам нужно сделать, это поддерживать вызовы вложенных функций. Std :: stack<> Это хорошо для этого. Используйте push (), чтобы сохранить адрес в _penter, получить его с помощью top () в функции _pexit и вызвать pop ().
Больше не нужно знать размер тела функции.
Поскольку компилятор гарантирует, что _penter
а также _pexit
вызываются в начале и в конце каждой функции, вы можете быть уверены, что при вызове _pexit
указатель на вершину стека, созданный _penter
всегда указывает на текущую функцию. Там нет необходимости искать его.
(Это должно быть верно, если вы не вызываете одну из функций вручную, чего не следует делать, или не имеете многопоточной программы. В последнем случае вам следует создать частный стек для каждого потока. Конечно, у вас также будет добавить Stack_Pop
обращение к _pexit
, но я предполагаю, что вы все равно планировали это сделать.)
Оказывается, я смотрел на проблему неправильно. Я решил проблему, получив информацию о символах с помощью SymFromAddress метод, из dbghelp.lib. Получив название метода, я смог сравнить его с информацией, хранящейся в _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");