哎,郁闷,不知道是优快云的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
有篇文章特好,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;
}
本文介绍了一个能在VC++6.0中实现类似callstack功能的程序,可以输出调用栈上的函数名称、实参个数及值,还有函数调用处的偏移量。通过具体的源代码示例展示了如何获取这些信息。
6424

被折叠的 条评论
为什么被折叠?



