上次写了列出EXE,DLL或PDB文件中的符号信息,这次再贴一段代码。举例说明如何列举一指定函数的局部信息,即函数的参数和局部变量信息。呵呵,本人即不爱说废话,又怕打字太累。^_^,开门见山,来看下面代码吧。Enjoy!
//============================================================================
// LFVars : A small tool used to display function symbol informaton from EXE, DLL or PDB files
// L(ist)F(untion)Vars: list function parameters and local variabls.
// Author : zyq654321 --- Oct, 2004
// Comment: This is only a sample code to show you how to dump symbol information,
// you can improve it and your advise is appreciated.
#include <windows.h>
#include <TCHAR.h>
#define _NO_CVCONST_H // We should define the constant in order to ...
#include <dbghelp.h>
#include <stdio.h>
#pragma comment( lib, "dbghelp.lib" )
BOOL CALLBACK LFVarsCallback( SYMBOL_INFO* pSymInfo, ULONG SymbolSize, PVOID UserContext )
{
if( pSymInfo != 0 )
{
// Increase the counter of found local variables and parameters
if( UserContext != 0 )
*(int*)UserContext += 1;
// list parameters or variables
_tprintf(_T("Name: %s /n"),pSymInfo->Name);
_tprintf(_T(" Type: %s "),
(pSymInfo->Flags & SYMFLAG_PARAMETER) ? "Function Parameter" :
( (pSymInfo->Flags & SYMFLAG_LOCAL)? "Local Variable": "Unknown"));
TCHAR tcsReg[10];
switch(pSymInfo->Register)
{
case 17:
_tcscpy(tcsReg,_T("[EAX]"));
break;
case 18:
_tcscpy(tcsReg,_T("[ECX]"));
break;
case 19:
_tcscpy(tcsReg,_T("[EDX]"));
break;
case 20:
_tcscpy(tcsReg,_T("[EBX]"));
break;
case 21:
_tcscpy(tcsReg,_T("[ESP]"));
break;
case 22:
_tcscpy(tcsReg,_T("[EBP]"));
break;
case 23:
_tcscpy(tcsReg,_T("[ESI]"));
break;
case 24:
_tcscpy(tcsReg,_T("[EDI]"));
break;
default:
_tcscpy(tcsReg,_T("Unknown"));
break;
}
_tprintf( _T("Register: %s "), tcsReg );
UINT uMax = 0xFFFFFFFF;
_tprintf( _T("Address(Offset): %c0x%X "),
(LONG)pSymInfo->Address >= 0? ' ' : '-',
(LONG)pSymInfo->Address >= 0? pSymInfo->Address : (uMax - pSymInfo->Address + 1));
_tprintf( _T("Size: %d /n"), pSymInfo->Size);
//ShowSymbolDetails( *pSymInfo );
}
return TRUE; // Continue enumeration
}
int main( int argc, const TCHAR* argv[] )
{
if(argc < 3)
{
goto FAILED_PARAM;
}
// Set debug options
DWORD dwOpn = SymGetOptions();
dwOpn |= SYMOPT_DEBUG;
SymSetOptions(dwOpn);
// Initilaize the symbol handle for the current process
if(!SymInitialize( GetCurrentProcess(),
NULL,
FALSE ))
{
_tprintf(_T("Failed when SymInitialize():%d/n"), GetLastError());
return 0;
}
if( argv[1] == NULL || argv[2] == NULL)
{
goto FAILED_PARAM;
}
//------------------------------------------------------------------------
// Set initial parameters
TCHAR pszExt[MAX_PATH];
_tsplitpath( argv[1], NULL, NULL, NULL, pszExt );
DWORD64 dw64Base = 0; // if the image is a .pdb file, dw64Base cannot be zero.
// if the value is zero, the library obtains the load address
// from the symbol file.
DWORD dwFileSize = 0; // if the image is a .pdb file, dwFileSize cannot be zero.
// if the value is zero, the library obtains the size
// from the symbol file.
_tcslwr(pszExt);
if(_tcsicmp(pszExt, _T(".pdb")) == 0)
{
// this is a .pdb file, and so we should set the load address and file size;
dw64Base = 0x10000000;
// get the file size
HANDLE hFile = CreateFile( argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if( INVALID_HANDLE_VALUE == hFile )
{
_tprintf(_T("Failed when open %s: %d"), argv[1], GetLastError());
goto FAILED_PARAM;
}
if( INVALID_FILE_SIZE == ( dwFileSize = GetFileSize(hFile, NULL) ))
{
_tprintf(_T("Failed when read the size of %s: %d"), argv[1], GetLastError());
goto FAILED_PARAM;
}
CloseHandle(hFile);
}
//------------------------------------------------------------------------
// Load symbol table
_tprintf(_T("Load %s...../n"), argv[1]);
DWORD64 dw64ModAddress = SymLoadModule64( GetCurrentProcess(),
NULL,
argv[1],
NULL,
dw64Base,
dwFileSize);
if( dw64ModAddress == 0 )
{
_tprintf(_T("Failed when SymLoadModule64(): %d /n"), GetLastError());
return 0;
}
_tprintf(_T("Load Address: %I64x /n"), dw64ModAddress);
//------------------------------------------------------------------------
// Display the function parameters and local variables according to the
// specified function name.
SYMBOL_INFO symInfo;
symInfo.SizeOfStruct = sizeof(SYMBOL_INFO);
if(! SymFromName( GetCurrentProcess(),
argv[2],
&symInfo) )
{
_tprintf( _T("Failed When SymFromName(): %d /n"), GetLastError() );
goto FAILED_AFTER_LOAD;
}
// We only need functon symbol
if( symInfo.Tag != SymTagFunction )
{
_tprintf( _T("Invalid Function Name or Not Found./n") );
goto FAILED_AFTER_LOAD;
}
// List funtion's parameters and its local variables
IMAGEHLP_STACK_FRAME stackFrm;
stackFrm.InstructionOffset = symInfo.Address;
if(!SymSetContext( GetCurrentProcess(),
&stackFrm,
0 ))
{
_tprintf( _T("Failed when SymSetContext: %d /n"), GetLastError() );
goto FAILED_AFTER_LOAD;
}
int nVarsCnt = 0;
if(!SymEnumSymbols( GetCurrentProcess(),
0,
0,
LFVarsCallback,
&nVarsCnt ) )
{
_tprintf( _T("Failed when SymEnumSymbols(): %d /n"), GetLastError() );
goto FAILED_AFTER_LOAD;
}
_tprintf( _T("%d function parmeters and local variables had been listed./n"), nVarsCnt );
FAILED_AFTER_LOAD:
//------------------------------------------------------------------------
// Unload symbols table
if(!SymUnloadModule64( GetCurrentProcess(), dw64ModAddress ))
{
_tprintf( _T("Failed when SymUnloadModule64() : %d /n"), GetLastError() );
}
if(!SymCleanup(GetCurrentProcess()))
{
_tprintf(_T("Failed when SymCleanup(): %d /n"), GetLastError());
return 0;
}
return 0;
FAILED_PARAM:
_tprintf(_T("Failed Parameter!/n"));
_tprintf(_T("Usage: LFVars -filename -function_name/n"));
_tprintf(_T("filename: a EXE, DLL or PDB file/n"));
return 0;
}
呵呵,举了两个例子代码后。真正的有用的应该是如何建立自己的dubegging过程。空了,偶会整理一下,贴点更爽的例子。