Sleepy与DbgHlp库学习

参考:http://msdn.microsoft.com/en-us/library/windows/desktop/ms679291(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/ms680181(v=vs.85).aspx

http://sleepy.sourceforge.net/

http://www.codersnotes.com/sleepy

 

Very Sleepy是一个比较好用的Profiler工具(是对Sleepy的改进版本),开源,代码也很简洁。

那么Sleepy的原理是什么呢?

 

Sleepy程序作为主进程,启动子进程,或者Attach到目标进程上,从而获取到目标进程的第一个线程。

Sleepy每隔很短的一段时间就调用一次sample取样操作

void CALLBACK sprof_callback(UINT wTimerID, UINT msg,
                        DWORD dwUser, DWORD dw1, DWORD dw2)
{
    ProfilerThread* thread = (ProfilerThread*)dwUser;
 
    thread->sample();
 
}

然后将目标线程暂停,并且查看目标线程正在执行的eip地址

void Profiler::sampleTarget()
{
    // An open question is whther or not this routine can be called
    // reentrantly by the multi-media timer support.
 
    HRESULT result = SuspendThread(target_thread);
 
    if(result == 0xffffffff)
        throw ProfilerExcep("SuspendThread failed.");
 
    CONTEXT threadcontext;
    threadcontext.ContextFlags = CONTEXT_i386 | CONTEXT_CONTROL;
    result = GetThreadContext(target_thread, &threadcontext);
    if(!result)
        throw ProfilerExcep("GetThreadContext failed.");
 
    PROFILER_ADDR addr = threadcontext.Eip;
 
    //std::cout << "addr: " << addr << std::endl;
 
    result = ResumeThread(target_thread);
    if(!result)
        throw ProfilerExcep("ResumeThread failed.");
 
    //NOTE: this has to go after ResumeThread.  Otherwise mem allocation needed by std::map
    //may hit a lock held by the suspended thread.
    counts[addr]++;
}

并且将维护一张map,记录各个被取样到的ip地址被调用到的次数。

最后再通过DbgHlp的Sym功能,将ip地址映射成具体的函数名称。

 

Very Sleepy加入了Call Graph的feature,可以统计Include/Exclude方式下的某个函数被调用的计数。

估计是使用了DbgHelp的StackWalk64函数。

 

基于对pin的学习,这个功能很容易地用pintool重新改写。

但是,pintool的好处在哪呢?

posted @ 2014-04-11 16:08  Daniel King  阅读(439)  评论(0编辑  收藏  举报