原理不多说了,我们知道,GetThreadContext只能取得被挂起线程的上下文,所以我这里使用内嵌汇编得到当前地址eip和当前函数栈指针ebp

由于没有使用Debug Help API,当然也不想自己分析pdb文件,打印信息可以和map文件和cond文件对照使用,还是比较方便的

其实可以从teb中得到堆栈位置信息来确定最外层调用栈,这里偷懒了,但是不影响这段代码的实用性,呵呵。

使用这段代码跟踪的程序,最好将编译选项中的优化去掉,原因大家都知道的

void PrintStackTrace()
{

  DWORD dwAddr   = 0;
  DWORD dwChildEbp = 0;

  _asm call $+5;
  _asm pop eax;
  _asm mov dwAddr,eax;
  _asm mov dwChildEbp,ebp;

  DWORD dwRetAddr = *(DWORD*)(dwChildEbp+4);

  CString strMsg =  "Addr\t\tChildEbp\t\tRetAddr\r\n"
            "===============================\r\n";
  try
  {
    while (TRUE)//dwRetAddr != 0)
    {
      dwAddr = dwRetAddr;
      dwChildEbp = *(DWORD*)dwChildEbp;
      dwRetAddr = *(DWORD*)(dwChildEbp+4);

      CString strTemp;
      strTemp.Format("0x%08X\t0x%08X\t0x%08X\r\n",dwAddr,dwChildEbp,dwRetAddr);
      strMsg += strTemp;
    }
  }
  catch (...)
  {
    
    printf("%s",(LPCTSTR)strMsg);
  }
}