C ++ - 从结束地址获取函数的起始地址/获取函数的大小

时间:2016-07-07 17:58:52

标签: c++ visual-studio profiling compiler-options

我正在使用Visual Studio的/ Gh和/ GH编译器选项来分析一堆代码。使用的两种方法是_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
    }
}

3 个答案:

答案 0 :(得分:2)

您已经知道_pexit()函数中的地址,它已在_penter()函数中传递给您。您所要做的就是支持嵌套函数调用。 std :: stack<>对此有好处。使用push()在_penter中保存地址,在_pexit函数中使用top()检索它并调用pop()。

根本不需要知道功能体尺寸。

答案 1 :(得分:0)

由于编译器确保在每个函数的开头和结尾调用_penter_pexit,因此可以确定在调用_pexit时,函数指针位于顶部由_penter创建的堆栈始终指向当前函数。没有必要搜索它。

(这应该是真的,除非你手动调用其中一个函数,你不应该这样做,或者有一个多线程程序。在后一种情况下你应该为每个线程创建一个私有堆栈。当然,你' ll还必须向Stack_Pop添加_pexit次调用,但我认为无论如何你都计划这样做。)

答案 2 :(得分:0)

事实证明我是以错误的方式看待问题。我通过使用 dbmhelp.lib 中的 SymFromAddress 方法获取符号信息来解决问题。一旦我得到了方法的名称,我就可以将它与我在_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");