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

来源:互联网 发布:proc sql定义变量长度 编辑:程序博客网 时间:2024/06/10 02:36

本系列文章由 @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* conversionvoid 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;} #elsestrcpy(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 pathstrcpy(lpszSymbolPath, ".;");// get the current pathsprintf(lpszTemp, __FILE__);strcpy(lpszPath, strrev(strchr(strrev(lpszTemp), '\\')));strcat(lpszPath, "Debug");strcat(lpszSymbolPath, lpszPath);if (bSysPath){// environment variable _NT_SYMBOL_PATHif (GetEnvironmentVariableA("_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE)){strcat(lpszSymbolPath, ";");strcat(lpszSymbolPath, lpszPath);}// environment variable _NT_ALTERNATE_SYMBOL_PATHif (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE)){strcat(lpszSymbolPath, ";");strcat(lpszSymbolPath, lpszPath);}// environment variable SYSTEMROOTif (GetEnvironmentVariableA("SYSTEMROOT", lpszPath, BUFFERSIZE)){strcat(lpszSymbolPath, ";");strcat(lpszSymbolPath, lpszPath);// SYSTEMROOT\System32strcat(lpszSymbolPath, ";");strcat(lpszSymbolPath, lpszPath);strcat(lpszSymbolPath, "\\System32");}}// Add any user defined pathif (lpszIniPath != NULL){if (lpszIniPath[0] != '\0'){strcat(lpszSymbolPath, ";");strcat(lpszSymbolPath, lpszIniPath);}}}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * InitSymInfo(): initializes the symbol files * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */BOOL InitSymInfo(PCSTR lpszInitialSymbolPath, BOOL bSysPath){CHARlpszSymbolPath[BUFFERSIZE];DWORDsymOptions = 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 filesInitSymPath(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 infoif (SymGetSymFromAddr(GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym)){// Make the symbol readable for humansUnDecorateSymbolName(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 stringPCSTR2LPTSTR(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 dataZeroMemory(&context, sizeof(context));context.ContextFlags = CONTEXT_FULL;if (!GetThreadContext(hThread, &context))return L"";// initialize a stack frame struct in preparation to walk the stackZeroMemory(&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 nameCHAR* 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 argumentstrcat(lpszLast, ": ");return (const unsigned short *)lpszLast;}return L"";}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * KillSymInfo(): uninitialize the loaded symbol files * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */BOOL KillSymInfo() { return SymCleanup(GetCurrentProcess()); }


原创粉丝点击