哎,郁闷,不知道是CSDN的bug还是有人故意捣乱,辛辛苦苦写的文章被替换成“自由的思维”一文,真是百思不解呀,至此也没有什么再写的激情了!(该程序能输出调用栈上的函数名称,实参个数及其值,以及函数调用处的偏移量。像VC++ 6.0中的call stack)
控制台输出如下:
StackTrace dump begin...
StackTrace( )
Call_C( 0x0000000A , 0x00000014 ) line 448 + 0 bytes
Call_B( 0x0000000A , 0x00000014 ) line 453 + 13 bytes
Call_A( 0x0000000A , 0x00000014 ) line 458 + 13 bytes
main( 0x00000001 , 0x00391380 , 0x003913D8 ) line 463 + 9 bytes
StackTrace dump end !
Press any key to continue
StackTrace( )
Call_C( 0x0000000A , 0x00000014 ) line 448 + 0 bytes
Call_B( 0x0000000A , 0x00000014 ) line 453 + 13 bytes
Call_A( 0x0000000A , 0x00000014 ) line 458 + 13 bytes
main( 0x00000001 , 0x00391380 , 0x003913D8 ) line 463 + 9 bytes
StackTrace dump end !
Press any key to continue
有篇文章特好,Playing with the stack : http://www.codeguru.com/cpp/misc/misc/stack/article.php/c3875/
下面贴个源码。
#include
<
stdio.h
>
#include < windows.h >
#include < Dbghelp.h >
#define JMP_INSTR 0xE9
#define SYM_BUFF_SIZE 512
static BYTE g_stSymbol [ SYM_BUFF_SIZE ] ;
int GetFuncArgsNum( int retAddrs)
... {
if(0xC483 == *(WORD *)retAddrs) // 0xC483 'Add esp, xxx'
return *(BYTE*)(retAddrs + 2) >> 2;
else
return 0;
}
int GetFuncArgVal( int ebp, int index)
... {
return *(int *)(ebp + ((index + 2) << 2));
}
int GetCallFuncAddrs( int retAddrs)
... {
int callFuncAddrs = *(int *)(retAddrs - 4) + retAddrs;
//callFuncAddrs > 0x80000000 can cause the 'can not read the memory' error!
if((DWORD)callFuncAddrs > 0x80000000)
...{
return 0;
}
//Jump over the JMP instruction to the real address of function
while(JMP_INSTR == *(BYTE *)callFuncAddrs)
...{
int offset = callFuncAddrs + 1;
callFuncAddrs = *(int *)(offset) + (callFuncAddrs + 5);
}
return callFuncAddrs;
}
void PrintCallFuncOffset( int retAddrs)
... {
HANDLE hCurProcess = (HANDLE) ::GetCurrentProcessId();
static saved_retAddrs = 0;
if(0 == saved_retAddrs)
...{
saved_retAddrs = retAddrs;
printf("%s", " ");
return;
}
DWORD dwDisp;
IMAGEHLP_LINE stLine;
FillMemory(&stLine, NULL, sizeof(IMAGEHLP_LINE));
stLine.SizeOfStruct = sizeof(stLine);
if(!::SymGetLineFromAddr(hCurProcess, (DWORD)saved_retAddrs, &dwDisp, &stLine))
...{
printf("%s", " ");
return;
}
printf("line %d + %d bytes ", stLine.LineNumber, dwDisp);
saved_retAddrs = retAddrs;
}
void PrintCallFunc( int ebp)
... {
int callFuncAddrs;
DWORD dwDisp = 0;
int retAddrs = *(int *)(ebp + 4);
HANDLE hCurProcess = (HANDLE) ::GetCurrentProcessId();
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol ;
int argsNum = ::GetFuncArgsNum(retAddrs);
callFuncAddrs = GetCallFuncAddrs(retAddrs);
if(!::SymGetSymFromAddr(hCurProcess, (DWORD)callFuncAddrs, &dwDisp, pSym))
...{
return;
}
//Print the name of call function
printf("%s( ", pSym->Name);
//Print the args
if(argsNum > 0)
...{
argsNum--;
for(int i = 0; i < argsNum; i++)
...{
printf("0x%08X, ", GetFuncArgVal(ebp, i));
}
//print the last arg.
printf("0x%08X ) ", GetFuncArgVal(ebp, i));
}
else
...{
printf("%s", " ) ");
}
//Print the line number
PrintCallFuncOffset(retAddrs);
}
void StackTrace( void )
... {
int saved_ebp;
int cur_ebp;
HANDLE hCurProcess;
//Fill the IMAGEHLP_SYMBOL struct
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol ;
FillMemory ( pSym , NULL , SYM_BUFF_SIZE ) ;
pSym->SizeOfStruct = sizeof ( IMAGEHLP_SYMBOL ) ;
pSym->MaxNameLength = SYM_BUFF_SIZE - sizeof ( IMAGEHLP_SYMBOL );
//Initialize & load the symbol table
hCurProcess = (HANDLE)::GetCurrentProcessId();
::SymSetOptions ( SYMOPT_UNDNAME | SYMOPT_LOAD_LINES ) ;
if(!::SymInitialize(hCurProcess, NULL, TRUE))// Load the module automatically
...{
return;
}
__asm
...{
//Get the current ebp
mov cur_ebp, ebp
}
//Get the saved ebp
saved_ebp = *(int *)cur_ebp;
//Print the call stack
printf("StackTrace dump begin... ");
while(saved_ebp != 0)
...{
PrintCallFunc(cur_ebp);
//Move to the next caller's stack frame
cur_ebp = saved_ebp;
saved_ebp = *(int *)saved_ebp;
}
printf(" StackTrace dump end! ");
::SymCleanup(hCurProcess);
}
class CTest
... {
public:
void Hello()
...{
StackTrace();
};
} ;
int Call_C( int a, int b)
... {
StackTrace();
return (a + b);
}
int Call_B( int a, int b)
... {
return Call_C(a, b);
}
int Call_A( int a, int b)
... {
return Call_B(a, b);
}
main()
... {
Call_A(10, 20);
// CTest test;
// test.Hello();
return 0;
}
#include < windows.h >
#include < Dbghelp.h >
#define JMP_INSTR 0xE9
#define SYM_BUFF_SIZE 512
static BYTE g_stSymbol [ SYM_BUFF_SIZE ] ;
int GetFuncArgsNum( int retAddrs)
... {
if(0xC483 == *(WORD *)retAddrs) // 0xC483 'Add esp, xxx'
return *(BYTE*)(retAddrs + 2) >> 2;
else
return 0;
}
int GetFuncArgVal( int ebp, int index)
... {
return *(int *)(ebp + ((index + 2) << 2));
}
int GetCallFuncAddrs( int retAddrs)
... {
int callFuncAddrs = *(int *)(retAddrs - 4) + retAddrs;
//callFuncAddrs > 0x80000000 can cause the 'can not read the memory' error!
if((DWORD)callFuncAddrs > 0x80000000)
...{
return 0;
}
//Jump over the JMP instruction to the real address of function
while(JMP_INSTR == *(BYTE *)callFuncAddrs)
...{
int offset = callFuncAddrs + 1;
callFuncAddrs = *(int *)(offset) + (callFuncAddrs + 5);
}
return callFuncAddrs;
}
void PrintCallFuncOffset( int retAddrs)
... {
HANDLE hCurProcess = (HANDLE) ::GetCurrentProcessId();
static saved_retAddrs = 0;
if(0 == saved_retAddrs)
...{
saved_retAddrs = retAddrs;
printf("%s", " ");
return;
}
DWORD dwDisp;
IMAGEHLP_LINE stLine;
FillMemory(&stLine, NULL, sizeof(IMAGEHLP_LINE));
stLine.SizeOfStruct = sizeof(stLine);
if(!::SymGetLineFromAddr(hCurProcess, (DWORD)saved_retAddrs, &dwDisp, &stLine))
...{
printf("%s", " ");
return;
}
printf("line %d + %d bytes ", stLine.LineNumber, dwDisp);
saved_retAddrs = retAddrs;
}
void PrintCallFunc( int ebp)
... {
int callFuncAddrs;
DWORD dwDisp = 0;
int retAddrs = *(int *)(ebp + 4);
HANDLE hCurProcess = (HANDLE) ::GetCurrentProcessId();
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol ;
int argsNum = ::GetFuncArgsNum(retAddrs);
callFuncAddrs = GetCallFuncAddrs(retAddrs);
if(!::SymGetSymFromAddr(hCurProcess, (DWORD)callFuncAddrs, &dwDisp, pSym))
...{
return;
}
//Print the name of call function
printf("%s( ", pSym->Name);
//Print the args
if(argsNum > 0)
...{
argsNum--;
for(int i = 0; i < argsNum; i++)
...{
printf("0x%08X, ", GetFuncArgVal(ebp, i));
}
//print the last arg.
printf("0x%08X ) ", GetFuncArgVal(ebp, i));
}
else
...{
printf("%s", " ) ");
}
//Print the line number
PrintCallFuncOffset(retAddrs);
}
void StackTrace( void )
... {
int saved_ebp;
int cur_ebp;
HANDLE hCurProcess;
//Fill the IMAGEHLP_SYMBOL struct
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)&g_stSymbol ;
FillMemory ( pSym , NULL , SYM_BUFF_SIZE ) ;
pSym->SizeOfStruct = sizeof ( IMAGEHLP_SYMBOL ) ;
pSym->MaxNameLength = SYM_BUFF_SIZE - sizeof ( IMAGEHLP_SYMBOL );
//Initialize & load the symbol table
hCurProcess = (HANDLE)::GetCurrentProcessId();
::SymSetOptions ( SYMOPT_UNDNAME | SYMOPT_LOAD_LINES ) ;
if(!::SymInitialize(hCurProcess, NULL, TRUE))// Load the module automatically
...{
return;
}
__asm
...{
//Get the current ebp
mov cur_ebp, ebp
}
//Get the saved ebp
saved_ebp = *(int *)cur_ebp;
//Print the call stack
printf("StackTrace dump begin... ");
while(saved_ebp != 0)
...{
PrintCallFunc(cur_ebp);
//Move to the next caller's stack frame
cur_ebp = saved_ebp;
saved_ebp = *(int *)saved_ebp;
}
printf(" StackTrace dump end! ");
::SymCleanup(hCurProcess);
}
class CTest
... {
public:
void Hello()
...{
StackTrace();
};
} ;
int Call_C( int a, int b)
... {
StackTrace();
return (a + b);
}
int Call_B( int a, int b)
... {
return Call_C(a, b);
}
int Call_A( int a, int b)
... {
return Call_B(a, b);
}
main()
... {
Call_A(10, 20);
// CTest test;
// test.Hello();
return 0;
}