JD2022-TU1/main/tools/legacy/CallStackDisplay/CallStackDisplay.cpp

363 lines
12 KiB
C++

//--------------------------------------------------------------------------------------
// 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 <fstream>
#include <string>
#include <map>
#include <time.h>
//--------------------------------------------------------------------------------------
// 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 <typename T> 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<DWORD,symbolInfo> 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<numStack;++indexStack)
{
// Load the count of how many addresses follow.
DWORD numEntries = 0;
DWORD attributes = 0;
DWORD crc = 0;
BOOL result = ReadFile( hFile, &crc, sizeof( crc ), &readCount, 0 );
if( !result)
break;
ByteReverse( crc );
result = ReadFile( hFile, &numEntries, sizeof( numEntries ), &readCount, 0 );
// When we reach the end of the file the read of numEntries will fail.
// Elsewhere I omit checking for read failures, to simplify the code.
if( !result || readCount != sizeof( numEntries ) )
break;
ByteReverse( numEntries );
// Check for bogus values.
if( numEntries > 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<numAllocation;++allocationIndex)
{
u32 memaddress;
ReadFile( hFile, &memaddress, sizeof( memaddress ), &readCount, 0 );
ByteReverse( memaddress );
fwrite(&memaddress,sizeof(memaddress),1,fileDump);
u64 memchk;
ReadFile( hFile, &memchk, sizeof( memchk ), &readCount, 0 );
ByteReverse( memchk );
fwrite(&memchk,sizeof(memchk),1,fileDump);
/*
DWORD ss = GET_SIZECHUNCK(memchk);
DWORD crc = GET_CRCCHUNCK(memchk);
*/
}
fclose(fileDump);
}
//--------------------------------------------------------------------------------------
// Name: Main
// Desc: Entry point for program
//--------------------------------------------------------------------------------------
int main( int/*argc*/, CHAR* /*argv[]*/)
{
// Declare a symbol helper object. This should be a local variable rather than
// a global variable to avoid problems caused by heavyweight construction going
// on during process load.
SymbolHelper symbols;
// Open the data file containing module information and addresses.
HANDLE hFile = CreateFile( g_filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
printf( "Can't open '%s'\n", g_filename );
return 0;
}
// Check and see if the file is a text or binary data file. The "BINR" comment
// is placed at the beginning of all binary format files created by CallStackRecording.
/*const CHAR* binaryID = "BINR";
CHAR fileID[4] = {0};
ReadFileOrAbort( hFile, &fileID, sizeof( fileID ), 0, 0 );*/
ProcessBinaryFile(hFile, symbols );
/*
// Process the file as binary or as text.
if( memcmp( binaryID, &fileID, sizeof( fileID ) ) == 0 )
{
printf( "Processing binary file.\n" );
ProcessBinaryFile( hFile, symbols );
}
else
{
printf( "Processing text file.\n" );
ProcessTextFile( g_filename, symbols );
}*/
// Clean up and exit.
CloseHandle( hFile );
return 0;
}