#include "SymHandler.h" //----< outputs string in Heading format >---- void Title ( const std::string & str, char ch ) { for ( int i = 0 ; i < ( int ) str.length() ; i ++ ) std::cout << ch ; std::cout << "\n" << str << "\n" ; for ( int i = 0 ; i < ( int ) str.length() ; i ++ ) std::cout << ch ; std::cout << "\n\n" ; } char * GetBasicTypeString ( const DWORD & BasTyp ) { switch ( BasTyp ) { case btNoType : return "basic type not specified" ; case btVoid : return "void" ; case btChar : return "char (C/C++ type)" ; case btWChar : return "WCHAR (wide/Unicode character)" ; case btInt : return "signed char (C/C++ type)" ; case btUInt : return "unsigned char (C/C++ type)" ; case btFloat : return "FLOAT (floating-point number)" ; case btBCD : return "BCD (binary-coded decimal)" ; case btBool : return "BOOL (Boolean)" ; case btLong : return "long int (C/C++ type)" ; case btULong : return "unsigned long int (C/C++ type)" ; case btCurrency : return "currency" ; case btDate : return "DATE (date/time)" ; case btVariant : return "VARIANT (variable type structure)" ; case btComplex : return "complex number" ; case btBit : return "bit" ; case btBSTR : return "BSTR (binary string)" ; case btHresult : return "HRESULT" ; default : return "Basic Type Info could not be detected !" ; } } char * GetIM64SymTypeString ( const SYM_TYPE & stSymTyp ) { switch ( stSymTyp ) { case SymCoff : return "COFF symbols" ; case SymCv : return "codeview (CV) symbols" ; case SymDeferred : return "symbol loading deferred" ; case SymDia : return "DIA symbols" ; case SymExport : return "symbols generated from a DLL export table" ; case SymNone : return "no symbols are loaded" ; case SymPdb : return "PDB symbols" ; case SymSym : return ".sym file" ; case SymVirtual : return "virtual module" ; default : return "symbol type could not be detected !" ; } } char * GetSymInfoTagString ( const DWORD & dwTag ) { switch ( dwTag ) { case SymTagNull : return "symbol has no type" ; case SymTagExe : return "symbol is an .exe file" ; case SymTagCompiland : return "" ; // ???? case SymTagCompilandDetails : return "" ; // ???? case SymTagCompilandEnv : return "" ; // ????? case SymTagFunction : return "symbol is a function" ; case SymTagBlock : return "symbol is a nested block" ; case SymTagData : return "symbol is data" ; case SymTagAnnotation : return "symbol is for a code annotation" ; case SymTagLabel : return "symbol is a label" ; case SymTagPublicSymbol : return "symbol is a public symbol" ; case SymTagUDT : return "symbol is a user-defined type" ; case SymTagEnum : return "symbol is an enumeration" ; case SymTagFunctionType : return "symbol is a function signature type" ; case SymTagPointerType : return "symbol is a pointer type" ; case SymTagArrayType : return "symbol is an array type" ; case SymTagBaseType : return "symbol is a base type" ; case SymTagTypedef : return "symbol is a typedef" ; case SymTagBaseClass : return "symbol is a base class of a user-defined type" ; case SymTagFriend : return "symbol is a friend of a user-defined type" ; case SymTagFunctionArgType : return "symbol is a function argument" ; case SymTagFuncDebugStart : return "symbol is the end location of the function's prologue code" ; case SymTagFuncDebugEnd : return "symbol is the beginning location of the function's epilogue code" ; case SymTagUsingNamespace : return "symbol is a namespace name active in the current scope" ; case SymTagVTableShape : return "symbol is a virtual table description" ; case SymTagVTable : return "symbol is a virtual table pointer" ; case SymTagCustom : return "symbol is a custom symbol uninterrupted by DIA" ; case SymTagThunk : return "symbol is a thunk" ; case SymTagCustomType : return "symbol is a custom compiler symbol" ; case SymTagManagedType : return "symbol is in metadata" ; case SymTagDimension : return "symbol is a FORTRAN multi-dimensional array" ; default : return "tag info could not be retrieved !" ; } } char * GetCallingConvString ( const DWORD & dwCallConv ) { switch (dwCallConv) { case CV_CALL_NEAR_C : return "near call, right to left push, caller pops stack" ; case CV_CALL_FAR_C : return "far call, right to left push, caller pops stack" ; case CV_CALL_NEAR_PASCAL: return "near call, left to right push, callee pops stack" ; case CV_CALL_FAR_PASCAL : return "far call, left to right push, callee pops stack" ; case CV_CALL_NEAR_FAST : return "near call, left to right push with regs, callee pops stack" ; case CV_CALL_FAR_FAST : return "fast call, left to right push with regs, callee pops stack" ; case CV_CALL_SKIPPED : return "skipped (unused) call" ; case CV_CALL_NEAR_STD : return "near standard call" ; case CV_CALL_FAR_STD : return "far standard call" ; case CV_CALL_NEAR_SYS : return "near sys call" ; case CV_CALL_FAR_SYS : return "far sys call" ; case CV_CALL_THISCALL : return "this call, this ptr passed in register" ; case CV_CALL_MIPSCALL : return "mips call" ; case CV_CALL_GENERIC : return "generic calling convention" ; case CV_CALL_ALPHACALL : return "alpha call" ; case CV_CALL_PPCCALL : return "PPC call" ; case CV_CALL_SHCALL : return "hitachi SuperH call" ; case CV_CALL_ARMCALL : return "ARM call" ; case CV_CALL_AM33CALL : return "AM33 call" ; case CV_CALL_TRICALL : return "TriCore Call" ; case CV_CALL_SH5CALL : return "hitachi SuperH-5 call" ; case CV_CALL_M32RCALL : return "M32R Call" ; case CV_CALL_RESERVED : return "first unused call" ; default : return "calling convention could not be detected !" ; } } BOOL CALLBACK EnumSourceFiles ( PSOURCEFILE pSourceFile, PVOID UserContext ) { /* display this header only once */ /////////////////////////////////// static bool displayed = false ; if ( ! displayed ) { cout << "\n" ; Title ( "SOURCE FILES", '#' ) ; displayed = true ; } /* display all source files */ ////////////////////////////// cout << " " << pSourceFile->FileName << "\n" ; return TRUE ; } BOOL CALLBACK EnumLocalVars ( PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext ) { /* display only name, size & addr for SYMBOL_INFO */ //////////////////////////////////////////////////// cout << setw(20) << left << " address" << " : " << hex << showbase << pSymInfo->Address << noshowbase << endl << setw(20) << left << " size (bytes)" << " : " << dec << pSymInfo->Size << endl << setw(20) << left << " name" << " : " << pSymInfo->Name << endl ; cout << endl ; return TRUE ; } BOOL CALLBACK EnumSymbols ( PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext ) { HANDLE hProcess = * ((usr_context*)UserContext)->hProcess ; DWORD64 dwModBase = ((usr_context*)UserContext)->dwModBase ; /* display this header only once */ /////////////////////////////////// static bool displayed = false ; if ( ! displayed ) { cout << "\n" ; Title ( "SYMBOL INFORMATION", '#' ) ; displayed = true ; } /* display all members of SYMBOL_INFO */ //////////////////////////////////////// cout << setw(15) << left << " Address" << " : " << hex << showbase << pSymInfo->Address << noshowbase << endl << setw(15) << left << " size (bytes)" << " : " << dec << pSymInfo->Size << endl << setw(15) << left << " module base" << " : " << hex << showbase << pSymInfo->ModBase << noshowbase << endl << setw(15) << left << " name" << " : " << pSymInfo->Name << endl << setw(15) << left << " tag info" << " : " << GetSymInfoTagString(pSymInfo->Tag) << endl ; if ( (pSymInfo->Flags & SYMFLAG_CONSTANT) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a constant\n" ; if ( (pSymInfo->Flags & SYMFLAG_EXPORT) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is from the export table\n" ; if ( (pSymInfo->Flags & SYMFLAG_FORWARDER) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a forwarder\n" ; if ( (pSymInfo->Flags & SYMFLAG_FRAMEREL) != 0 ) cout << setw(15) << left << " flag info" << " : " << "Offsets are frame relative\n" ; if ( (pSymInfo->Flags & SYMFLAG_FUNCTION) != 0 ) cout << setw(15) << left << " flag info" << " : " << "The symbol is a function\n" ; if ( (pSymInfo->Flags & SYMFLAG_LOCAL) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a local variable\n" ; if ( (pSymInfo->Flags & SYMFLAG_PARAMETER) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a parameter\n" ; if ( (pSymInfo->Flags & SYMFLAG_REGISTER) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol uses register with encoding 0x" << hex << pSymInfo->Register << "\n" ; if ( (pSymInfo->Flags & SYMFLAG_REGREL) != 0 ) cout << setw(15) << left << " flag info" << " : " << "Offsets are register relative\n" ; if ( (pSymInfo->Flags & SYMFLAG_THUNK) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a thunk\n" ; if ( (pSymInfo->Flags & SYMFLAG_TLSREL) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is an offset into the TLS data area\n" ; if ( (pSymInfo->Flags & SYMFLAG_VALUEPRESENT) != 0 ) cout << setw(15) << left << " flag info" << " : " << "value of constant is 0x" << hex << pSymInfo->Value << "\n" ; if ( (pSymInfo->Flags & SYMFLAG_VIRTUAL) != 0 ) cout << setw(15) << left << " flag info" << " : " << "symbol is a virtual symbol\n" ; // more for managed code //////////////////////// //if ( (pSymInfo->Flags & SYMFLAG_ILREL) != 0 ) // cout << setw(15) << left << " description" << " : " // << "symbol addr is an offset, relative to begining of IL block\n" ; //if ( (pSymInfo->Flags & SYMFLAG_SLOT) != 0 ) // cout << setw(15) << left << " description" << " : " // << "symbol is a managed code slot\n" ; //if ( (pSymInfo->Flags & SYMFLAG_METADATA) != 0 ) // cout << setw(15) << left << " description" << " : " // << "symbol is managed metadata\n" ; /* NOTE : pSymInfo->TypeIndex is "NOT" the actual type index. To retrieve the actual type index, use SymGetTypeInfo() with the params pSymInfo->TypeIndex and the flag TI_GET_TYPEID. The actual type index is returned in an [out] param. */ DWORD dwTypeId = 0 ; if (SymGetTypeInfo(hProcess,dwModBase,pSymInfo->TypeIndex,TI_GET_TYPEID,&dwTypeId)) cout << setw(15) << left << " type index" << " : " << dec << dwTypeId << endl ; /* get base type for symbol */ ////////////////////////////// DWORD dwBaseType = 0 ; if (SymGetTypeInfo(hProcess,dwModBase,dwTypeId,TI_GET_BASETYPE,&dwBaseType)) cout << setw(15) << left << " base type" << " : " << dec << GetBasicTypeString(dwBaseType) << endl ; /* get calling conventions for function symbols */ ////////////////////////////////////////////////// DWORD dwCallConv = 0 ; if (SymGetTypeInfo(hProcess,dwModBase,pSymInfo->TypeIndex,TI_GET_CALLING_CONVENTION,&dwCallConv)) cout << setw(15) << left << " calling convention" << " : " << dec << GetCallingConvString(dwCallConv) << endl ; /* if it is a function, then time to enumerate locals */ //////////////////////////////////////////////////////// if ( pSymInfo->Tag == SymTagFunction ) { //IMAGEHLP_STACK_FRAME istStckFrm ; //istStckFrm.InstructionOffset = pSymInfo->Address ; /* x86 Only ! */ //SymSetContext ( hProcess, & istStckFrm, NULL ) ; //cout << setw(15) << left << " Enumerating locals....\n\n" ; //SymEnumSymbols(hProcess,NULL,NULL,EnumLocalVars,NULL) ; /* 2nd param must be zero. thank you, matt pietrek */ STACKFRAME64 sfStckFrm ; CONTEXT ctCont ; HANDLE hThr = GetCurrentThread () ; if ( ! GetThreadContext ( hThr, & ctCont ) ) { ; // clean up code ! } /* initializing the STACKFRAME64 struct */ ////////////////////////////////////////// sfStckFrm.AddrPC.Mode = AddrModeFlat ; sfStckFrm.AddrStack.Mode = AddrModeFlat ; sfStckFrm.AddrFrame.Mode = AddrModeFlat ; sfStckFrm.AddrPC.Offset = ctCont.Eip ; sfStckFrm.AddrStack.Offset = ctCont.Esp ; sfStckFrm.AddrFrame.Offset = ctCont.Ebp ; if (! StackWalk64 ( IMAGE_FILE_MACHINE_I386, hProcess, hThr, & sfStckFrm, (PVOID) & ctCont, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL ) ) { ; } } cout << endl ; return TRUE ; } // currently not using this // BOOL CALLBACK EnumModules( LPSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext ) { HANDLE hProcess = (HANDLE) UserContext ; cout << " " << setw(15) << left << ModuleName << "0x" << setw(15) << left << hex << BaseOfDll << "\n" ; if (SymEnumSymbols ( hProcess, BaseOfDll, NULL, EnumSymbols, NULL )) cout << "SymInitialize succeeded.\n" ; else cout << "SymInitialize failed.\n" ; return TRUE ; } void DispModInfo ( const IMAGEHLP_MODULE64 & im64 ) { /* pre-condition check */ ///////////////////////// assert (im64.SizeOfStruct == sizeof(IMAGEHLP_MODULE64)) ; /* display all members of IMAGEHLP_MODULE64 */ ////////////////////////////////////////////// cout << "\n" ; Title ( "MODULE INFORMATION", '#' ) ; cout << setw(32) << left << " base of image (VA)" << ": 0x" << hex << im64.BaseOfImage << "\n" << setw(32) << left << " image size (bytes)" << ": " << dec << im64.ImageSize << "\n" << setw(32) << left << " date-time stamp" << ": " << ctime ((const time_t *) & im64.TimeDateStamp) /*<< "\n"*/ << setw(32) << left << " checksum" << ": 0x" << hex << im64.CheckSum << "\n" << setw(32) << left << " total symbols in symbol table" << ": " << dec << im64.NumSyms << "\n" << setw(32) << left << " symbol type" << ": " << GetIM64SymTypeString(im64.SymType) << "\n" << setw(32) << left << " module name" << ": " << im64.ModuleName << "\n" << setw(32) << left << " image name" << ": " << im64.ImageName << "\n" << setw(32) << left << " symbols loaded from" << ": " << im64.LoadedImageName << "\n\n" ; /* << setw(32) << left << " program database (PDB)" << ": " << im64.LoadedPdbName << "\n" << setw(32) << left << " codeview (CV) record signature" << setw(32) << left << " codeview (CV) record content" << setw(32) << left << " pdb signature" << setw(32) << left << " pdb signature - ver 7.0 +" << setw(32) << left << " loaded PDB unmatched ?" << setw(32) << left << " loaded DBG unmatched ?" << setw(32) << left << " line number info available ?" << setw(32) << left << " global symbol info available ?" << setw(32) << left << " type info available ?" << setw(32) << left << " PDB support for source server ?" << setw(32) << left << " module contains public symbols ?" */ } //----< main program entry point >---- void main ( int argc, char* argv[] ) { /* a little command-line check */ ///////////////////////////////// if ( argc != 2 ) { cout << "Syntax Error ! \n" << "Usage : SymHandler \n" ; return ; } char * pszModName = argv[1] ; HANDLE hProcess = GetCurrentProcess() ; /* defer symbol loading */ ////////////////////////// SymSetOptions ( SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS ) ; /* initialize the symbol handler */ /////////////////////////////////// if ( SymInitialize ( hProcess, NULL, FALSE ) ) cout << "Symbol Engine Initialized.\n" ; else cout << "Symbol Engine could not be initialized !\n" ; /* Manually load the module's symbol table */ ///////////////////////////////////////////// DWORD64 dwModBase = SymLoadModule64 (hProcess, NULL, pszModName, NULL, 0, 0) ; if ( dwModBase == 0 ) { /* Display error & terminate symbol handler */ ////////////////////////////////////////////// cout << "Module's Symbol Table could not be loaded !\n" ; if ( SymCleanup ( hProcess ) ) cout << "SymCleanup succeeded\n" ; else cout << "SymCleanup failed\n" ; return ; } /* module loaded. now continue*/ //////////////////////////////// cout << "Module's Symbol Table Loaded. \n" ; IMAGEHLP_MODULE64 im64 ; im64.SizeOfStruct = sizeof ( IMAGEHLP_MODULE64 ) ; if ( ! SymGetModuleInfo64 ( hProcess, dwModBase, & im64 ) ) { cout << "Module Info Could not be Retrieved !\n" ; // any cleanup action ????? return ; } /* module info retrieved. now continue */ ///////////////////////////////////////// cout << "Module Info Retrieved. \n" ; DispModInfo ( im64 ) ; /* now enumerate through the source files */ //////////////////////////////////////////// if (! SymEnumSourceFiles ( hProcess, dwModBase, NULL, EnumSourceFiles, NULL)) { cout << "Source File Enumeration failed !\n" ; // cleanup action ???? return ; } /* now enumerate through the symbols */ /////////////////////////////////////// usr_context UsrContext ; UsrContext.hProcess = & hProcess ; UsrContext.dwModBase = dwModBase ; if (! SymEnumSymbols(hProcess, dwModBase, NULL, EnumSymbols, (PVOID) & UsrContext)) { cout << "Symbol Enumeration failed !\n" ; // cleanup action ???? return ; } /* Manually Unload the module's symbol table */ /////////////////////////////////////////////// if ( SymUnloadModule64 ( hProcess, dwModBase ) ) cout << "Module's Symbol Table Unloaded. \n" ; else cout << "Module's Symbol Table could not be unloaded !\n" ; /* terminate the symbol handler */ ////////////////////////////////// if ( SymCleanup ( hProcess ) ) cout << "SymCleanup succeeded\n" ; else cout << "SymCleanup failed\n" ; }