//-------------------------------------------------------------------------------------- // CallStackDisplay.cpp // // This sample illustrates how to do symbol lookup on your PC. Run the // CallStackRecording sample first and copy the callstacks.dat file from the devkit // to the CallStackDisplay directory. You can optionally copy the pdb file from the // CallStackRecording sample to the CallStackDisplay directory. // // DbgHelp will be used to locate system symbols in the symbol server, and DIA2 will // be used to do symbol loading and lookups. // // Microsoft Game Technology Group. // Copyright (C) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- #include "stdafx.h" #include "SymbolHelper.h" #include #include #include #include //-------------------------------------------------------------------------------------- // Name of the file to load call stack information from. //-------------------------------------------------------------------------------------- const CHAR* g_filename = "E:\\dump.dat"; typedef unsigned __int64 u64; typedef unsigned int u32; #pragma warning(push) #pragma warning(disable : 6384) // warning C6384: Dividing sizeof a pointer by another value //-------------------------------------------------------------------------------------- // Name: ByteReverse // Desc: Template function to byte-reverse in place any arbitrary block of data. //-------------------------------------------------------------------------------------- template void ByteReverse( T& data ) { BYTE* pData = ( BYTE* )&data; for( int i = 0; i < sizeof( data ) / 2; ++i ) { std::swap( pData[i], pData[sizeof( data ) - 1 - i] ); } } #pragma warning(pop) //-------------------------------------------------------------------------------------- // Name: ReadFileOrAbort // Desc: Read data from a file and abort the program if the requested data is not read. //-------------------------------------------------------------------------------------- VOID ReadFileOrAbort( __in HANDLE hFile, __out_bcount_part(nNumberOfBytesToRead, *lpNumberOfBytesRead) LPVOID lpBuffer, __in DWORD nNumberOfBytesToRead, __out_opt LPDWORD lpNumberOfBytesRead, __inout_opt LPOVERLAPPED lpOverlapped ) { // Make sure we have a bytes-read pointer. DWORD bytesRead; if( !lpNumberOfBytesRead ) lpNumberOfBytesRead = &bytesRead; BOOL result = ReadFile( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped ); if( !result || nNumberOfBytesToRead != *lpNumberOfBytesRead ) { printf( "Error reading from file--aborting\n" ); abort(); } } //-------------------------------------------------------------------------------------- // Name: ProcessBinaryFile // Desc: Process a file containing binary data describing the loaded modules and the // addresses to look up. //-------------------------------------------------------------------------------------- const DWORD maxBackTrace = 20; class TraceInfo { public: DWORD m_attributes; DWORD m_stack[maxBackTrace]; }; typedef struct _XALLOC_ATTRIBUTES { DWORD dwObjectType : 13; DWORD dwHeapTracksAttributes : 1; DWORD dwMustSucceed : 1; DWORD dwFixedSize : 1; DWORD dwAllocatorId : 8; DWORD dwAlignment : 4; DWORD dwMemoryProtect : 2; DWORD dwZeroInitialize : 1; DWORD dwMemoryType : 1; } XALLOC_ATTRIBUTES, *PXALLOC_ATTRIBUTES; struct symbolInfo { int m_iLine; std::string m_szSymbolTable; std::string m_szFileName; }; typedef std::map SymbolTable; #define MAKE_MEMCHUNCK(__size,__crc) (u64)((((u64)(__size) << 32) | __crc)) #define GET_SIZECHUNCK(__chunck) (u32)((__chunck >> 32)) #define GET_CRCCHUNCK(__chunck) (u32)((__chunck & 0xFFFFFFFF)) VOID ProcessBinaryFile( HANDLE hFile, SymbolHelper& symbols ) { DWORD readCount = 0; // Loop through all of the module information, loading symbols for // each module. for(; ; ) { // Each module is prefixed by a magic number, and the list of modules is // terminated with a DWORD zero. const DWORD modulePrefixID = 0xABABCDCD; // Read in the ID. If it is zero then we are at the end of the list of // modules. DWORD id = 0; ReadFileOrAbort( hFile, &id, sizeof( id ), &readCount, 0 ); ByteReverse( id ); if( id != modulePrefixID ) { if( id != 0 ) { printf( "Unexpected data in '%s'--aborting\n", g_filename ); return; } // We've hit a modulePrefixID of zero, which tells us we have reached // the end of the list of modules, so we exit the loop. break; } // Read in the data that describes this module. // Read the module address and byte reverse it. VOID* baseAddress = 0; ReadFileOrAbort( hFile, &baseAddress, sizeof( baseAddress ), &readCount, 0 ); ByteReverse( baseAddress ); // Read the module size and byte reverse it. size_t size = 0; ReadFileOrAbort( hFile, &size, sizeof( size ), &readCount, 0 ); ByteReverse( size ); // Read the module timestamp and byte reverse it. DWORD timeStamp = 0; ReadFileOrAbort( hFile, &timeStamp, sizeof( timeStamp ), &readCount, 0 ); ByteReverse( timeStamp ); // Read the module name. CHAR name[MAX_PATH] = {0}; ReadFileOrAbort( hFile, &name, sizeof( name ), &readCount, 0 ); // Read the module PDB signature. DM_PDB_SIGNATURE signature = {0}; ReadFileOrAbort( hFile, &signature, sizeof( signature ), &readCount, 0 ); // Load the symbols for this module. bool result = symbols.LoadSymbolsForModule( baseAddress, size, timeStamp, &signature ); printf( "Symbols loaded %s for %s\n", result ? "successfully" : "unsuccessfully", name ); } // Loop through all of the callstacks. DWORD numStack = 0; ReadFile( hFile, &numStack, sizeof( numStack ), &readCount, 0 ); ByteReverse( numStack ); FILE* fileDump; fopen_s(&fileDump,"c:\\dump.bin","wb"); fwrite(&numStack,sizeof(numStack),1,fileDump); std::string _symbolName; std::string _fileName; int _lineNumber = 0; SymbolTable mSymbolTable; for(DWORD indexStack = 0;indexStack 100 ) break; result = ReadFile( hFile, &attributes, sizeof( attributes ), &readCount, 0 ); if( !result) break; ByteReverse( attributes ); const XALLOC_ATTRIBUTES& AllocAttributes = *( XALLOC_ATTRIBUTES* )&attributes; //Loop through doing symbol lookups on all of the addresses. //printf( "\nCall stack with %u entries:\n", numEntries ); fwrite(&crc,sizeof(crc),1,fileDump); fwrite(&numEntries,sizeof(numEntries),1,fileDump); fwrite(&attributes,sizeof(attributes),1,fileDump); for( DWORD i = 0; i < numEntries; ++i ) { // Read the address and byte reverse it. DWORD address = 0; ReadFileOrAbort( hFile, &address, sizeof( address ), &readCount, 0 ); ByteReverse( address ); fwrite(&address,sizeof(address),1,fileDump); SymbolTable::const_iterator iterAddress = mSymbolTable.find(address); // Look up the symbol information for this address and print it. if (iterAddress == mSymbolTable.end() && symbols.PrintSymbolSummary( address,_symbolName,_fileName,_lineNumber)) { //record them in the symbolTable symbolInfo info; info.m_iLine = _lineNumber; info.m_szFileName = _fileName; info.m_szSymbolTable = _symbolName; mSymbolTable[address] = info; } } } //Save the symbol table; DWORD symbolTableSize = mSymbolTable.size(); fwrite(&symbolTableSize,sizeof(symbolTableSize),1,fileDump); for (SymbolTable::iterator iterAddress = mSymbolTable.begin();iterAddress != mSymbolTable.end();++iterAddress) { DWORD address = (*iterAddress).first; const symbolInfo& info = (*iterAddress).second; fwrite(&address,sizeof(address),1,fileDump); fwrite(&info.m_iLine,sizeof(info.m_iLine),1,fileDump); DWORD len = info.m_szFileName.length(); fwrite(&len,sizeof(len),1,fileDump); fwrite(info.m_szFileName.c_str(),len,1,fileDump); len = info.m_szSymbolTable.length(); fwrite(&len,sizeof(len),1,fileDump); fwrite(info.m_szSymbolTable.c_str(),len,1,fileDump); } DWORD numAllocation = 0; ReadFile( hFile, &numAllocation, sizeof( numAllocation ), &readCount, 0 ); ByteReverse( numAllocation ); fwrite(&numAllocation,sizeof(numAllocation),1,fileDump); for (DWORD allocationIndex = 0;allocationIndex