给函数增加Debug头 - windows平台的普通打印调试处理

本系列文章由 @lonelyrains 出品,转载请注明出处。 
文章链接: http://blog.csdn.net/lonelyrains/article/details/9428395


     笔者在VS2008和VC6.0两种常用平台应用此工具,发现VC6.0版本不支持__FUNCTION__宏,有高手自定义的__FUNCTION__实现在此

     有几个问题需要注意:

1、在MFC环境下报错的问题:

①#error WINDOWS.H already included.  MFC apps must not #include <windows.h>。无奈的解决方法是把自动添加上的调试头文件#include语句添加到afx相关的头文件之后。

②unexpected endif:需要添加stafx.h的预编译头文件,然后把xtrace.cpp里的#if defined(_DEBUG) && defined(WIN32)和对应的#endif去掉

2、在Unicode环境下报错的问题:

添加强制转换


最终的xtrace.cpp文件代码如下:

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * xtrace.cpp by Hector J. Rivas, torjo2k@hotmail.com from "ExtendedTrace"
 * by Zoltan Csizmadia, zoltan_csizmadia@yahoo.com
 * 
 * A Win32 VC++ 6.0 implementation of the __FUNCTION__ macro that works for me.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "StdAfx.h"

#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <ImageHlp.h>
#include "xtrace.h"

// Unicode safe char* -> TCHAR* conversion
void PCSTR2LPTSTR(PCSTR lpszIn, LPTSTR lpszOut)
{
#if defined(UNICODE) || defined(_UNICODE)
	
	ULONG index = 0; 
	PCSTR lpAct = lpszIn;
	
	for(;; lpAct++)
	{
		lpszOut[index++] = (TCHAR)(*lpAct);
		
		if (*lpAct == 0) break;
	} 
#else
	strcpy(lpszOut, lpszIn);
#endif
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * InitSymPath(): figure  out  the  path for the symbol files; the search path is:
 *
 * 		. +
 *		__FILE__ (path) + Debug +
 * 		%_NT_SYMBOL_PATH% +
 * 		%_NT_ALTERNATE_SYMBOL_PATH% +
 * 		%SYSTEMROOT% +
 * 		%SYSTEMROOT%\System32 +
 * 		lpszIniPath
 *
 * NOTES: There is no size check for lpszSymbolPath. If you want to limit the macro to
 * symbols in your debug executable, you can omit the environment variables (default).
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void InitSymPath(PSTR lpszSymbolPath, PCSTR lpszIniPath, BOOL bSysPath)
{
	CHAR lpszPath[BUFFERSIZE] = "";
	CHAR lpszTemp[BUFFERSIZE] = "";
	
	// create the default path
	strcpy(lpszSymbolPath, ".;");

	// get the current path
	sprintf(lpszTemp, __FILE__);

	strcpy(lpszPath, strrev(strchr(strrev(lpszTemp), '\\')));

	strcat(lpszPath, "Debug");

	strcat(lpszSymbolPath, lpszPath);

	if (bSysPath)
	{
		// environment variable _NT_SYMBOL_PATH
		if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE))
		{
			strcat(lpszSymbolPath, ";");
			strcat(lpszSymbolPath, lpszPath);
		}
		
		// environment variable _NT_ALTERNATE_SYMBOL_PATH
		if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE))
		{
			strcat(lpszSymbolPath, ";");
			strcat(lpszSymbolPath, lpszPath);
		}
		
		// environment variable SYSTEMROOT
		if (GetEnvironmentVariableA("SYSTEMROOT", lpszPath, BUFFERSIZE))
		{
			strcat(lpszSymbolPath, ";");
			strcat(lpszSymbolPath, lpszPath);
			
			// SYSTEMROOT\System32
			strcat(lpszSymbolPath, ";");
			strcat(lpszSymbolPath, lpszPath);
			strcat(lpszSymbolPath, "\\System32");
		}
	}
	
	// Add any user defined path
	if (lpszIniPath != NULL)
	{
		if (lpszIniPath[0] != '\0')
		{
			strcat(lpszSymbolPath, ";");
			strcat(lpszSymbolPath, lpszIniPath);
		}
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * InitSymInfo(): initializes the symbol files
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

BOOL InitSymInfo(PCSTR lpszInitialSymbolPath, BOOL bSysPath)
{
	CHAR	lpszSymbolPath[BUFFERSIZE];
	
	DWORD	symOptions = SymGetOptions();
	
	// set current image help API options; according to the SDK docs, with
	// SYMOPT_DEFERRED_LOADS: "Symbols are not loaded until a reference is made
	// requiring the symbols be loaded. This is the fastest, most efficient way to use
	// the symbol handler.". SYMOPT_UNDNAME is excluded to do the undecoration
	// ourselves.
	symOptions |= SYMOPT_DEFERRED_LOADS; 
	symOptions &= ~SYMOPT_UNDNAME;
	
	SymSetOptions(symOptions);
	
	// get the search path for the symbol files
	InitSymPath(lpszSymbolPath, lpszInitialSymbolPath, bSysPath);
	
	return SymInitialize(GetCurrentProcess(), lpszSymbolPath, TRUE);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * GetFuncInfo(): Get function prototype from address and stack address
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

BOOL GetFuncInfo(ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol)
{
	BOOL ret = FALSE;
	
	DWORD dwDisp = 0, dwSymSize = 10000;
	
	TCHAR lpszUDSymbol[BUFFERSIZE] = _T("?");
	
	CHAR lpszANSIUDSymbol[BUFFERSIZE] = "?";
		
	PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc(GMEM_FIXED, dwSymSize);

	ZeroMemory(pSym, dwSymSize);
	
	pSym->SizeOfStruct  = dwSymSize;
	pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);

	// Set the default to unknown
	_tcscpy(lpszSymbol, _T("?"));

	// Get symbol info
	if (SymGetSymFromAddr(GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym))
	{
		// Make the symbol readable for humans
		UnDecorateSymbolName(pSym->Name,
							 lpszANSIUDSymbol,
							 BUFFERSIZE,
							 UNDNAME_COMPLETE			  |
							 UNDNAME_NO_THISTYPE		  |
							 UNDNAME_NO_SPECIAL_SYMS	  |
							 UNDNAME_NO_MEMBER_TYPE		  |
							 UNDNAME_NO_MS_KEYWORDS		  |
							 UNDNAME_NO_ACCESS_SPECIFIERS |
							 UNDNAME_NO_ARGUMENTS);

		// Symbol information is ANSI string
		PCSTR2LPTSTR(lpszANSIUDSymbol, lpszUDSymbol);

		lpszSymbol[0] = _T('\0');

		_tcscat(lpszSymbol, lpszUDSymbol);
   
		ret = TRUE;
	}

	GlobalFree(pSym);

	return ret;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * GetFuncName(): return the undecorated function name
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

LPCTSTR GetFuncName()
{
	BOOL           bResult = FALSE;

	STACKFRAME     callStack;
	CONTEXT        context;
	
	TCHAR          lpszFnInfo[BUFFERSIZE];
	
	HANDLE         hProcess = GetCurrentProcess();
	HANDLE         hThread  = GetCurrentThread();

	// initialize a context struct to retrieve processor-specific register data
	ZeroMemory(&context, sizeof(context));
	
	context.ContextFlags = CONTEXT_FULL;

	if (!GetThreadContext(hThread, &context))
		return L"";
	
	// initialize a stack frame struct in preparation to walk the stack
	ZeroMemory(&callStack, sizeof(callStack));
	
	callStack.AddrPC.Offset    = context.Eip;
	callStack.AddrStack.Offset = context.Esp;
	callStack.AddrFrame.Offset = context.Ebp;
	
	callStack.AddrPC.Mode      = AddrModeFlat;
	callStack.AddrStack.Mode   = AddrModeFlat;
	callStack.AddrFrame.Mode   = AddrModeFlat;

	// obtain a stack trace of the calling function (i.e., omit this one)
	for (ULONG n = 0; n < 2; n++) 
	{
		bResult = StackWalk(IMAGE_FILE_MACHINE_I386,
							hProcess,
							hThread,
							&callStack,
							NULL,
							NULL,
							SymFunctionTableAccess,
							SymGetModuleBase,
							NULL);
	}

	if (bResult && callStack.AddrFrame.Offset != 0) 
	{
		GetFuncInfo(callStack.AddrPC.Offset, callStack.AddrFrame.Offset, lpszFnInfo);

		// from now on its all personal display preferences with string manipulation

		// tokenize the undecorated returned symbol to omit the class name
		CHAR* lpszToken = strtok((char *)lpszFnInfo, "::");
		CHAR  lpszLast[BUFFERSIZE] = "";

		while (lpszToken != NULL)
		{
			strcpy(lpszLast, lpszToken);
			lpszToken = strtok(NULL, "::");
		}

		// append a delimiter, so that our display in printf instructions is 
		// 'functionname: message' for debug builds and 'message' for release builds,
		// using the format string "%smessage" and __FUNCTION__ as an argument
		strcat(lpszLast, ": ");

		return (const unsigned short *)lpszLast;
	}

	return L"";
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * KillSymInfo(): uninitialize the loaded symbol files
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL KillSymInfo() { return SymCleanup(GetCurrentProcess()); }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值