|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 2000
//
// File: moduleinfo.cpp
//
//--------------------------------------------------------------------------
// ModuleInfo.cpp: implementation of the CModuleInfo class.
//
//////////////////////////////////////////////////////////////////////
#ifndef NO_STRICT
#ifndef STRICT
#define STRICT 1
#endif
#endif /* NO_STRICT */
#include <WINDOWS.H>
#include <STDIO.H>
#include <TCHAR.H>
#include <time.h>
#include "ModuleInfo.h"
#include "Globals.h"
#include "ProgramOptions.h"
#include "SymbolVerification.h"
#include "FileData.h"
#include "UtilityFunctions.h"
#include "DmpFile.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CModuleInfo::CModuleInfo() { m_dwRefCount = 1; m_dwCurrentReadPosition = 0;
m_lpInputFile = NULL; m_lpOutputFile = NULL; m_lpDmpFile = NULL;
// File version information
m_fPEImageFileVersionInfo = false; m_tszPEImageFileVersionDescription = NULL; m_tszPEImageFileVersionCompanyName = NULL; m_tszPEImageFileVersionString = NULL; m_dwPEImageFileVersionMS = 0; m_dwPEImageFileVersionLS = 0; m_tszPEImageProductVersionString = NULL; m_dwPEImageProductVersionMS = 0; m_dwPEImageProductVersionLS = 0;
// PE Image Properties
m_tszPEImageModuleName = NULL; // Module name (eg. notepad.exe)
m_tszPEImageModuleFileSystemPath = NULL; // Full path to module (eg. C:\winnt\system32\notepad.exe)
m_dwPEImageFileSize = 0; m_ftPEImageFileTimeDateStamp.dwLowDateTime = 0; m_ftPEImageFileTimeDateStamp.dwHighDateTime = 0; m_dwPEImageCheckSum = 0; m_dwPEImageTimeDateStamp = 0; m_dwPEImageSizeOfImage = 0; m_enumPEImageType = PEImageTypeUnknown; // We need to track what ImageType we have (PE32/PE64/???)
m_dw64BaseAddress = 0;
m_wPEImageMachineArchitecture = 0; m_wCharacteristics = 0; // These are the PE image characteristics
// PE Image has a reference to DBG file
m_enumPEImageSymbolStatus = SYMBOLS_NO; // Assume there are no symbols for this module
m_tszPEImageDebugDirectoryDBGPath = NULL; // Path to DBG (found in PE Image)
// PE Image has internal symbols
m_dwPEImageDebugDirectoryCoffSize = 0; m_dwPEImageDebugDirectoryFPOSize = 0; m_dwPEImageDebugDirectoryCVSize = 0; m_dwPEImageDebugDirectoryOMAPtoSRCSize = 0; m_dwPEImageDebugDirectoryOMAPfromSRCSize = 0; // PE Image has a reference to PDB file...
m_tszPEImageDebugDirectoryPDBPath = NULL; m_dwPEImageDebugDirectoryPDBFormatSpecifier = 0; m_dwPEImageDebugDirectoryPDBSignature = 0; // PDB Signature (unique (across PDB instances) signature)
m_dwPEImageDebugDirectoryPDBAge = 0; // PDB Age (Number of times this instance has been updated)
m_tszPEImageDebugDirectoryPDBGuid = NULL;
// DBG Symbol information
m_enumDBGModuleStatus = SYMBOL_NOT_FOUND; // Status of the DBG file
m_tszDBGModuleFileSystemPath = NULL; // Path to the DBG file (after searching)
m_dwDBGTimeDateStamp = 0; m_dwDBGCheckSum = 0; m_dwDBGSizeOfImage = 0; m_dwDBGImageDebugDirectoryCoffSize = 0; m_dwDBGImageDebugDirectoryFPOSize = 0; m_dwDBGImageDebugDirectoryCVSize = 0; m_dwDBGImageDebugDirectoryOMAPtoSRCSize = 0; m_dwDBGImageDebugDirectoryOMAPfromSRCSize = 0; // DBG File has a reference to a PDB file...
m_tszDBGDebugDirectoryPDBPath = NULL; m_dwDBGDebugDirectoryPDBFormatSpecifier = 0; // NB10, RSDS, etc...
m_dwDBGDebugDirectoryPDBAge = 0; m_dwDBGDebugDirectoryPDBSignature = 0; m_tszDBGDebugDirectoryPDBGuid = NULL;
// PDB File Information
m_enumPDBModuleStatus = SYMBOL_NOT_FOUND; // Status of the PDB file
m_tszPDBModuleFileSystemPath = NULL; // Path to the PDB file (after searching)
m_dwPDBFormatSpecifier = 0; m_dwPDBSignature = 0; m_dwPDBAge = 0; m_tszPDBGuid = NULL; m_dwPDBTotalBytesOfLineInformation = 0; m_dwPDBTotalBytesOfSymbolInformation = 0; m_dwPDBTotalSymbolTypesRange = 0; }
CModuleInfo::~CModuleInfo() { // Let's cleanup a bit...
if (m_tszPEImageFileVersionDescription) delete [] m_tszPEImageFileVersionDescription;
if (m_tszPEImageFileVersionCompanyName) delete [] m_tszPEImageFileVersionCompanyName; if (m_tszPEImageFileVersionString) delete [] m_tszPEImageFileVersionString; if (m_tszPEImageProductVersionString) delete [] m_tszPEImageProductVersionString;
if (m_tszPEImageModuleName) delete [] m_tszPEImageModuleName;
if (m_tszPEImageModuleFileSystemPath) delete [] m_tszPEImageModuleFileSystemPath;
if (m_tszPEImageDebugDirectoryDBGPath) delete [] m_tszPEImageDebugDirectoryDBGPath;
if (m_tszPEImageDebugDirectoryPDBPath) delete [] m_tszPEImageDebugDirectoryPDBPath;
if (m_tszPEImageDebugDirectoryPDBGuid) delete [] m_tszPEImageDebugDirectoryPDBGuid;
if (m_tszDBGModuleFileSystemPath) delete [] m_tszDBGModuleFileSystemPath;
if (m_tszDBGDebugDirectoryPDBPath) delete [] m_tszDBGDebugDirectoryPDBPath;
if (m_tszDBGDebugDirectoryPDBGuid) delete [] m_tszDBGDebugDirectoryPDBGuid;
if (m_tszPDBModuleFileSystemPath) delete [] m_tszPDBModuleFileSystemPath;
if (m_tszPDBGuid) delete [] m_tszPDBGuid; }
//bool CModuleInfo::Initialize(CProgramOptions * lpProgramOptions, CFileData * lpInputFile, CFileData * lpOutputFile)
bool CModuleInfo::Initialize(CFileData * lpInputFile, CFileData * lpOutputFile, CDmpFile * lpDmpFile) { // Let's save off the Program Options so we don't have to pass it to every method...
m_lpInputFile = lpInputFile; m_lpOutputFile = lpOutputFile; m_lpDmpFile = lpDmpFile;
return true; }
bool CModuleInfo::GetModuleInfo(LPTSTR tszModulePath, bool fDmpFile, DWORD64 dw64ModAddress, bool fGetDataFromCSVFile) { bool fReturn = true;
if (fGetDataFromCSVFile) { fReturn = GetModuleInfoFromCSVFile(tszModulePath); } else { fReturn = GetModuleInfoFromPEImage(tszModulePath, fDmpFile, dw64ModAddress); }
return fReturn; }
LPTSTR CModuleInfo::GetModulePath() { return m_tszPEImageModuleFileSystemPath; }
bool CModuleInfo::OutputData(LPTSTR tszProcessName, DWORD iProcessID, unsigned int dwModuleNumber) { // Output to STDOUT?
if (!g_lpProgramOptions->GetMode(CProgramOptions::QuietMode)) { if (!OutputDataToStdout(dwModuleNumber)) return false; }
// Output to file?
if (g_lpProgramOptions->GetMode(CProgramOptions::OutputCSVFileMode)) { // Try and output to file...
if (!OutputDataToFile(tszProcessName, iProcessID)) return false; }
return true; }
bool CModuleInfo::fCheckPDBSignature(bool fDmpFile, HANDLE hModuleHandle, OMFSignature *pSig, PDB_INFO *ppdb) { if (!DoRead(fDmpFile, hModuleHandle, pSig, sizeof(*pSig))) return false;
if ( (pSig->Signature[0] != 'N') || (pSig->Signature[1] != 'B') || (!isdigit(pSig->Signature[2])) || (!isdigit(pSig->Signature[3])))
{ //
// If this is a DMP file (fDmpFile), odds are good that this was not compiled with
// a linker 6.20 or higher (which marks the PDB path in the PE image such
// that it gets mapped into the virtual address space (and will be in the user.dmp
// file).
//
return false; }
// This switch statement is reminiscent of some windbg code...don't shoot me
// (I modified it slightly since the NB signature isn't super important to me)...
switch (*(LONG UNALIGNED *)(pSig->Signature)) { case sigNB10: // OMF Signature, and hopefully some PDB INFO
{ if (!DoRead(fDmpFile, hModuleHandle, ppdb, sizeof(PDB_INFO))) break; }
default: break; }
// Before returning true (since we have some form of NB## symbols), we'll save this...
/*
#ifdef _UNICODE
// Source is in ANSI, dest is in _UNICODE... need to convert...
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pSig->Signature, 4, m_tszPEImageDebugDirectoryNBInfo, 4); #else
// Copy the ANSI string over...
strncpy(m_tszPEImageDebugDirectoryNBInfo, pSig->Signature, 4); #endif
m_tszPEImageDebugDirectoryNBInfo[4] = '\0'; */ return true; }
bool CModuleInfo::VerifySymbols(CSymbolVerification * lpSymbolVerification) { bool fReturn = false;
if (!m_tszPEImageModuleName) goto cleanup;
// Find/Verify a DBG file...
if (m_enumPEImageSymbolStatus == SYMBOLS_DBG) { if ( g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPath) ) { fReturn = GetDBGModuleFileUsingSymbolPath(g_lpProgramOptions->GetSymbolPath()); }
// Do we want to try an alternate method to find symbols?
if ( m_enumDBGModuleStatus != SYMBOL_MATCH ) { // Try SQL server next...
if ( g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSQLServer) ) { fReturn = GetDBGModuleFileUsingSQLServer(lpSymbolVerification); } // Try SQL2 server next ... mjl 12/14/99
if ( g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSQLServer2) ) { fReturn = GetDBGModuleFileUsingSQLServer2(lpSymbolVerification); } } } // Note, it is possible that the m_enumPEImageSymbolStatus will have changed from SYMBOLS_DBG
// to SYMBOLS_DBG_AND_PDB after the DBG file is found above...
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) || (m_enumPEImageSymbolStatus == SYMBOLS_PDB) ) { // This gets populated with the PDB filename (obtained from the DBG or PE Image)
// if (m_tszDebugDirectoryPDBPath)
if (GetDebugDirectoryPDBPath()) { if (!lpSymbolVerification) { m_enumPDBModuleStatus = SYMBOL_NO_HELPER_DLL; goto cleanup; }
fReturn = GetPDBModuleFileUsingSymbolPath();
// Do we want to try an alternate method to find symbols?
if ( m_enumPDBModuleStatus != SYMBOL_MATCH ) { // Search for PDB in SQL2 if enabled - mjl 12/14/99
if ( g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSQLServer2) ) { fReturn = GetPDBModuleFileUsingSQLServer2(lpSymbolVerification); } }
} }
cleanup:
return fReturn; }
bool CModuleInfo::GetDBGModuleFileUsingSymbolPath(LPTSTR tszSymbolPath) { HANDLE hModuleHandle = INVALID_HANDLE_VALUE; TCHAR tszDebugModulePath[_MAX_PATH+1]; TCHAR tszDrive[_MAX_DRIVE]; TCHAR tszDir[_MAX_DIR]; TCHAR tszExtModuleName[_MAX_EXT]; TCHAR tszDBGModuleName[_MAX_FNAME]; TCHAR tszSymbolPathWithModulePathPrepended[_MAX_PATH+_MAX_PATH+1]; TCHAR tszPEImageModuleName[_MAX_FNAME+_MAX_EXT+1];
bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths();
// We have two options on the name of the DBG file...
//
// We compose the name of the DBG file we're searching for and pass that as the
// first parameter (we could grab that which is in the MISC section but the
// debuggers do not tend to do that...
//
// or
//
// We actually grab the MISC section and pull the name from there...
if (!g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeUsingDBGInMISCSection)) { // We search for this PE Image by it's actual name...
_tcscpy(tszPEImageModuleName, m_tszPEImageModuleName);
// Compose the DBG filename from the PE Image Name
_tsplitpath(m_tszPEImageModuleName, NULL, NULL, tszDBGModuleName, NULL); _tcscat(tszDBGModuleName, TEXT(".DBG"));
} else { // If we're told to grab the DBG name from the MISC section... and there isn't one...
// bail!
if (!m_tszPEImageDebugDirectoryDBGPath) goto cleanup;
// Okay, the user wants us to look in the MISC section of the Debug Directories
// to figure out the DBG file location... though the FindDebugInfoFileEx() takes
// as an argument the name of the DBG file... if you provide the PE Image name
// instead, it performs a search that is more "broad"...
// Split the DBG file info found in the MISC section into components...
_tsplitpath(m_tszPEImageDebugDirectoryDBGPath, NULL, NULL, tszDBGModuleName, tszExtModuleName);
// Save the module name found here...
_tcscpy(tszPEImageModuleName, tszDBGModuleName);
// Append the DBG extension back on...
_tcscat(tszDBGModuleName, tszExtModuleName);
// Grab the extension of the PE Image and add it to end of our DBG module name..
_tsplitpath(m_tszPEImageModuleName, NULL, NULL, NULL, tszExtModuleName); _tcscat(tszPEImageModuleName, tszExtModuleName); }
// _tcsupr(tszDBGModuleName);
tszSymbolPathWithModulePathPrepended[0] = '\0'; // Fast way to empty this string ;)
if (fDebugSearchPaths) { _tprintf(TEXT("DBG Search - Looking for [%s] Using Symbol Path...\n"), tszDBGModuleName); };
if (g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ) { if (fDebugSearchPaths) { _tprintf(TEXT("DBG Search - SEARCH in Symbol Tree We're Building!\n")); };
// When we are constructing a build symbol tree... we should first
// search there to see if our symbol is already present...
hModuleHandle = CUtilityFunctions::FindDebugInfoFileEx(tszPEImageModuleName, g_lpProgramOptions->GetSymbolTreeToBuild(), tszDebugModulePath, VerifyDBGFile, this);
// Close handle if one is returned...
if (hModuleHandle != NULL) { CloseHandle(hModuleHandle); }
// Hey, if we found it, we're done...
if (GetDBGSymbolModuleStatus() == SYMBOL_MATCH) { goto cleanup; } }
// Okay, we're not building a symbol tree... or we didn't find our symbol match in
// the symbol tree... keep looking...
// Well... let's search the SymbolPath provided for the DBG file...
if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathRecursion)) { // Do we use recursion???
if (fDebugSearchPaths) { _tprintf(TEXT("DBG Search - SEARCH Symbol path with recursion!\n")); // ISSUE-2000/07/24-GREGWI: Does FindDebugInfoFileEx2 support SYMSRV?
}; hModuleHandle = CUtilityFunctions::FindDebugInfoFileEx2(tszDBGModuleName, tszSymbolPath, VerifyDBGFile, this);
} else { // Only do this if we're doing the standard file search mechanism...
if (!g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly)) { // Don't do this block here if VerifySymbolsModeWithSymbolPathOnly option has been set...
// Hmm... Windbg changed behavior and now prepends the module path to the
// front of the symbolpath before called FindDebugInfoFileEx()...
_tsplitpath(m_tszPEImageModuleFileSystemPath, tszDrive, tszDir, NULL, NULL);
_tcscat(tszSymbolPathWithModulePathPrepended, tszDrive); _tcscat(tszSymbolPathWithModulePathPrepended, tszDir); _tcscat(tszSymbolPathWithModulePathPrepended, TEXT(";")); } _tcscat(tszSymbolPathWithModulePathPrepended, tszSymbolPath);
if (fDebugSearchPaths) { _tprintf(TEXT("DBG Search - SEARCH Symbol path!\n")); };
// Do we do the standard thing?
hModuleHandle = CUtilityFunctions::FindDebugInfoFileEx(tszPEImageModuleName, tszSymbolPathWithModulePathPrepended, tszDebugModulePath, VerifyDBGFile, this); }
cleanup: // If we have a hModuleHandle... free it now..
if (hModuleHandle != NULL) { CloseHandle(hModuleHandle); }
// We found the following path
if (m_tszDBGModuleFileSystemPath) { // Okay, let's clean up any "strangeness" added by FindDebugInfoFileEx()
// If a symbol is found in the same directory as the module, it will be
// returned with an extra \.\ combination (which is superfluous normally)...
LPTSTR tszLocationOfExtraJunk = _tcsstr(m_tszDBGModuleFileSystemPath, TEXT("\\.\\"));
if ( tszLocationOfExtraJunk ) { // Remember where we were...
LPTSTR tszPreviousLocation = tszLocationOfExtraJunk;
// Skip the junk...
tszLocationOfExtraJunk = CharNext(tszLocationOfExtraJunk); // '\\'
tszLocationOfExtraJunk = CharNext(tszLocationOfExtraJunk); // '.'
// While we have data... copy to the old location...
while (*tszLocationOfExtraJunk) { *tszPreviousLocation = *tszLocationOfExtraJunk; tszLocationOfExtraJunk = CharNext(tszLocationOfExtraJunk); tszPreviousLocation = CharNext(tszPreviousLocation); }
// Null terminate the module path...
*tszPreviousLocation = '\0'; }
}
if (fDebugSearchPaths) { if (GetDBGSymbolModuleStatus() == SYMBOL_MATCH) { _tprintf(TEXT("DBG Search - Debug Module Found at [%s]\n\n"), m_tszDBGModuleFileSystemPath); } else { _tprintf(TEXT("DBG Search - Debug Module Not Found.\n\n")); } }
return true; }
bool CModuleInfo::GetDBGModuleFileUsingSQLServer(CSymbolVerification * lpSymbolVerification) { // Do we need to initialize the SQL Server Connection?
if (!lpSymbolVerification->SQLServerConnectionInitialized() && !lpSymbolVerification->SQLServerConnectionAttempted()) { if (!lpSymbolVerification->InitializeSQLServerConnection( g_lpProgramOptions->GetSQLServerName() ) ) return false; }
// Let's only use the SQL Server if it was initialized properly...
if ( lpSymbolVerification->SQLServerConnectionInitialized() ) { if (!lpSymbolVerification->SearchForDBGFileUsingSQLServer(m_tszPEImageModuleName, m_dwPEImageTimeDateStamp, this)) return false; } return true; }
// begin SQL2 - mjl 12/14/99
bool CModuleInfo::GetDBGModuleFileUsingSQLServer2(CSymbolVerification * lpSymbolVerification) { // Do we need to initialize the SQL Server Connection?
if (!lpSymbolVerification->SQLServerConnectionInitialized2() && !lpSymbolVerification->SQLServerConnectionAttempted2()) { if (!lpSymbolVerification->InitializeSQLServerConnection2( g_lpProgramOptions->GetSQLServerName2() ) ) return false; }
// Let's only use the SQL Server if it was initialized properly...
if ( lpSymbolVerification->SQLServerConnectionInitialized2() ) { if (!lpSymbolVerification->SearchForDBGFileUsingSQLServer2(m_tszPEImageModuleName, m_dwPEImageTimeDateStamp, this)) return false; } return true; }
bool CModuleInfo::GetPDBModuleFileUsingSQLServer2(CSymbolVerification * lpSymbolVerification) { // Do we need to initialize the SQL Server Connection?
if (!lpSymbolVerification->SQLServerConnectionInitialized2() && !lpSymbolVerification->SQLServerConnectionAttempted2()) { if (!lpSymbolVerification->InitializeSQLServerConnection2( g_lpProgramOptions->GetSQLServerName2() ) ) return false; }
// Let's only use the SQL Server if it was initialized properly...
if ( lpSymbolVerification->SQLServerConnectionInitialized2() ) { if (!lpSymbolVerification->SearchForPDBFileUsingSQLServer2(m_tszPEImageModuleName, m_dwPEImageDebugDirectoryPDBSignature, this)) return false; } return true; } // end SQL2 - mjl 12/14/99
bool CModuleInfo::fValidDBGCheckSum() { if (m_enumDBGModuleStatus == SYMBOL_MATCH) return true;
if ((g_lpProgramOptions->GetVerificationLevel() == 1) && fValidDBGTimeDateStamp()) return true;
if (m_enumDBGModuleStatus == SYMBOL_POSSIBLE_MISMATCH) return (m_dwPEImageCheckSum == m_dwDBGCheckSum);
return false; }
bool CModuleInfo::fValidDBGTimeDateStamp() { return ( (m_enumDBGModuleStatus == SYMBOL_POSSIBLE_MISMATCH) || (m_enumDBGModuleStatus == SYMBOL_MATCH) ) ? (m_dwPEImageTimeDateStamp == m_dwDBGTimeDateStamp ) : false; }
bool CModuleInfo::GetPDBModuleFileUsingSymbolPath() { enum { niNil = 0, PDB_MAX_PATH = 260, cbErrMax = 1024, };
HANDLE hModuleHandle = NULL; TCHAR tszSymbolPathWithModulePathPrepended[_MAX_PATH+_MAX_PATH+1]; bool fSuccess = false; TCHAR tszRefPath[_MAX_PATH]; TCHAR tszImageExt[_MAX_EXT] = {0}; // In case there is no extension we need to null terminate now...
char szPDBOut[cbErrMax]; TCHAR tszPDBModuleName[_MAX_FNAME]; LPTSTR pcEndOfPath = NULL; tszPDBModuleName[0] = '\0'; tszSymbolPathWithModulePathPrepended[0] = '\0'; bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths();
_tsplitpath(m_tszPEImageModuleFileSystemPath, NULL, NULL, NULL, tszImageExt);
// Copy the symbol name we're searching for from the Debug Directories
//LPTSTR lptszPointerToPDBName = _tcsrchr(m_tszDebugDirectoryPDBPath, '\\');
LPTSTR lptszPointerToPDBName = _tcsrchr(GetDebugDirectoryPDBPath(), '\\');
// If we don't find a \ char, then go ahead and copy the PDBPath directly...
if (lptszPointerToPDBName == NULL) { //_tcscpy(tszPDBModuleName, m_tszDebugDirectoryPDBPath);
_tcscpy(tszPDBModuleName, GetDebugDirectoryPDBPath()); } else { // Advance past the \ char...
lptszPointerToPDBName = CharNext(lptszPointerToPDBName); _tcscpy(tszPDBModuleName, lptszPointerToPDBName); }
if (fDebugSearchPaths) { //_tprintf(TEXT("PDB Search - Looking for [%s] Using Symbol Path...\n"), g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : m_tszDebugDirectoryPDBPath);
_tprintf(TEXT("PDB Search - Looking for [%s] Using Symbol Path...\n"), g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : GetDebugDirectoryPDBPath()); };
if (g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ) { // When we are constructing a build symbol tree... we should first
// search there to see if our symbol is already present...
// Do we do the standard thing?
if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - SEARCH in Symbol Tree We're Building!\n")); }; //fSuccess = LocatePdb(g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : m_tszDebugDirectoryPDBPath,
fSuccess = LocatePdb(g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : GetDebugDirectoryPDBPath(), m_dwPEImageDebugDirectoryPDBAge, m_dwPEImageDebugDirectoryPDBSignature, g_lpProgramOptions->GetSymbolTreeToBuild(), &tszImageExt[1], false);
// Hey, if we found it, we're done...
if (fSuccess) { goto cleanup; } }
if (!g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly)) { // Hey, we better have one or the other...
if (!m_tszDBGModuleFileSystemPath && !m_tszPEImageModuleFileSystemPath) goto cleanup;
// figure out the home directory of the EXE/DLL or DBG file - pass that along to
// OpenValidate this will direct to dbi to search for it in that directory.
_tfullpath(tszRefPath, m_tszDBGModuleFileSystemPath ? m_tszDBGModuleFileSystemPath : m_tszPEImageModuleFileSystemPath, sizeof(tszRefPath)/sizeof(TCHAR)); pcEndOfPath = _tcsrchr(tszRefPath, '\\'); *pcEndOfPath = '\0'; // null terminate it
*szPDBOut = '\0';
if (_MAX_PATH+_MAX_PATH+1 < (_tcsclen(tszRefPath) + _tcsclen(g_lpProgramOptions->GetSymbolPath())+2)) goto cleanup; // Buffer isn't big enough... sigh...
_tcscat(tszSymbolPathWithModulePathPrepended, tszRefPath); _tcscat(tszSymbolPathWithModulePathPrepended, TEXT(";")); }
_tcscat(tszSymbolPathWithModulePathPrepended, g_lpProgramOptions->GetSymbolPath());
// Well... let's search the SymbolPath provided for the PDB file...
if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathRecursion)) { if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - SEARCH Symbol path with recursion!\n")); // ISSUE-2000/07/24-GREGWI: Does FindDebugInfoFileEx2 support SYMSRV?
};
// Do we use recursion???
// ISSUE-2000/07/24-GREGWI - Are we passing the right first arg? Is this supported?
hModuleHandle = CUtilityFunctions::FindDebugInfoFileEx2(tszPDBModuleName, tszSymbolPathWithModulePathPrepended, VerifyPDBFile, this);
if (hModuleHandle != NULL) { CloseHandle(hModuleHandle); }
fSuccess = false; } else { if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - SEARCH Symbol path!\n")); };
// Search for the PDB file the old fashioned way...
// fSuccess = LocatePdb(g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : m_tszDebugDirectoryPDBPath,
if (m_enumPEImageSymbolStatus == SYMBOLS_PDB) { fSuccess = LocatePdb(g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : GetDebugDirectoryPDBPath(), m_dwPEImageDebugDirectoryPDBAge, m_dwPEImageDebugDirectoryPDBSignature, tszSymbolPathWithModulePathPrepended, &tszImageExt[1], false); } else { fSuccess = LocatePdb(g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly) ? tszPDBModuleName : GetDebugDirectoryPDBPath(), m_dwDBGDebugDirectoryPDBAge, m_dwDBGDebugDirectoryPDBSignature, tszSymbolPathWithModulePathPrepended, &tszImageExt[1], false); } }
cleanup:
if (fDebugSearchPaths) { if (GetPDBSymbolModuleStatus() == SYMBOL_MATCH) { _tprintf(TEXT("PDB Search - Debug Module Found at [%s]\n\n"), m_tszPDBModuleFileSystemPath); } else { _tprintf(TEXT("PDB Search - Debug Module Not Found.\n\n")); } }
return fSuccess; }
BOOL CModuleInfo::VerifyPDBFile(HANDLE hFileHandle, LPTSTR tszFileName, PVOID CallerData) { PDB * lpPdb = NULL; EC ec = 0; char szError[cbErrMax] = ""; bool fPdbModuleFound = false; char szFileName[_MAX_FNAME+1]; hFileHandle = INVALID_HANDLE_VALUE;
// Let's grab the data passed to us...
CModuleInfo * lpModuleInfo = (CModuleInfo *) CallerData; // mjl
CUtilityFunctions::CopyTSTRStringToAnsi(tszFileName, szFileName, _MAX_FNAME+1);
PDBOpenValidate(szFileName, NULL, pdbRead, lpModuleInfo->m_dwPEImageDebugDirectoryPDBSignature, lpModuleInfo->m_dwPEImageDebugDirectoryPDBAge, &ec, szError, &lpPdb);
// Based on the return code, the path may be saved, and the PDB Module Status
// updated...
fPdbModuleFound = lpModuleInfo->HandlePDBOpenValidateReturn(lpPdb, tszFileName, ec);
if (lpPdb) { PDBClose(lpPdb); lpPdb = NULL; }
return fPdbModuleFound ? (ec == EC_OK) : FALSE; }
bool CModuleInfo::LocatePdb( LPTSTR tszPDB, ULONG PdbAge, ULONG PdbSignature, LPTSTR tszSymbolPath, LPTSTR tszImageExt, bool fImagePathPassed ) { PDB *lpPdb = NULL; EC ec = 0; char szError[cbErrMax] = ""; TCHAR tszPDBSansPath[_MAX_FNAME]; TCHAR tszPDBExt[_MAX_EXT]; TCHAR tszPDBLocal[_MAX_PATH]; char szPDBLocal[_MAX_PATH]; LPTSTR ptszSemiColon; DWORD pass; BOOL symsrv = TRUE; TCHAR tszPDBName[_MAX_PATH]; bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths();
// We're pessimistic initially...
m_enumPDBModuleStatus = SYMBOL_NOT_FOUND; bool fPdbModuleFound = false;
// szSymbolPath is a semicolon delimited path (reference path first)
_tcscpy(tszPDBLocal, tszPDB); _tsplitpath(tszPDBLocal, NULL, NULL, tszPDBSansPath, tszPDBExt);
do { ptszSemiColon = _tcschr(tszSymbolPath, ';');
if (ptszSemiColon) { *ptszSemiColon = '\0'; } if (fImagePathPassed) { pass = 2; fImagePathPassed = 0; } else { pass = 0; } if (tszSymbolPath) { do_again: if (!_tcsnicmp(tszSymbolPath, TEXT("SYMSRV*"), 7)) { *tszPDBLocal = 0; _stprintf(tszPDBName, TEXT("%s%s"), tszPDBSansPath, TEXT(".pdb"));
if (symsrv) {
if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - SYMSRV [%s,0x%x,0x%x]\n"), tszSymbolPath, PdbSignature, PdbAge); }
CUtilityFunctions::GetSymbolFileFromServer(tszSymbolPath, tszPDBName, PdbSignature, PdbAge, 0, tszPDBLocal); symsrv = FALSE; } } else { _tcscpy(tszPDBLocal, tszSymbolPath); CUtilityFunctions::EnsureTrailingBackslash(tszPDBLocal); // search order is ...
//
// %dir%\symbols\%ext%\%file%
// %dir%\%ext%\%file%
// %dir%\%file%
switch (pass) { case 0: _tcscat(tszPDBLocal, TEXT("symbols")); CUtilityFunctions::EnsureTrailingBackslash(tszPDBLocal); // pass through
case 1: _tcscat(tszPDBLocal, tszImageExt); // pass through
default: CUtilityFunctions::EnsureTrailingBackslash(tszPDBLocal); break; } _tcscat(tszPDBLocal, tszPDBSansPath); _tcscat(tszPDBLocal, tszPDBExt); }
// Okay... at this point we may have a path to a PDB file to examine...
// If so, then issue the PDBOpenValidate() and attempt to verify it...
if (*tszPDBLocal) { CUtilityFunctions::CopyTSTRStringToAnsi(tszPDBLocal, szPDBLocal, _MAX_PATH);
if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - Search here [%s]\n"), tszPDBLocal); }
PDBOpenValidate(szPDBLocal, NULL, "r", PdbSignature, PdbAge, &ec, szError, &lpPdb);
if (lpPdb) { fPdbModuleFound = true; }
// Based on the return code, the path may be saved, and the PDB Module Status
// updated...
if ( !HandlePDBOpenValidateReturn(lpPdb, tszPDBLocal, ec) ) goto cleanup;
if (fPdbModuleFound) { PDBClose(lpPdb); lpPdb = NULL; break; } else { if (pass < 2) { pass++; goto do_again; } } } }
// If we found a semicolon before... then restore the semi... and move just beyond it...
// Enable our symsrv searching again...
if (ptszSemiColon) { *ptszSemiColon = ';'; ptszSemiColon++; symsrv = TRUE; }
// Reset the tszSymbolPath to the new location...
tszSymbolPath = ptszSemiColon;
} while (ptszSemiColon);
// Only try this last check if we're not bound to our Symbol Path Only
if (!g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsModeWithSymbolPathOnly)) { // Okay... if pdb is still not found... then try the tszPDB location...
if (!lpPdb) { // ISSUE-2000/07/24-GREGWI: Is it required to copy the tszPDB string here?
_tcscpy(tszPDBLocal, tszPDB); CUtilityFunctions::CopyTSTRStringToAnsi(tszPDBLocal, szPDBLocal, _MAX_PATH);
if (fDebugSearchPaths) { _tprintf(TEXT("PDB Search - Search here [%s]\n"), tszPDBLocal); }
PDBOpenValidate(szPDBLocal, NULL, "r", PdbSignature, PdbAge, &ec, szError, &lpPdb); if ( !HandlePDBOpenValidateReturn(lpPdb, tszPDBLocal, ec) ) goto cleanup; if (lpPdb) { fPdbModuleFound = true; PDBClose(lpPdb); lpPdb = NULL; }
} }
cleanup: return fPdbModuleFound; }
BOOL CModuleInfo::VerifyDBGFile(HANDLE hFileHandle, LPTSTR tszFileName, PVOID CallerData) { CModuleInfo * lpModuleInfo = (CModuleInfo * )CallerData; WORD wMagic; // Read to identify a DBG file...
bool fPerfectMatch = false; // Assume we don't have a good DBG match...
// DBG Image Locals
IMAGE_SEPARATE_DEBUG_HEADER ImageSeparateDebugHeader;
// Start at the top of the image...
lpModuleInfo->SetReadPointer(false, hFileHandle, 0, FILE_BEGIN);
// Read in a signature word... is this a DBG file?
if ( !lpModuleInfo->DoRead(false, hFileHandle, &wMagic, sizeof(wMagic) ) ) goto cleanup;
// No sense in going further since we're expecting a DBG image file...
if (wMagic != IMAGE_SEPARATE_DEBUG_SIGNATURE) goto cleanup;
// Start at the top of the image...
lpModuleInfo->SetReadPointer(false, hFileHandle, 0, FILE_BEGIN);
// Read in the full Separate Debug Header
if ( !lpModuleInfo->DoRead(false, hFileHandle, &ImageSeparateDebugHeader, sizeof(ImageSeparateDebugHeader) ) ) goto cleanup;
//
// We have a more stringent requirement for matching the checksum if the verification level is set...
//
if ( (lpModuleInfo->m_dwPEImageTimeDateStamp == ImageSeparateDebugHeader.TimeDateStamp ) && (lpModuleInfo->m_dwPEImageSizeOfImage == ImageSeparateDebugHeader.SizeOfImage ) ) { if (g_lpProgramOptions->GetVerificationLevel() == 2) { if (lpModuleInfo->m_dwPEImageCheckSum == ImageSeparateDebugHeader.CheckSum) fPerfectMatch = true; } else { fPerfectMatch = true; } }
//
// We're going to perform some action below unless this is not a perfect match
// and we've already picked up a "bad" DBG file reference...
//
if (!fPerfectMatch && lpModuleInfo->m_tszDBGModuleFileSystemPath) goto cleanup;
//
// Take action based on our results...
// 1. If we have a perfect match... save our stuff!
// 2. If we don't already have a DBG, go ahead and save (even if wrong)
//
// Save off the checksum/linker information...
lpModuleInfo->m_dwDBGTimeDateStamp = ImageSeparateDebugHeader.TimeDateStamp; lpModuleInfo->m_dwDBGCheckSum = ImageSeparateDebugHeader.CheckSum; lpModuleInfo->m_dwDBGSizeOfImage = ImageSeparateDebugHeader.SizeOfImage; // If we already had a path to a wrong DBG file, delete it...
if (lpModuleInfo->m_tszDBGModuleFileSystemPath) { delete [] lpModuleInfo->m_tszDBGModuleFileSystemPath; lpModuleInfo->m_tszDBGModuleFileSystemPath = NULL; }
// Save the Module Path now that we know we have a match...
// Okay, let's save off the path to the DBG file...
lpModuleInfo->m_tszDBGModuleFileSystemPath = (LPTSTR)CUtilityFunctions::CopyString(tszFileName);
// Delete any PDB reference we may have found in our last DBG file (if any)...
if (lpModuleInfo->m_tszDBGDebugDirectoryPDBPath) { delete [] lpModuleInfo->m_tszDBGDebugDirectoryPDBPath; lpModuleInfo->m_tszDBGDebugDirectoryPDBPath = NULL; }
//
// At this point, we only continue on if we've made a perfect "hit"
//
if (!fPerfectMatch) { // Not a perfect symbol.. record the status and exit...
lpModuleInfo->m_enumDBGModuleStatus = SYMBOL_POSSIBLE_MISMATCH;
goto cleanup; }
// Good symbol.. record this...
lpModuleInfo->m_enumDBGModuleStatus = SYMBOL_MATCH;
// Now that we're done verifying the module... do we save the symbol in
// our tree?
if ( g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ) { // Yup...
CUtilityFunctions::CopySymbolFileToSymbolTree(lpModuleInfo->m_tszPEImageModuleName, &lpModuleInfo->m_tszDBGModuleFileSystemPath, g_lpProgramOptions->GetSymbolTreeToBuild()); }
//
// Okay, now with a good symbol let's extract the goods...
//
// If there's no debug info, we can't continue further.
if (ImageSeparateDebugHeader.DebugDirectorySize == 0) { goto cleanup; }
// Okay, we need to advance by the IMAGE_SECTION_HEADER...
lpModuleInfo->SetReadPointer(false, hFileHandle, (ImageSeparateDebugHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), FILE_CURRENT);
// Skip over the exported names.
if (ImageSeparateDebugHeader.ExportedNamesSize) { lpModuleInfo->SetReadPointer(false, hFileHandle, ImageSeparateDebugHeader.ExportedNamesSize, FILE_CURRENT); } if (!lpModuleInfo->ProcessDebugDirectory(false, false, hFileHandle, ImageSeparateDebugHeader.DebugDirectorySize, lpModuleInfo->GetReadPointer())) goto cleanup;
cleanup:
return (fPerfectMatch ? TRUE : FALSE); }
bool CModuleInfo::OutputDataToFile(LPTSTR tszProcessName, DWORD iProcessID) {
LPTSTR tszString = NULL;
bool fReturn = false;
// We remove the first three columns if -E was specified...
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { // Let's skip the first column to make room for the tag in the first column...
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// Process Name
//
if (tszProcessName) { if (!m_lpOutputFile->WriteString(tszProcessName, true)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// BUG 524 - GREGWI - CheckSym - Unable to read CSV file generated on Windows 2000 Machine
// (I changed the code to emit the PID no matter what it's value, I was special casing 0)
//
// Process ID
//
// ISSUE-2000/07/24-GREGWI: Put conditional write back in (only emit if this is PROCESSES collection
// ISSUE-2000/07/24-GREGWI: we don't want to see 0 as the PID for any other collection....
if (tszProcessName) { // Let's only emit the PID if there is a process name...
if (!m_lpOutputFile->WriteDWORD(iProcessID)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
}
// if -E is specified, we only spit out if the module has a problem
if ( g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode) ) {
switch (m_enumPEImageSymbolStatus) { case SYMBOLS_DBG: if ( m_enumDBGModuleStatus == SYMBOL_MATCH) { // Don't print this out.. it matches...
fReturn = true; goto cleanup; } break;
case SYMBOLS_DBG_AND_PDB: if ( m_enumDBGModuleStatus == SYMBOL_MATCH && m_enumPDBModuleStatus == SYMBOL_MATCH ) { // Don't print this out.. it matches...
fReturn = true; goto cleanup; } break;
case SYMBOLS_PDB: if ( m_enumPDBModuleStatus == SYMBOL_MATCH) { // Don't print this out.. it matches...
fReturn = true; goto cleanup; } break; } }
//
// Module Path
//
if (m_tszPEImageModuleFileSystemPath) { if (!m_lpOutputFile->WriteString(m_tszPEImageModuleFileSystemPath, true)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// Symbol Status
//
if (m_enumPEImageSymbolStatus != SYMBOL_INFORMATION_UNKNOWN) { tszString = SymbolInformationString(m_enumPEImageSymbolStatus);
if (tszString) { if (!m_lpOutputFile->WriteString(tszString)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
// We remove this column if -E is specified
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { //
// Checksum
//
if ( m_enumPEImageSymbolStatus != SYMBOL_INFORMATION_UNKNOWN ) { if (!m_lpOutputFile->WriteDWORD(m_dwPEImageCheckSum)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup; //
// Time/Date Stamp
//
if ( m_enumPEImageSymbolStatus != SYMBOL_INFORMATION_UNKNOWN ) { if (!m_lpOutputFile->WriteDWORD(m_dwPEImageTimeDateStamp)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
}
//
// Time/Date String
//
// If -E is specified we'll use version2 of the output format...
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { if ( m_enumPEImageSymbolStatus != SYMBOL_INFORMATION_UNKNOWN ) { if (!m_lpOutputFile->WriteTimeDateString(m_dwPEImageTimeDateStamp)) goto cleanup; } } else { if (!m_lpOutputFile->WriteTimeDateString2(m_dwPEImageTimeDateStamp)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
// We remove these columns if -E is specified
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { //
// Size Of Image (internal PE value) - used for SYMSRV support
//
if (!m_lpOutputFile->WriteDWORD(m_dwPEImageSizeOfImage)) goto cleanup;
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// DBG Pointer
//
if ( m_enumPEImageSymbolStatus == SYMBOLS_DBG || m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB ) { // Output the Path
if (m_tszPEImageDebugDirectoryDBGPath) { if (!m_lpOutputFile->WriteString(m_tszPEImageDebugDirectoryDBGPath, true)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// PDB Pointer
//
if ( m_enumPEImageSymbolStatus == SYMBOLS_PDB ) { // Output the Path
if (GetDebugDirectoryPDBPath()) { if (!m_lpOutputFile->WriteString(GetDebugDirectoryPDBPath(), true)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// PDB Signature
//
if ( m_enumPEImageSymbolStatus == SYMBOLS_PDB ) { if (!m_lpOutputFile->WriteDWORD(m_dwPEImageDebugDirectoryPDBSignature)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// PDB Age
//
if ( m_enumPEImageSymbolStatus == SYMBOLS_PDB ) { if (!m_lpOutputFile->WriteDWORD(m_dwPEImageDebugDirectoryPDBAge)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
}
//
// Product Version
//
// We remove these columns if -E is specified
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { if (m_fPEImageFileVersionInfo && m_tszPEImageProductVersionString) { if (!m_lpOutputFile->WriteString(m_tszPEImageProductVersionString)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup; }
//
// File Version
//
if (m_fPEImageFileVersionInfo && m_tszPEImageFileVersionString) { if (!m_lpOutputFile->WriteString(m_tszPEImageFileVersionString)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup; //
// Company Name
//
if (m_fPEImageFileVersionInfo && m_tszPEImageFileVersionCompanyName) { if (!m_lpOutputFile->WriteString(m_tszPEImageFileVersionCompanyName, true)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// File Description
//
if (m_fPEImageFileVersionInfo && m_tszPEImageFileVersionDescription) { if (!m_lpOutputFile->WriteString(m_tszPEImageFileVersionDescription, true)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
// We remove these columns if -E is specified
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { //
// File Size (in bytes)
//
if ( m_dwPEImageFileSize ) { if (!m_lpOutputFile->WriteDWORD(m_dwPEImageFileSize)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
// File Date High Word
if ( m_ftPEImageFileTimeDateStamp.dwLowDateTime || m_ftPEImageFileTimeDateStamp.dwHighDateTime ) { if (!m_lpOutputFile->WriteDWORD(m_ftPEImageFileTimeDateStamp.dwHighDateTime)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
// File Date Low Word
if ( m_ftPEImageFileTimeDateStamp.dwLowDateTime || m_ftPEImageFileTimeDateStamp.dwHighDateTime ) { if (!m_lpOutputFile->WriteDWORD(m_ftPEImageFileTimeDateStamp.dwLowDateTime)) goto cleanup; }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
}
// File Date String
if ( m_ftPEImageFileTimeDateStamp.dwLowDateTime || m_ftPEImageFileTimeDateStamp.dwHighDateTime ) { // If -E is specified we'll use version2 of the output format...
if (!g_lpProgramOptions->GetMode(CProgramOptions::ExceptionMonitorMode)) { if (!m_lpOutputFile->WriteFileTimeString(m_ftPEImageFileTimeDateStamp)) goto cleanup; } else { if (!m_lpOutputFile->WriteFileTimeString2(m_ftPEImageFileTimeDateStamp)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) { //
// Local DBG Status
//
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG) || (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) ) {
tszString = SymbolModuleStatusString(m_enumDBGModuleStatus);
if (tszString) { if (!m_lpOutputFile->WriteString(tszString)) goto cleanup; }
}
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// Local DBG
//
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG) || (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) ) { if (m_tszDBGModuleFileSystemPath) { if (!m_lpOutputFile->WriteString(m_tszDBGModuleFileSystemPath, true)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// Local PDB Status
//
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) || (m_enumPEImageSymbolStatus == SYMBOLS_PDB) ) { tszString = SymbolModuleStatusString(m_enumPDBModuleStatus); if (tszString) { if (!m_lpOutputFile->WriteString(tszString)) goto cleanup; } }
if (!m_lpOutputFile->WriteString(TEXT(","))) goto cleanup;
//
// Local PDB
//
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) || (m_enumPEImageSymbolStatus == SYMBOLS_PDB) ) { if (m_tszPDBModuleFileSystemPath) { if (!m_lpOutputFile->WriteString(m_tszPDBModuleFileSystemPath, true)) goto cleanup; } } } // Write the carriage-return line-feed at the end of the line...
if (!m_lpOutputFile->WriteString(TEXT("\r\n"))) goto cleanup;
fReturn = true; // Success
cleanup:
if (!fReturn) { _tprintf(TEXT("Error: Failure writing module data!\n")); m_lpOutputFile->PrintLastError(); } return fReturn; }
bool CModuleInfo::OutputDataToStdout(DWORD dwModuleNumber) { //
// Do we output this module?
//
if (!OutputDataToStdoutThisModule()) return false; //
// First, Output Module Info
//
OutputDataToStdoutModuleInfo(dwModuleNumber);
bool fPrintCarriageReturn = false;
//
// Second, if we were to collect symbol info, but NOT verify... dump out what we
// discovered about the symbol info...
//
if (g_lpProgramOptions->GetMode(CProgramOptions::OutputSymbolInformationMode) && !g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) { fPrintCarriageReturn = true;
switch (m_enumPEImageSymbolStatus) { case SYMBOL_INFORMATION_UNKNOWN: _tprintf(TEXT(" Module symbol information was not collected!\n")); break;
case SYMBOLS_NO: _tprintf(TEXT(" Module has NO symbols!\n")); break;
case SYMBOLS_LOCAL: //
// This module has ONLY local symbols...
//
_tprintf(TEXT(" Module has internal symbols only! %s\n"), SourceEnabledPEImage()); OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize); break;
case SYMBOLS_DBG:
//
// This module may have Internal Symbols but has a DBG file...
//
OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize);
//
// Output the DBG Symbol Information
//
OutputDataToStdoutDbgSymbolInfo(m_tszPEImageDebugDirectoryDBGPath, m_dwPEImageTimeDateStamp, m_dwPEImageCheckSum, m_dwPEImageSizeOfImage);
//
// Output the DBG Internal Symbol Information
//
OutputDataToStdoutInternalSymbolInfo(m_dwDBGImageDebugDirectoryCoffSize, m_dwDBGImageDebugDirectoryFPOSize, m_dwDBGImageDebugDirectoryCVSize, m_dwDBGImageDebugDirectoryOMAPtoSRCSize, m_dwDBGImageDebugDirectoryOMAPfromSRCSize); break;
case SYMBOLS_PDB: //
// Output any internal symbols (that should be "splitsym'ed out")
//
OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize);
//
// In this case, we have a PE Image with a PDB file...
//
OutputDataToStdoutPdbSymbolInfo(m_dwPEImageDebugDirectoryPDBFormatSpecifier, m_tszPEImageDebugDirectoryPDBPath, m_dwPEImageDebugDirectoryPDBSignature, m_tszPEImageDebugDirectoryPDBGuid, m_dwPEImageDebugDirectoryPDBAge); break; } }
//
// Third, if we were to verify symbol info, display the results...
//
if (g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) { fPrintCarriageReturn = true;
switch (m_enumPEImageSymbolStatus) { case SYMBOL_INFORMATION_UNKNOWN: _tprintf(TEXT(" Module symbol information was not collected!\n")); break;
case SYMBOLS_NO: _tprintf(TEXT(" Module has NO symbols\n")); break;
case SYMBOLS_LOCAL: _tprintf(TEXT(" Module has internal symbols only! %s\n"), SourceEnabledPEImage()); OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize); break;
case SYMBOLS_DBG: case SYMBOLS_DBG_AND_PDB: switch (m_enumDBGModuleStatus) { case SYMBOL_MATCH: // Did they want the debug/symbol info for the PE image itself?
if(g_lpProgramOptions->GetMode(CProgramOptions::OutputSymbolInformationMode)) { OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize); }
if(m_tszDBGModuleFileSystemPath ) { _tprintf(TEXT(" DBG File = %s [VERIFIED] %s\n"), m_tszDBGModuleFileSystemPath, SourceEnabledDBGImage()); } if(g_lpProgramOptions->GetMode(CProgramOptions::OutputSymbolInformationMode)) { OutputDataToStdoutInternalSymbolInfo(m_dwDBGImageDebugDirectoryCoffSize, m_dwDBGImageDebugDirectoryFPOSize, m_dwDBGImageDebugDirectoryCVSize, m_dwDBGImageDebugDirectoryOMAPtoSRCSize, m_dwDBGImageDebugDirectoryOMAPfromSRCSize); } break;
case SYMBOL_NOT_FOUND: OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize); OutputDataToStdoutDbgSymbolInfo(m_tszPEImageDebugDirectoryDBGPath, m_dwPEImageTimeDateStamp, m_dwPEImageCheckSum, m_dwPEImageSizeOfImage); _tprintf(TEXT(" DBG File NOT FOUND!\n")); break; // If we didn't find the DBG file... we don't bother with the PDB...
case SYMBOL_POSSIBLE_MISMATCH: OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize);
OutputDataToStdoutDbgSymbolInfo(m_tszPEImageDebugDirectoryDBGPath, m_dwPEImageTimeDateStamp, m_dwPEImageCheckSum, m_dwPEImageSizeOfImage); OutputDataToStdoutDbgSymbolInfo(m_tszDBGModuleFileSystemPath, m_dwDBGTimeDateStamp, m_dwDBGCheckSum, m_dwDBGSizeOfImage, TEXT("DISCREPANCY"), m_dwPEImageTimeDateStamp, m_dwPEImageCheckSum, m_dwPEImageSizeOfImage); OutputDataToStdoutInternalSymbolInfo(m_dwDBGImageDebugDirectoryCoffSize, m_dwDBGImageDebugDirectoryFPOSize, m_dwDBGImageDebugDirectoryCVSize, m_dwDBGImageDebugDirectoryOMAPtoSRCSize, m_dwDBGImageDebugDirectoryOMAPfromSRCSize); break; };
//
// Intentional fall through to SYMBOLS_PDB (we might have one)
//
case SYMBOLS_PDB:
// These two cases should have a PDB file... if we can find it...
//
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) || (m_enumPEImageSymbolStatus == SYMBOLS_PDB) ) { //
// If we have a DebugDirectoryPDBPath... then display the goods...
//
if (GetDebugDirectoryPDBPath()) { switch(m_enumPDBModuleStatus) { case SYMBOL_NOT_FOUND: OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize);
// Output PDB info as appropriate
if (m_enumPEImageSymbolStatus == SYMBOLS_PDB) { OutputDataToStdoutPdbSymbolInfo(m_dwPEImageDebugDirectoryPDBFormatSpecifier, m_tszPEImageDebugDirectoryPDBPath, m_dwPEImageDebugDirectoryPDBSignature, m_tszPEImageDebugDirectoryPDBGuid, m_dwPEImageDebugDirectoryPDBAge); } else { OutputDataToStdoutPdbSymbolInfo(m_dwDBGDebugDirectoryPDBFormatSpecifier, m_tszDBGDebugDirectoryPDBPath, m_dwDBGDebugDirectoryPDBSignature, m_tszDBGDebugDirectoryPDBGuid, m_dwDBGDebugDirectoryPDBAge); }
_tprintf(TEXT(" NO PDB FILE FOUND!!\n")); break;
case SYMBOL_MATCH: // Did they want the debug/symbol info for the PE image itself?
if(m_tszPDBModuleFileSystemPath ) _tprintf(TEXT(" PDB File = %s [VERIFIED] %s\n"), m_tszPDBModuleFileSystemPath, SourceEnabledPDB());
// BUGBUG: Testing...
if (g_lpProgramOptions->GetMode(CProgramOptions::OutputSymbolInformationMode)) { if (m_dwPDBTotalBytesOfLineInformation) _tprintf(TEXT(" Module PDB Bytes of Lines = 0x%x\n"), m_dwPDBTotalBytesOfLineInformation);
if (m_dwPDBTotalBytesOfSymbolInformation) _tprintf(TEXT(" Module PDB Bytes of Symbols = 0x%x\n"), m_dwPDBTotalBytesOfSymbolInformation);
if (m_dwPDBTotalSymbolTypesRange) _tprintf(TEXT(" Module PDB Symbol Types Range = 0x%x\n"), m_dwPDBTotalSymbolTypesRange); } break;
case SYMBOL_POSSIBLE_MISMATCH: if(m_tszPDBModuleFileSystemPath ) { // Output PDB info as appropriate
if (m_enumPEImageSymbolStatus == SYMBOLS_PDB) { OutputDataToStdoutPdbSymbolInfo(m_dwPEImageDebugDirectoryPDBFormatSpecifier, m_tszPEImageDebugDirectoryPDBPath, m_dwPEImageDebugDirectoryPDBSignature, m_tszPEImageDebugDirectoryPDBGuid, m_dwPEImageDebugDirectoryPDBAge); } else { OutputDataToStdoutPdbSymbolInfo(m_dwDBGDebugDirectoryPDBFormatSpecifier, m_tszDBGDebugDirectoryPDBPath, m_dwDBGDebugDirectoryPDBSignature, m_tszDBGDebugDirectoryPDBGuid, m_dwDBGDebugDirectoryPDBAge); }
//
// Output the PDB data itself...
//
OutputDataToStdoutPdbSymbolInfo(m_dwPDBFormatSpecifier, m_tszPDBModuleFileSystemPath, m_dwPDBSignature, m_tszPDBGuid, m_dwPDBAge, TEXT("DISCREPANCY")); } break;
case SYMBOL_INVALID_FORMAT: if(m_tszPDBModuleFileSystemPath ) { // Output PDB info as appropriate
if (m_enumPEImageSymbolStatus == SYMBOLS_PDB) { OutputDataToStdoutPdbSymbolInfo(m_dwPEImageDebugDirectoryPDBFormatSpecifier, m_tszPEImageDebugDirectoryPDBPath, m_dwPEImageDebugDirectoryPDBSignature, m_tszPEImageDebugDirectoryPDBGuid, m_dwPEImageDebugDirectoryPDBAge); } else { OutputDataToStdoutPdbSymbolInfo(m_dwDBGDebugDirectoryPDBFormatSpecifier, m_tszDBGDebugDirectoryPDBPath, m_dwDBGDebugDirectoryPDBSignature, m_tszDBGDebugDirectoryPDBGuid, m_dwDBGDebugDirectoryPDBAge); } _tprintf(TEXT(" PDB File = %s [INVALID_FORMAT]\n"), m_tszPDBModuleFileSystemPath ); } break;
case SYMBOL_NO_HELPER_DLL: if(m_tszPDBModuleFileSystemPath ) { // Output PDB info as appropriate
if (m_enumPEImageSymbolStatus == SYMBOLS_PDB) { OutputDataToStdoutPdbSymbolInfo(m_dwPEImageDebugDirectoryPDBFormatSpecifier, m_tszPEImageDebugDirectoryPDBPath, m_dwPEImageDebugDirectoryPDBSignature, m_tszPEImageDebugDirectoryPDBGuid, m_dwPEImageDebugDirectoryPDBAge); } else { OutputDataToStdoutPdbSymbolInfo(m_dwDBGDebugDirectoryPDBFormatSpecifier, m_tszDBGDebugDirectoryPDBPath, m_dwDBGDebugDirectoryPDBSignature, m_tszDBGDebugDirectoryPDBGuid, m_dwDBGDebugDirectoryPDBAge); } _tprintf(TEXT(" PDB File = %s [Unable to Validate]\n"), m_tszPDBModuleFileSystemPath ); } break; } } else { OutputDataToStdoutInternalSymbolInfo(m_dwPEImageDebugDirectoryCoffSize, m_dwPEImageDebugDirectoryFPOSize, m_dwPEImageDebugDirectoryCVSize, m_dwPEImageDebugDirectoryOMAPtoSRCSize, m_dwPEImageDebugDirectoryOMAPfromSRCSize); OutputDataToStdoutDbgSymbolInfo(m_tszPEImageDebugDirectoryDBGPath, m_dwPEImageTimeDateStamp, m_dwPEImageCheckSum, m_dwPEImageSizeOfImage); _tprintf(TEXT(" Module has PDB File\n")); _tprintf(TEXT(" Module Pointer to PDB = [UNKNOWN] (Could not find in PE Image)\n")); }; }; } }
// Should we tack an extra carriage-return?
if ( fPrintCarriageReturn ) _tprintf(TEXT("\n"));
return true; }
LPTSTR CModuleInfo::SymbolModuleStatusString(enum SymbolModuleStatus enumModuleStatus) { LPTSTR tszStringPointer = NULL;
// Output the Symbol Information for the PE module
switch (enumModuleStatus) { case SYMBOL_NOT_FOUND: tszStringPointer = TEXT("SYMBOL_NOT_FOUND"); break;
case SYMBOL_MATCH: tszStringPointer = TEXT("SYMBOL_MATCH"); break;
case SYMBOL_POSSIBLE_MISMATCH: tszStringPointer = TEXT("SYMBOL_POSSIBLE_MISMATCH"); break;
case SYMBOL_INVALID_FORMAT: tszStringPointer = TEXT("SYMBOL_INVALID_FORMAT"); break;
case SYMBOL_NO_HELPER_DLL: tszStringPointer = TEXT("SYMBOL_NO_HELPER_DLL"); break;
default: tszStringPointer = NULL; }
return tszStringPointer; }
LPTSTR CModuleInfo::SymbolInformationString(enum SymbolInformationForPEImage enumSymbolInformationForPEImage) { LPTSTR tszStringPointer = NULL;
// Ouput the Symbol Information for the PE module
switch (enumSymbolInformationForPEImage) { case SYMBOL_INFORMATION_UNKNOWN: tszStringPointer = TEXT("SYMBOL_INFORMATION_UNKNOWN"); break;
case SYMBOLS_NO: tszStringPointer = TEXT("SYMBOLS_NO"); break;
case SYMBOLS_LOCAL: tszStringPointer = TEXT("SYMBOLS_LOCAL"); break; case SYMBOLS_DBG: tszStringPointer = TEXT("SYMBOLS_DBG"); break; case SYMBOLS_DBG_AND_PDB: tszStringPointer = TEXT("SYMBOLS_DBG_AND_PDB"); break;
case SYMBOLS_PDB: tszStringPointer = TEXT("SYMBOLS_PDB"); break;
default: tszStringPointer = NULL; }
return tszStringPointer; }
bool CModuleInfo::GetModuleInfoFromPEImage(LPTSTR tszModulePath, const bool fDmpFile, const DWORD64 dw64ModAddress) { HANDLE hModuleHandle = INVALID_HANDLE_VALUE; bool fReturn = false;
// PE File Version
TCHAR tszFileName[_MAX_FNAME]; TCHAR tszFileExtension[_MAX_EXT]; DWORD dwVersionInfoSize = 0; DWORD dwHandle = 0; LPBYTE lpBuffer = NULL; VS_FIXEDFILEINFO * lpFixedFileInfo = NULL; DWORD * pdwLang = NULL; unsigned int cbLang = 0; unsigned int uint = 0; TCHAR achName[256]; LPTSTR psz = NULL; // PE Image Locals
IMAGE_DOS_HEADER ImageDosHeader; DWORD dwMagic; IMAGE_FILE_HEADER ImageFileHeader; IMAGE_DATA_DIRECTORY DebugImageDataDirectory; IMAGE_OPTIONAL_HEADER64 ImageOptionalHeader64; PIMAGE_OPTIONAL_HEADER32 lpImageOptionalHeader32 = NULL; PIMAGE_SECTION_HEADER lpImageSectionHeader = NULL; ULONG OffsetImageDebugDirectory;
unsigned long ul; // bool fDBGSymbolStrippedFromImage = false;
bool fCodeViewSectionFound = false; // unsigned long NumDebugDirs;
// Save the base address so that all DmpFile reads become relative to this...
m_dw64BaseAddress = dw64ModAddress;
// We don't know anything about symbols yet... (we may not when we exit if the user
// didn't ask us to look...)
m_enumPEImageSymbolStatus = SYMBOL_INFORMATION_UNKNOWN;
if (!fDmpFile) { // Copy the Module Name to the ModuleInfo Object...
_tsplitpath(m_tszPEImageModuleFileSystemPath, NULL, NULL, tszFileName, tszFileExtension);
if (tszFileName && tszFileExtension) { // Compose the module name...
m_tszPEImageModuleName = new TCHAR[_tcsclen(tszFileName)+_tcsclen(tszFileExtension)+1]; if (!m_tszPEImageModuleName) goto cleanup;
_tcscpy(m_tszPEImageModuleName, tszFileName); _tcscat(m_tszPEImageModuleName, tszFileExtension); }
// Let's open the file... we use this for both Version Info and Symbol Info
// gathering...
hModuleHandle = CreateFile( tszModulePath, GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
if (hModuleHandle == INVALID_HANDLE_VALUE) { goto cleanup; } } // Did the user request version information?
if (g_lpProgramOptions->GetMode(CProgramOptions::CollectVersionInfoMode) && !fDmpFile) {
// Now, get CheckSum, TimeDateStamp, and other Image properties...
BY_HANDLE_FILE_INFORMATION lpFileInformation;
if ( GetFileInformationByHandle(hModuleHandle, &lpFileInformation) ) { // Get the file size...
m_dwPEImageFileSize = lpFileInformation.nFileSizeLow;
m_ftPEImageFileTimeDateStamp = lpFileInformation.ftLastWriteTime; }
// First, is there any FileVersionInfo at all?
dwVersionInfoSize = GetFileVersionInfoSize(m_tszPEImageModuleFileSystemPath, &dwHandle);
if (dwVersionInfoSize != 0) { // Allocate a buffer to read into...
lpBuffer = new BYTE[dwVersionInfoSize]; if (lpBuffer) { // Okay... query to get this version info...
if (GetFileVersionInfo(m_tszPEImageModuleFileSystemPath, dwHandle, dwVersionInfoSize, lpBuffer)) { // Well, we returned the buffer...
m_fPEImageFileVersionInfo = true;
// Get the VS_FIXEDFILEINFO structure which carries version info...
if (VerQueryValue(lpBuffer, TEXT("\\"), (LPVOID *)&lpFixedFileInfo, &uint)) { m_dwPEImageFileVersionMS = lpFixedFileInfo->dwFileVersionMS; m_dwPEImageFileVersionLS = lpFixedFileInfo->dwFileVersionLS;
m_dwPEImageProductVersionMS = lpFixedFileInfo->dwProductVersionMS; m_dwPEImageProductVersionLS = lpFixedFileInfo->dwProductVersionLS;
// Okay, before we go allocating a version string... let's ensure
// we actually have a version number worth reporting...
if ( m_dwPEImageFileVersionMS || m_dwPEImageFileVersionLS ) { m_tszPEImageFileVersionString = new TCHAR[1+5+1+5+1+5+1+5+1+1]; // Format will be (#.#:#.#) where each # is a word
if (m_tszPEImageFileVersionString) // Okay, blitz the data into place...
_stprintf( m_tszPEImageFileVersionString, TEXT("(%d.%d:%d.%d)"), HIWORD(m_dwPEImageFileVersionMS), LOWORD(m_dwPEImageFileVersionMS), HIWORD(m_dwPEImageFileVersionLS), LOWORD(m_dwPEImageFileVersionLS) ); }
// Okay, before we go allocating a version string... let's ensure
// we actually have a version number worth reporting...
if ( m_dwPEImageProductVersionMS || m_dwPEImageProductVersionLS ) { m_tszPEImageProductVersionString = new TCHAR[1+5+1+5+1+5+1+5+1+1]; // Format will be (#.#:#.#) where each # is a word
if (m_tszPEImageProductVersionString) // Okay, blitz the data into place...
_stprintf( m_tszPEImageProductVersionString, TEXT("(%d.%d:%d.%d)"), HIWORD(m_dwPEImageFileVersionMS), LOWORD(m_dwPEImageFileVersionMS), HIWORD(m_dwPEImageProductVersionLS), LOWORD(m_dwPEImageProductVersionLS) ); }
}
// Get the language and codepage information for the CompanyName and
// FileDescription string table resources...
if (VerQueryValue(lpBuffer, TEXT("\\VarFileInfo\\Translation"), (LPVOID *)&pdwLang, &cbLang)) { _stprintf(achName,TEXT("\\StringFileInfo\\%04x%04x\\CompanyName"), LOWORD(*pdwLang), HIWORD(*pdwLang));
if (VerQueryValue(lpBuffer, achName, (LPVOID *)&psz, &uint)) { // Cool, we have a Company Name...
if (psz && *psz) { m_tszPEImageFileVersionCompanyName = new TCHAR[_tcslen(psz)+1];
if (m_tszPEImageFileVersionCompanyName) _tcscpy(m_tszPEImageFileVersionCompanyName, psz); }
}
_stprintf(achName,TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"), LOWORD(*pdwLang), HIWORD(*pdwLang));
if (VerQueryValue(lpBuffer, achName, (LPVOID *)&psz, &uint)) { // Cool, we have a Company Name...
if (psz && *psz) { m_tszPEImageFileVersionDescription = new TCHAR[_tcslen(psz)+1]; if (m_tszPEImageFileVersionDescription) _tcscpy(m_tszPEImageFileVersionDescription, psz); }
}
// If we still don't have a proper file version... just try
// and grab the FileVersion string and hope it's good...
if ( !m_dwPEImageFileVersionMS && !m_dwPEImageFileVersionLS ) { _stprintf(achName,TEXT("\\StringFileInfo\\%04x%04x\\FileVersion"), LOWORD(*pdwLang), HIWORD(*pdwLang));
if (VerQueryValue(lpBuffer, achName, (LPVOID *)&psz, &uint)) { // Cool, we have a FileVersion String...
if (psz && *psz) { m_tszPEImageFileVersionString = new TCHAR[_tcslen(psz)+1]; if (m_tszPEImageFileVersionString) _tcscpy(m_tszPEImageFileVersionString, psz); } } } // If we still don't have a proper file version... just try
// and grab the ProductVersion string and hope it's good...
if ( !m_dwPEImageProductVersionMS && !m_dwPEImageProductVersionLS ) { _stprintf(achName,TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), LOWORD(*pdwLang), HIWORD(*pdwLang));
if (VerQueryValue(lpBuffer, achName, (LPVOID *)&psz, &uint)) { // Cool, we have a FileVersion String...
if (psz && *psz) { m_tszPEImageProductVersionString = new TCHAR[_tcslen(psz)+1]; if (m_tszPEImageProductVersionString) _tcscpy(m_tszPEImageProductVersionString, psz); } } } } } } } } // If the user chose not to collect or verify symbol information, then bail out of here...
if (!g_lpProgramOptions->GetMode(CProgramOptions::OutputSymbolInformationMode) && !g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) { fReturn = true; goto cleanup; } // Start at the top of the image...
SetReadPointer(fDmpFile, hModuleHandle, 0, FILE_BEGIN);
// Read in a dos exe header
if ( !DoRead(fDmpFile, hModuleHandle, &ImageDosHeader, sizeof(ImageDosHeader) ) ) goto cleanup; if (ImageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) { // No sense in going further since we're expecting a PE image file...
goto cleanup; }
if (ImageDosHeader.e_lfanew == 0) { // This is a DOS program... very odd...
goto cleanup; }
// Great, we have a valid DOS_SIGNATURE... now read in the NT_SIGNATURE?!
SetReadPointer(fDmpFile, hModuleHandle, ImageDosHeader.e_lfanew, FILE_BEGIN);
// Read in a DWORD to see if this is an image worth looking at...
if ( !DoRead(fDmpFile, hModuleHandle, &dwMagic, sizeof(DWORD)) ) goto cleanup;
// Probe to see if this is a valid image... we only handle NT images (PE/PE64)
if (dwMagic != IMAGE_NT_SIGNATURE) goto cleanup;
// Now read the ImageFileHeader...
if ( !DoRead(fDmpFile, hModuleHandle, &ImageFileHeader, sizeof(IMAGE_FILE_HEADER)) ) goto cleanup;
// Okay, we have a PE Image!!!!
// Save the Time Date Stamp
m_dwPEImageTimeDateStamp = ImageFileHeader.TimeDateStamp;
// Save the Machine Architecture
m_wPEImageMachineArchitecture = ImageFileHeader.Machine;
// Save the PE Image Characteristics
m_wCharacteristics = ImageFileHeader.Characteristics;
// The OptionalHeader is necessary to get the SizeOfImage and to find the DebugDirectoryInfo.
if (ImageFileHeader.SizeOfOptionalHeader == 0) goto cleanup;
// Now... the size of the Optional Header is DIFFERENT between PE32 and PE64...
// The only items we need from the option header are:
//
// ULONG CheckSum
// ULONG SizeOfImage
// IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
//
// We'll read as a PE64 (since it's larger) and cast to PE32 if required...
if ( !DoRead(fDmpFile, hModuleHandle, &ImageOptionalHeader64, sizeof(IMAGE_OPTIONAL_HEADER64)) ) goto cleanup;
switch (ImageOptionalHeader64.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
m_enumPEImageType = PE32;
lpImageOptionalHeader32 = (PIMAGE_OPTIONAL_HEADER32)&ImageOptionalHeader64;
// Save the Checksum info (though it's not very relavent to identifying symbols)
m_dwPEImageCheckSum = lpImageOptionalHeader32->CheckSum;
// Save the SizeOfImage info...
m_dwPEImageSizeOfImage = lpImageOptionalHeader32->SizeOfImage;
// Get the preferred load address (but only if we don't already have one)
if (m_dw64BaseAddress != 0) { m_dw64BaseAddress = lpImageOptionalHeader32->ImageBase; } DebugImageDataDirectory.Size = lpImageOptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; DebugImageDataDirectory.VirtualAddress = lpImageOptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
m_enumPEImageType = PE64;
// Save the Checksum info (though it's not very relavent to identifying symbols)
m_dwPEImageCheckSum = ImageOptionalHeader64.CheckSum;
// Save the SizeOfImage info...
m_dwPEImageSizeOfImage = ImageOptionalHeader64.SizeOfImage;
// Get the preferred load address (but only if we don't already have one)
if (m_dw64BaseAddress != 0) { m_dw64BaseAddress = ImageOptionalHeader64.ImageBase; } DebugImageDataDirectory.Size = ImageOptionalHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; DebugImageDataDirectory.VirtualAddress = ImageOptionalHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; break;
default: goto cleanup;
}
// Let's quickly look to see if there is even a Debug Directory in the PE image!
if (DebugImageDataDirectory.Size == 0) { m_enumPEImageSymbolStatus = SYMBOLS_NO; fReturn = true; goto cleanup; // No Debug Directory found...
}
// Now, go ahead and allocate the storage...
lpImageSectionHeader = (PIMAGE_SECTION_HEADER) new IMAGE_SECTION_HEADER[ImageFileHeader.NumberOfSections];
if (lpImageSectionHeader == NULL) goto cleanup;
// Set the pointer to the start of the Section Headers... (we may need to back up if we read
// PE64 Optional Headers and this is a PE32 image...
if (m_enumPEImageType == PE32) { SetReadPointer(fDmpFile, hModuleHandle, (LONG)(sizeof(IMAGE_OPTIONAL_HEADER32)-sizeof(IMAGE_OPTIONAL_HEADER64)), FILE_CURRENT); }
// Read in the Section Headers...
if (!DoRead(fDmpFile, hModuleHandle, lpImageSectionHeader, (ImageFileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))) goto cleanup;
// Let's walk through these Section Headers...
// For PE images, walk the section headers looking for the
// one that's got the debug directory.
for (ul=0; ul < ImageFileHeader.NumberOfSections; ul++) {
// If the virtual address for the Debug Entry falls into this section header, then we've found it!
if ( DebugImageDataDirectory.VirtualAddress >= lpImageSectionHeader[ul].VirtualAddress && DebugImageDataDirectory.VirtualAddress < lpImageSectionHeader[ul].VirtualAddress + lpImageSectionHeader[ul].SizeOfRawData ) { break; } }
// Assuming we haven't exhausted the list of section headers, we should have the debug directory now.
if (ul >= ImageFileHeader.NumberOfSections) { m_enumPEImageSymbolStatus = SYMBOLS_NO; fReturn = true; goto cleanup; // No Debug Directory found...
}
// For a DmpFile, the address is based on the Section Header's Virtual Address, not PointerToRawData
if (fDmpFile) { OffsetImageDebugDirectory = ((DebugImageDataDirectory.VirtualAddress - lpImageSectionHeader[ul].VirtualAddress) + lpImageSectionHeader[ul].VirtualAddress);
} else { OffsetImageDebugDirectory = ((DebugImageDataDirectory.VirtualAddress - lpImageSectionHeader[ul].VirtualAddress) + lpImageSectionHeader[ul].PointerToRawData); } // NumDebugDirs = DebugImageDataDirectory.Size / sizeof(IMAGE_DEBUG_DIRECTORY);
if (!ProcessDebugDirectory(true, fDmpFile, hModuleHandle, DebugImageDataDirectory.Size, OffsetImageDebugDirectory)) goto cleanup;
fReturn = true;
// fDBGSymbolStrippedFromImage = (ImageFileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) == IMAGE_FILE_DEBUG_STRIPPED;
// fIMAGE_FILE_LOCAL_SYMS_STRIPPED = (ImageFileHeader.Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED) == IMAGE_FILE_LOCAL_SYMS_STRIPPED;
/**
** ** What type of symbols were found to be present... ** ** NO SYMBOLS ** ============= ** No Debug Directory ** NO Debug information stripped ** Symbols stripped ** ** LOCAL SYMBOLS ** ============= ** Debug Directory ** NO Debug information stripped ** NO Symbols stripped ** ** PDB SYMBOL ** ============= ** Debug Directory ** NO Debug information stripped ** Symbols stripped ** ** DBG SYMBOL ** ============= ** Debug Directory (assumed) ** BOTH - YES/NO Debug information stripped ** NO Symbols stripped ** **/
if ((ImageFileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) == IMAGE_FILE_DEBUG_STRIPPED) { // Debug Information Stripped! (A DBG file is assumed)
m_enumPEImageSymbolStatus = SYMBOLS_DBG; } else { // Debug Information NOT stripped! (Either a PDB exists, or symbols are local, or both...)
if ( ( m_tszPEImageDebugDirectoryPDBPath) || (fDmpFile && fCodeViewSectionFound) ) { // If we find PDB data, a PDB file is assumed...
// Starting with LINK.EXE 6.2 and higher, we'll find PDB data in USER.DMP files....
m_enumPEImageSymbolStatus = SYMBOLS_PDB; } else { // Symbols NOT stripped (Symbols appear to be local to the PE Image)
m_enumPEImageSymbolStatus = SYMBOLS_LOCAL; } }
cleanup:
if (hModuleHandle != INVALID_HANDLE_VALUE) CloseHandle(hModuleHandle);
if (lpImageSectionHeader) delete [] lpImageSectionHeader;
return fReturn;
}
bool CModuleInfo::GetModuleInfoFromCSVFile(LPTSTR tszModulePath) { TCHAR tszFileName[_MAX_FNAME]; TCHAR tszFileExtension[_MAX_EXT];
// Copy the Module Name to the ModuleInfo Object...
_tsplitpath(tszModulePath, NULL, NULL, tszFileName, tszFileExtension);
if (tszFileName && tszFileExtension) { // Compose the module name...
m_tszPEImageModuleName = new TCHAR[_tcsclen(tszFileName)+_tcsclen(tszFileExtension)+1]; if (!m_tszPEImageModuleName) return false;
_tcscpy(m_tszPEImageModuleName, tszFileName); _tcscat(m_tszPEImageModuleName, tszFileExtension); }
// Get the symbol status
enum {BUFFER_SIZE = 32}; char szSymbolStatus[BUFFER_SIZE];
m_lpInputFile->ReadString(szSymbolStatus, BUFFER_SIZE);
// Get the enum value for this string...
m_enumPEImageSymbolStatus = SymbolInformation(szSymbolStatus); // Reset the symbol status if it is DBG/PDB (that may have
// applied on the other machine where the data was captured,
// but on this machine we'll have to find the DBG file
// first, then see if a PDB file exists...
if (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) m_enumPEImageSymbolStatus = SYMBOLS_DBG;
m_lpInputFile->ReadDWORD(&m_dwPEImageCheckSum);
m_lpInputFile->ReadDWORD((LPDWORD)&m_dwPEImageTimeDateStamp);
// Skip the time/date string...
m_lpInputFile->ReadString();
m_lpInputFile->ReadDWORD(&m_dwPEImageSizeOfImage);
char szBuffer[_MAX_PATH+1];
DWORD dwStringLength;
// Read in the DBG Module Path
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good path... allocate space for it...
m_tszPEImageDebugDirectoryDBGPath = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if (!m_tszPEImageDebugDirectoryDBGPath) return false; }
// Read in the PDB Module Path
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good path... allocate space for it...
m_tszPEImageDebugDirectoryPDBPath = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if (!m_tszPEImageDebugDirectoryPDBPath) return false; // Failure allocating...
}
m_lpInputFile->ReadDWORD(&m_dwPEImageDebugDirectoryPDBSignature); m_lpInputFile->ReadDWORD(&m_dwPEImageDebugDirectoryPDBAge);
// Read in the Product Version String
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good version... allocate space for it...
m_tszPEImageProductVersionString = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if (!m_tszPEImageProductVersionString ) return false; // Failure allocating...
}
// Read in the File Version String
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good version... allocate space for it...
m_tszPEImageFileVersionString = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if (!m_tszPEImageFileVersionString ) return false; // Failure allocating...
} // Read in the File Version Company String
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good version... allocate space for it...
m_tszPEImageFileVersionCompanyName = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if ( !m_tszPEImageFileVersionCompanyName ) return false; // Failure allocating...
} // Read in the File Version Description String
dwStringLength = m_lpInputFile->ReadString(szBuffer, _MAX_PATH+1);
if (dwStringLength) { // Okay, if we found a good version... allocate space for it...
m_tszPEImageFileVersionDescription = CUtilityFunctions::CopyAnsiStringToTSTR(szBuffer);
if ( !m_tszPEImageFileVersionDescription ) return false; // Failure allocating...
} m_lpInputFile->ReadDWORD(&m_dwPEImageFileSize); m_lpInputFile->ReadDWORD(&m_ftPEImageFileTimeDateStamp.dwHighDateTime);
m_lpInputFile->ReadDWORD(&m_ftPEImageFileTimeDateStamp.dwLowDateTime);
// Okay... read to the start of the next line...
m_lpInputFile->ReadFileLine();
return true; }
// This function is for ANSI strings explicitly because we only need to map these from
// ANSI strings read from a file, to an enum...
CModuleInfo::SymbolInformationForPEImage CModuleInfo::SymbolInformation(LPSTR szSymbolInformationString) { if (0 == _stricmp(szSymbolInformationString, "SYMBOLS_DBG")) return SYMBOLS_DBG;
if (0 == _stricmp(szSymbolInformationString, "SYMBOLS_PDB")) return SYMBOLS_PDB;
if (0 == _stricmp(szSymbolInformationString, "SYMBOLS_DBG_AND_PDB")) return SYMBOLS_DBG_AND_PDB;
if (0 == _stricmp(szSymbolInformationString, "SYMBOLS_NO")) return SYMBOLS_NO;
if (0 == _stricmp(szSymbolInformationString, "SYMBOLS_LOCAL")) return SYMBOLS_LOCAL;
if (0 == _stricmp(szSymbolInformationString, "SYMBOL_INFORMATION_UNKNOWN")) return SYMBOL_INFORMATION_UNKNOWN;
return SYMBOL_INFORMATION_UNKNOWN; }
bool CModuleInfo::OutputFileTime(FILETIME ftFileTime, LPTSTR tszFileTime, int iFileTimeBufferSize) {
// Thu Oct 08 15:37:22 1998
FILETIME ftLocalFileTime; SYSTEMTIME lpSystemTime; int cch = 0, cch2 = 0;
// Let's convert this to a local file time first...
if (!FileTimeToLocalFileTime(&ftFileTime, &ftLocalFileTime)) return false;
FileTimeToSystemTime( &ftLocalFileTime, &lpSystemTime ); cch = GetDateFormat( LOCALE_USER_DEFAULT, 0, &lpSystemTime, TEXT("ddd MMM dd"), tszFileTime, iFileTimeBufferSize );
if (!cch) return false;
// Let's keep going...
tszFileTime[cch-1] = TEXT(' ');
//
// Get time and format to characters
//
cch2 = GetTimeFormat( LOCALE_USER_DEFAULT, NULL, &lpSystemTime, TEXT("HH':'mm':'ss"), tszFileTime + cch, iFileTimeBufferSize - cch );
// Let's keep going... we have to tack on the year...
tszFileTime[cch + cch2 - 1] = TEXT(' ');
GetDateFormat( LOCALE_USER_DEFAULT, 0, &lpSystemTime, TEXT("yyyy"), tszFileTime + cch + cch2, iFileTimeBufferSize - cch - cch2); return true; }
bool CModuleInfo::SetModulePath(LPTSTR tszModulePath) { // Copy the Module Path to the ModuleInfo Object...
if (!tszModulePath) { return false; }
if (m_tszPEImageModuleFileSystemPath) delete [] m_tszPEImageModuleFileSystemPath;
m_tszPEImageModuleFileSystemPath = new TCHAR[(_tcsclen(tszModulePath)+1)];
if (!m_tszPEImageModuleFileSystemPath) return false;
_tcscpy(m_tszPEImageModuleFileSystemPath, tszModulePath); return true; }
bool CModuleInfo::HandlePDBOpenValidateReturn(PDB * lpPdb, LPTSTR tszPDBLocal, EC ec) { char szPDBLocal[_MAX_PATH+1];
// What we do now is based on the return from PDBOpenValidate()
switch (ec) { case EC_NOT_FOUND: break; // Not here, go back for more...
case EC_OK: // Yee haa... save the data for sure...
m_enumPDBModuleStatus = SYMBOL_MATCH;
// On a perfect match, these must be equal...
m_dwPDBSignature = m_dwPEImageDebugDirectoryPDBSignature; m_dwPDBAge = m_dwPEImageDebugDirectoryPDBAge;
// We're saving this... delete an existing one if found...
if (m_tszPDBModuleFileSystemPath) { delete [] m_tszPDBModuleFileSystemPath; m_tszPDBModuleFileSystemPath = NULL; }
m_tszPDBModuleFileSystemPath = CUtilityFunctions::CopyString(tszPDBLocal);
_tcscpy(m_tszPDBModuleFileSystemPath, tszPDBLocal);
if (!m_tszPDBModuleFileSystemPath) return false;
// Now that we're done verifying the module... do we save the symbol in
// our tree?
if ( g_lpProgramOptions->GetMode(CProgramOptions::BuildSymbolTreeMode) ) { // Yup...
CUtilityFunctions::CopySymbolFileToSymbolTree(m_tszPEImageModuleName, &m_tszPDBModuleFileSystemPath, g_lpProgramOptions->GetSymbolTreeToBuild()); }
//
// Is there any Private Information (Source Enabled?)
//
if (!ProcessPDBSourceInfo(lpPdb)) return false; break;
case EC_FORMAT: // This deserves an error of its own...
m_enumPDBModuleStatus = SYMBOL_INVALID_FORMAT;
// We'll only save this if we don't already have one...
if (m_tszPDBModuleFileSystemPath == NULL) { m_tszPDBModuleFileSystemPath = CUtilityFunctions::CopyString(tszPDBLocal);
if (!m_tszPDBModuleFileSystemPath) return false; } break; case EC_INVALID_SIG: case EC_INVALID_AGE: // We'll save the location only for interests sake (and only if we
// don't have a PDB path already...
// Maybe we need to be more granular?
m_enumPDBModuleStatus = SYMBOL_POSSIBLE_MISMATCH;
// We'll only save this if we don't already have one...
if (m_tszPDBModuleFileSystemPath == NULL) { m_tszPDBModuleFileSystemPath = CUtilityFunctions::CopyString(tszPDBLocal);
if (!m_tszPDBModuleFileSystemPath) return false; }
// Okay, we know that we had a bad match, but we don't know why... let's
// go ahead and figure it out...
EC ec; char szError[cbErrMax]; PDB *pPdb;
CUtilityFunctions::CopyTSTRStringToAnsi(tszPDBLocal, szPDBLocal, _MAX_PATH+1);
if ( PDBOpen(szPDBLocal, pdbRead, m_dwPEImageDebugDirectoryPDBSignature, &ec, szError, &pPdb) ) { // We opened it...
// Get the goods...
m_dwPDBFormatSpecifier = sigNB10; // TEMPORARY ASSUMPTION!!!
m_dwPDBSignature = PDBQuerySignature(pPdb); m_dwPDBAge = PDBQueryAge(pPdb); PDBClose(pPdb); } break;
case EC_USAGE: m_enumPDBModuleStatus = SYMBOL_NO_HELPER_DLL;
// We'll only save this if we don't already have one...
if (m_tszPDBModuleFileSystemPath == NULL) { m_tszPDBModuleFileSystemPath = CUtilityFunctions::CopyString(tszPDBLocal);
if (!m_tszPDBModuleFileSystemPath) return false; } break;
default: break; }
return true; }
ULONG CModuleInfo::SetReadPointer(bool fDmpFile, HANDLE hModuleHandle, LONG cbOffset, int iFrom) { if (fDmpFile) { switch( iFrom ) { case FILE_BEGIN: m_dwCurrentReadPosition = cbOffset; break;
case FILE_CURRENT: m_dwCurrentReadPosition += cbOffset; break;
default: break; } } else { m_dwCurrentReadPosition = SetFilePointer(hModuleHandle, cbOffset, NULL, iFrom); }
return m_dwCurrentReadPosition; }
bool CModuleInfo::DoRead(bool fDmpFile, HANDLE hModuleHandle, LPVOID lpBuffer, DWORD cbNumberOfBytesToRead) { DWORD cbActuallyRead; bool fReturn = false;
if (fDmpFile) { if (m_lpDmpFile) { HRESULT Hr;
if (FAILED(Hr = m_lpDmpFile->m_pIDebugDataSpaces->ReadVirtual(m_dw64BaseAddress+(DWORD64)m_dwCurrentReadPosition, lpBuffer, cbNumberOfBytesToRead, &cbActuallyRead))) { goto exit; }
if (cbActuallyRead != cbNumberOfBytesToRead) { goto exit; }
} else { goto exit; }
m_dwCurrentReadPosition += cbActuallyRead;
} else if ( (ReadFile(hModuleHandle, lpBuffer, cbNumberOfBytesToRead, &cbActuallyRead, NULL) == 0) || (cbNumberOfBytesToRead != cbActuallyRead) ) { goto exit; }
fReturn = true;
exit: return fReturn; }
bool CModuleInfo::SetDebugDirectoryDBGPath(LPTSTR tszNewDebugDirectoryDBGPath) { if (m_tszPEImageDebugDirectoryDBGPath) delete [] m_tszPEImageDebugDirectoryDBGPath;
m_tszPEImageDebugDirectoryDBGPath = CUtilityFunctions::CopyString(tszNewDebugDirectoryDBGPath);
return true; }
bool CModuleInfo::SetPEDebugDirectoryPDBPath(LPTSTR tszNewDebugDirectoryPDBPath) { if (m_tszPEImageDebugDirectoryPDBPath) delete [] m_tszPEImageDebugDirectoryPDBPath;
m_tszPEImageDebugDirectoryPDBPath = CUtilityFunctions::CopyString(tszNewDebugDirectoryPDBPath);
return true; }
bool CModuleInfo::SetPEImageModulePath(LPTSTR tszNewPEImageModulePath) { if (m_tszPEImageModuleFileSystemPath) delete [] m_tszPEImageModuleFileSystemPath;
m_tszPEImageModuleFileSystemPath = CUtilityFunctions::CopyString(tszNewPEImageModulePath);
_tcsupr(m_tszPEImageModuleFileSystemPath);
return true; }
bool CModuleInfo::SetPEImageModuleName(LPTSTR tszNewModuleName) { if (m_tszPEImageModuleName) delete [] m_tszPEImageModuleName;
m_tszPEImageModuleName = CUtilityFunctions::CopyString(tszNewModuleName);
_tcsupr(m_tszPEImageModuleName);
return true; }
// Evaluate whether we've found the symbolic information for this module
// that the user is looking for.
bool CModuleInfo::GoodSymbolNotFound() { bool fBadSymbol = true;
// Well, we evaluate success based on the type of symbol we're looking for
// and whether it was successfully found.
switch (GetPESymbolInformation()) { // This is bad... consider this fatal...
case SYMBOL_INFORMATION_UNKNOWN: break;
// Is this bad? I think so... but if you inherit a module as an import should you
// be punished for the ills of another? Hmm.... For now we'll say it's okay...
case SYMBOLS_NO: fBadSymbol = false; break;
// While this is wasteful, we have symbolic info... so that's cool
case SYMBOLS_LOCAL: fBadSymbol = false; break;
case SYMBOLS_DBG: fBadSymbol = SYMBOL_MATCH == GetDBGSymbolModuleStatus(); break;
case SYMBOLS_DBG_AND_PDB: fBadSymbol = (SYMBOL_MATCH == GetDBGSymbolModuleStatus()) && (SYMBOL_MATCH == GetPDBSymbolModuleStatus()); break; case SYMBOLS_PDB: fBadSymbol = SYMBOL_MATCH == GetPDBSymbolModuleStatus(); break;
default: break; } return fBadSymbol; }
//
// Process the DebugDirectory data for a PE image (or a DBG file)
//
bool CModuleInfo::ProcessDebugDirectory(const bool fPEImage, const bool fDmpFile, const HANDLE hModuleHandle, unsigned int iDebugDirectorySize, ULONG OffsetImageDebugDirectory) { unsigned int iNumberOfDebugDirectoryEntries = iDebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY); //
// Let's loop through the debug directories and collect the relavent info...
//
while (iNumberOfDebugDirectoryEntries--) { IMAGE_DEBUG_DIRECTORY ImageDebugDirectory;
// Set the pointer to the DebugDirectories entry
SetReadPointer(fDmpFile, hModuleHandle, OffsetImageDebugDirectory, FILE_BEGIN);
// Read the DebugDirectoryImage
if (!DoRead(fDmpFile, hModuleHandle, &ImageDebugDirectory, sizeof(IMAGE_DEBUG_DIRECTORY))) goto cleanup;
//
// Processing of the Debug Directory is dependent on the type
//
switch (ImageDebugDirectory.Type) { //
// This is our preferred debug format as it offers full source level debugging (typically)
//
case IMAGE_DEBUG_TYPE_CODEVIEW: ProcessDebugTypeCVDirectoryEntry(fPEImage, fDmpFile, hModuleHandle, &ImageDebugDirectory); break;
//
// COFF symbols are okay... CV is better :)
//
case IMAGE_DEBUG_TYPE_COFF: ProcessDebugTypeCoffDirectoryEntry(fPEImage, &ImageDebugDirectory); break; //
// MISC implies that a DBG file is created...
//
case IMAGE_DEBUG_TYPE_MISC: ProcessDebugTypeMiscDirectoryEntry(fPEImage, fDmpFile, hModuleHandle, &ImageDebugDirectory); break; //
// FPO info is important for working with functions with FPO
//
case IMAGE_DEBUG_TYPE_FPO: ProcessDebugTypeFPODirectoryEntry(fPEImage, &ImageDebugDirectory); break; case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: ProcessDebugTypeOMAPDirectoryEntry(fPEImage, &ImageDebugDirectory); break; case IMAGE_DEBUG_TYPE_UNKNOWN: case IMAGE_DEBUG_TYPE_EXCEPTION: case IMAGE_DEBUG_TYPE_FIXUP: case IMAGE_DEBUG_TYPE_BORLAND: case IMAGE_DEBUG_TYPE_RESERVED10: case IMAGE_DEBUG_TYPE_CLSID: break;
default: break; }
OffsetImageDebugDirectory += sizeof(IMAGE_DEBUG_DIRECTORY); } cleanup:
return true; }
bool CModuleInfo::ProcessDebugTypeMiscDirectoryEntry(const bool fPEImage, const bool fDmpFile, const HANDLE hModuleHandle, const PIMAGE_DEBUG_DIRECTORY lpImageDebugDirectory) { bool fReturnValue = false; PIMAGE_DEBUG_MISC lpImageDebugMisc = NULL, lpCurrentImageDebugMiscPointer = NULL; ULONG OffsetImageDebugDirectory = NULL; unsigned long ulSizeOfMiscDirectoryEntry = lpImageDebugDirectory->SizeOfData;
//
// DBG files tend to store the EXE name here... not too useful for now...
//
if (!fPEImage) { fReturnValue = true; goto cleanup; }
//
// Allocate storage for the MISC data...
//
lpImageDebugMisc = (PIMAGE_DEBUG_MISC) new BYTE[ulSizeOfMiscDirectoryEntry];
if (lpImageDebugMisc == NULL) goto cleanup; // Calculate the location/size so we can load it.
if (fDmpFile) { OffsetImageDebugDirectory = lpImageDebugDirectory->AddressOfRawData; } else { OffsetImageDebugDirectory = lpImageDebugDirectory->PointerToRawData; }
// Advance to the location of the Debug Info
SetReadPointer(fDmpFile, hModuleHandle, OffsetImageDebugDirectory, FILE_BEGIN);
// Read the data...
if (!DoRead(fDmpFile, hModuleHandle, lpImageDebugMisc, ulSizeOfMiscDirectoryEntry)) goto cleanup;
// Set our pointer to the start of our data...
lpCurrentImageDebugMiscPointer = lpImageDebugMisc; //
// The logic of this routine will skip past bad sections of the MISC datastream...
//
while(ulSizeOfMiscDirectoryEntry > 0) { //
// Hopefully we have a string here...
//
if (lpCurrentImageDebugMiscPointer->DataType == IMAGE_DEBUG_MISC_EXENAME) { LPSTR lpszExeName;
lpszExeName = (LPSTR)&lpCurrentImageDebugMiscPointer->Data[ 0 ]; // Save off the DBG Path...
if (m_tszPEImageDebugDirectoryDBGPath) delete [] m_tszPEImageDebugDirectoryDBGPath;
if (lpCurrentImageDebugMiscPointer->Unicode) { // Is this a Unicode string?
m_tszPEImageDebugDirectoryDBGPath = CUtilityFunctions::CopyUnicodeStringToTSTR((LPWSTR)lpszExeName); } else { // Is this an ANSI string?
m_tszPEImageDebugDirectoryDBGPath = CUtilityFunctions::CopyAnsiStringToTSTR(lpszExeName); }
if (!m_tszPEImageDebugDirectoryDBGPath) goto cleanup;
break; } else { // Beware of corrupt images
if (lpCurrentImageDebugMiscPointer->Length == 0) { break; }
// Decrement the ulSizeOfMiscDirectoryEntry by the length of this "stuff"
ulSizeOfMiscDirectoryEntry -= lpCurrentImageDebugMiscPointer->Length;
// If our new value exceeds the SizeOfData we need to bail...
if (ulSizeOfMiscDirectoryEntry > lpImageDebugDirectory->SizeOfData) { ulSizeOfMiscDirectoryEntry = 0; // Avoid AV on bad exe
break; } lpCurrentImageDebugMiscPointer = (PIMAGE_DEBUG_MISC) (lpCurrentImageDebugMiscPointer + lpCurrentImageDebugMiscPointer->Length); } }
fReturnValue = true;
cleanup: if (lpImageDebugMisc) { delete [] lpImageDebugMisc; lpImageDebugMisc = NULL; } return fReturnValue; }
bool CModuleInfo::ProcessDebugTypeCoffDirectoryEntry(const bool fPEImage, const PIMAGE_DEBUG_DIRECTORY lpImageDebugDirectory) { //
// The only thing we really care about is the size right now...
//
if (fPEImage) { m_dwPEImageDebugDirectoryCoffSize = lpImageDebugDirectory->SizeOfData; } else { m_dwDBGImageDebugDirectoryCoffSize = lpImageDebugDirectory->SizeOfData; }
return true; }
bool CModuleInfo::ProcessDebugTypeFPODirectoryEntry(const bool fPEImage, const PIMAGE_DEBUG_DIRECTORY lpImageDebugDirectory) { //
// The only thing we really care about is the size right now...
//
if (fPEImage) { m_dwPEImageDebugDirectoryFPOSize = lpImageDebugDirectory->SizeOfData; } else { m_dwDBGImageDebugDirectoryFPOSize = lpImageDebugDirectory->SizeOfData; }
return true;
}
bool CModuleInfo::ProcessDebugTypeCVDirectoryEntry(const bool fPEImage, const bool fDmpFile, const HANDLE hModuleHandle, const PIMAGE_DEBUG_DIRECTORY lpImageDebugDirectory) { bool fReturnValue = false; ULONG OffsetImageDebugDirectory; DWORD dwCVFormatSpecifier; char szPdb[_MAX_PATH * 3]; // Must this be so large?
// Calculate the location/size so we can load it.
if (fDmpFile) { OffsetImageDebugDirectory = lpImageDebugDirectory->AddressOfRawData; } else { OffsetImageDebugDirectory = lpImageDebugDirectory->PointerToRawData; }
// Advance to the location of the Debug Info
SetReadPointer(fDmpFile, hModuleHandle, OffsetImageDebugDirectory, FILE_BEGIN);
// Read the data...
if (!DoRead(fDmpFile, hModuleHandle, &dwCVFormatSpecifier, sizeof(DWORD))) goto cleanup;
if (fPEImage) { m_dwPEImageDebugDirectoryPDBFormatSpecifier = dwCVFormatSpecifier; } else { m_dwDBGDebugDirectoryPDBFormatSpecifier = dwCVFormatSpecifier; }
switch (dwCVFormatSpecifier) { case sigNB09: case sigNB11: //
// The only thing we really care about is the size right now...
//
if (fPEImage) { m_dwPEImageDebugDirectoryCVSize = lpImageDebugDirectory->SizeOfData; } else { m_dwDBGImageDebugDirectoryCVSize = lpImageDebugDirectory->SizeOfData; } break; case sigNB10:
NB10I nb10i;
// Read the data...
if (!DoRead(fDmpFile, hModuleHandle, &nb10i.off, sizeof(NB10I) - sizeof(DWORD))) goto cleanup;
if (fPEImage) { // Save away the PDB Signature...
m_dwPEImageDebugDirectoryPDBSignature = nb10i.sig;
// Save away the PDB Age...
m_dwPEImageDebugDirectoryPDBAge = nb10i.age; } else { // Save away the PDB Signature...
m_dwDBGDebugDirectoryPDBSignature = nb10i.sig;
// Save away the PDB Age...
m_dwDBGDebugDirectoryPDBAge = nb10i.age; }
// Read the data...
if (!DoRead(fDmpFile, hModuleHandle, szPdb, (lpImageDebugDirectory->SizeOfData) - sizeof(NB10I))) goto cleanup;
if (szPdb[0] != '\0') { // Save the data (as appropriate)
if (fPEImage) { // Copy the PDB path away...
m_tszPEImageDebugDirectoryPDBPath = CUtilityFunctions::CopyAnsiStringToTSTR(szPdb);
if (!m_tszPEImageDebugDirectoryPDBPath) goto cleanup; } else { // Copy the PDB path away...
m_tszDBGDebugDirectoryPDBPath = CUtilityFunctions::CopyAnsiStringToTSTR(szPdb);
if (!m_tszDBGDebugDirectoryPDBPath) goto cleanup;
// We now know that we have a DBG/PDB combination...
m_enumPEImageSymbolStatus = SYMBOLS_DBG_AND_PDB; } } break;
case sigRSDS: RSDSI rsdsi;
// Read the RSDSI structure (except for the rsds DWORD at the beginning).
if (!DoRead(fDmpFile, hModuleHandle, &rsdsi.guidSig, sizeof(RSDSI) - sizeof(DWORD))) goto cleanup;
wchar_t wszGuid[39];
StringFromGUID2(rsdsi.guidSig, wszGuid, sizeof(wszGuid)/sizeof(wchar_t));
if (fPEImage) { // Save away the PDB Age...
m_dwPEImageDebugDirectoryPDBAge = rsdsi.age;
// Copy the GUID...
m_tszPEImageDebugDirectoryPDBGuid = CUtilityFunctions::CopyUnicodeStringToTSTR(wszGuid); } else { // Save away the PDB Age...
m_dwDBGDebugDirectoryPDBAge = rsdsi.age;
// Copy the GUID...
m_tszDBGDebugDirectoryPDBGuid = CUtilityFunctions::CopyUnicodeStringToTSTR(wszGuid); }
// Now, read in the PDB path... apparently it's in UTF8 format...
if (!DoRead(fDmpFile, hModuleHandle, szPdb, (lpImageDebugDirectory->SizeOfData) - sizeof(RSDSI))) goto cleanup; if (szPdb[0] != '\0') { // Save the data (as appropriate)
if (fPEImage) { wchar_t wszPdb[_MAX_PATH]; CUtilityFunctions::UTF8ToUnicode(szPdb, wszPdb, sizeof(wszPdb));
// Copy the PDB path away...
m_tszPEImageDebugDirectoryPDBPath = CUtilityFunctions::CopyUnicodeStringToTSTR(wszPdb); if (!m_tszPEImageDebugDirectoryPDBPath) goto cleanup; } else { wchar_t wszPdb[_MAX_PATH]; CUtilityFunctions::UTF8ToUnicode(szPdb, wszPdb, sizeof(wszPdb));
// Copy the PDB path away...
m_tszDBGDebugDirectoryPDBPath = CUtilityFunctions::CopyUnicodeStringToTSTR(wszPdb); if (!m_tszDBGDebugDirectoryPDBPath) goto cleanup; } } break;
// Unknown CV format...
default: break; }
fReturnValue = true;
cleanup:
return fReturnValue; }
bool CModuleInfo::ProcessDebugTypeOMAPDirectoryEntry(const bool fPEImage, const PIMAGE_DEBUG_DIRECTORY lpImageDebugDirectory) { DWORD dwSize = lpImageDebugDirectory->SizeOfData; //
// The only thing we really care about is the size right now...
//
switch (lpImageDebugDirectory->Type) { case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: if (fPEImage) { m_dwPEImageDebugDirectoryOMAPtoSRCSize = dwSize; } else { m_dwDBGImageDebugDirectoryOMAPtoSRCSize = dwSize; } break; case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: if (fPEImage) { m_dwPEImageDebugDirectoryOMAPfromSRCSize = dwSize; } else { m_dwDBGImageDebugDirectoryOMAPfromSRCSize = dwSize; } break; }
return true; }
bool CModuleInfo::OutputDataToStdoutInternalSymbolInfo(DWORD dwCoffSize, DWORD dwFPOSize, DWORD dwCVSize, DWORD dwOMAPtoSRC, DWORD dwOMAPfromSRC) { // _tprintf(TEXT(" Module has internal symbols.\n"));
if (dwCoffSize) { _tprintf(TEXT(" Internal COFF Symbols - Size 0x%08x bytes\n"), dwCoffSize); }
if (dwFPOSize) { _tprintf(TEXT(" Internal FPO Symbols - Size 0x%08x bytes\n"), dwFPOSize); }
if (dwCVSize) { _tprintf(TEXT(" Internal CV Symbols - Size 0x%08x bytes\n"), dwCVSize); }
if (dwOMAPtoSRC) { _tprintf(TEXT(" Internal -> SRC Symbols - Size 0x%08x bytes\n"), dwOMAPtoSRC); }
if (dwOMAPfromSRC) { _tprintf(TEXT(" Internal SRC -> Symbols - Size 0x%08x bytes\n"), dwOMAPfromSRC); }
return true; }
//
// Dump DBG information
//
bool CModuleInfo::OutputDataToStdoutDbgSymbolInfo(LPCTSTR tszModulePointerToDbg, DWORD dwTimeDateStamp, DWORD dwChecksum, DWORD dwSizeOfImage, LPCTSTR tszDbgComment, DWORD dwExpectedTimeDateStamp, DWORD dwExpectedChecksum, DWORD dwExpectedSizeOfImage) { if (!tszDbgComment) { // Dump out the pointer to the DBG file from the PE Image
if (tszModulePointerToDbg) { _tprintf(TEXT(" Module Pointer to DBG = [%s]\n"), tszModulePointerToDbg); } else { _tprintf(TEXT(" Module had DBG File stripped from it.\n")); }
time_t time = dwTimeDateStamp; _tprintf(TEXT(" Module TimeDateStamp = 0x%08x - %s"), dwTimeDateStamp, _tctime(&time)); _tprintf(TEXT(" Module Checksum = 0x%08x\n"), dwChecksum); _tprintf(TEXT(" Module SizeOfImage = 0x%08x\n"), dwSizeOfImage);
} else { TCHAR tszBuffer[2*_MAX_PATH]; // This should be large enough ;)
size_t tszStringLength;
// Is this discrepancy stuff...
if (tszModulePointerToDbg) { _tprintf(TEXT(" DBG File = [%s] [%s]\n"), tszModulePointerToDbg, tszDbgComment); }
time_t time = dwTimeDateStamp; _stprintf(tszBuffer, TEXT(" DBG TimeDateStamp = 0x%08x - %s"), dwTimeDateStamp, _tctime(&time));
// If our TimeDateStamps don't match... we have some fixup to do...
if (dwTimeDateStamp != dwExpectedTimeDateStamp) { tszStringLength = _tcslen(tszBuffer); if (tszBuffer[tszStringLength-1] == '\n') tszBuffer[tszStringLength-1] = '\0'; } _tprintf(tszBuffer); // If our TimeDateStamps don't match... we have some fixup to do...
if (dwTimeDateStamp != dwExpectedTimeDateStamp) { _tprintf(TEXT(" [%s]!\n"), (dwTimeDateStamp > dwExpectedTimeDateStamp) ? TEXT("NEWER") : TEXT("OLDER")); }
_tprintf(TEXT(" DBG Checksum = 0x%08x [%s]\n"), dwChecksum, ( (dwChecksum == dwExpectedChecksum) ? TEXT("MATCHED"):TEXT("UNMATCHED")) ); _tprintf(TEXT(" DBG SizeOfImage = 0x%08x [%s]\n"), dwSizeOfImage, ( ( dwSizeOfImage == dwExpectedSizeOfImage) ? TEXT("MATCHED"):TEXT("UNMATCHED")) ); }
return true; }
bool CModuleInfo::OutputDataToStdoutPdbSymbolInfo(DWORD dwPDBFormatSpecifier, LPTSTR tszModulePointerToPDB, DWORD dwPDBSignature, LPTSTR tszPDBGuid, DWORD dwPDBAge, LPCTSTR tszPdbComment) {
if (tszModulePointerToPDB) { if (!tszPdbComment) { _tprintf(TEXT(" Module Pointer to PDB = [%s]\n"), tszModulePointerToPDB); } else { _tprintf(TEXT(" PDB File = [%s] [%s]\n"), tszModulePointerToPDB, tszPdbComment); } switch (dwPDBFormatSpecifier) { case sigNB10: _tprintf(TEXT(" Module PDB Signature = 0x%x\n"), dwPDBSignature); break; case sigRSDS: _tprintf(TEXT(" Module PDB Guid = %s\n"), tszPDBGuid); break; default: _tprintf(TEXT(" UNKNOWN PDB Format!\n")); break; } _tprintf(TEXT(" Module PDB Age = 0x%x\n"), dwPDBAge); } else { _tprintf(TEXT(" Module has PDB File\n")); _tprintf(TEXT(" Module Pointer to PDB = [UNKNOWN] (Could not find in PE Image)\n")); }
return true; }
bool CModuleInfo::OutputDataToStdoutModuleInfo(DWORD dwModuleNumber) { _tprintf(TEXT("Module[%3d] [%s] %s\n"), dwModuleNumber, m_tszPEImageModuleFileSystemPath, (m_dwPEImageDebugDirectoryCVSize ? TEXT("(Source Enabled)") : TEXT("")));
// LPTSTR lpMachineArchitecture;
//
// switch(m_wPEImageMachineArchitecture)
// {
// case IMAGE_FILE_MACHINE_I386:
// lpMachineArchitecture = TEXT("Binary Image for Intel Machines");
// break;
//
// case IMAGE_FILE_MACHINE_ALPHA64:
// lpMachineArchitecture = TEXT("Binary Image for Alpha Machines");
// break;
//
// default:
// lpMachineArchitecture = TEXT("Binary Image for Unknown Machine Architecture");
// }
//
// if (m_wPEImageMachineArchitecture) _tprintf(TEXT(" %s\n"), lpMachineArchitecture);
//
// First, let's output version information if requested
//
if (g_lpProgramOptions->GetMode(CProgramOptions::CollectVersionInfoMode) ) { // Version Information
if (m_tszPEImageFileVersionCompanyName) _tprintf(TEXT(" Company Name: %s\n"), m_tszPEImageFileVersionCompanyName); if (m_tszPEImageFileVersionDescription) _tprintf(TEXT(" File Description: %s\n"), m_tszPEImageFileVersionDescription); if (m_tszPEImageProductVersionString) _tprintf(TEXT(" Product Version: %s\n"), m_tszPEImageProductVersionString); if (m_tszPEImageFileVersionString) _tprintf(TEXT(" File Version: %s\n"), m_tszPEImageFileVersionString); if (m_dwPEImageFileSize) _tprintf(TEXT(" File Size (bytes): %d\n"), m_dwPEImageFileSize); if ( m_ftPEImageFileTimeDateStamp.dwHighDateTime || m_ftPEImageFileTimeDateStamp.dwLowDateTime) { enum { FILETIME_BUFFERSIZE = 128 }; TCHAR tszFileTime[FILETIME_BUFFERSIZE]; if (OutputFileTime(m_ftPEImageFileTimeDateStamp, tszFileTime, FILETIME_BUFFERSIZE)) _tprintf(TEXT(" File Date: %s\n"), tszFileTime); } }
return true; }
bool CModuleInfo::OutputDataToStdoutThisModule() { //
// If we're not doing "Discrepancies Only" then we output this module unconditionally...
//
if (!g_lpProgramOptions->GetMode(CProgramOptions::OutputDiscrepanciesOnly)) return true;
//
// If we're not in verification mode, then we output everything...
//
if (!g_lpProgramOptions->GetMode(CProgramOptions::VerifySymbolsMode)) return true; //
// This is "Discrepancy Only" mode, so check for discrepancies...
//
bool fAnyDiscrepancies = false;
// Hey, if they only want to dump out modules with discrepancies... check to see
// if this qualifies...
switch (m_enumPEImageSymbolStatus) { // Consider these normal status codes...
case SYMBOLS_DBG: case SYMBOLS_DBG_AND_PDB: case SYMBOLS_PDB: case SYMBOLS_LOCAL: break;
// Anything else is worth reporting...
default: fAnyDiscrepancies = true; }
// If we don't have a discrepancy yet... let's look further...
if (!fAnyDiscrepancies) { // Is there a DBG file?
if ( (m_enumPEImageSymbolStatus == SYMBOLS_DBG) || (m_enumPEImageSymbolStatus == SYMBOLS_DBG_AND_PDB) ) { // Does it match?
if ( m_enumDBGModuleStatus != SYMBOL_MATCH ) fAnyDiscrepancies = true; }
// Is there a PDB file?
if ( GetDebugDirectoryPDBPath() ) { if (m_enumPDBModuleStatus != SYMBOL_MATCH ) fAnyDiscrepancies = true; } }
return fAnyDiscrepancies; }
bool CModuleInfo::ProcessPDBSourceInfo(PDB *lpPdb) { bool fReturnValue = false; DBI* lpDbi = NULL;
// Module variables...
Mod * lpMod = NULL; Mod * lpPrevMod = NULL; long cb;
// Type variables...
TPI * lpTpi = NULL; TI tiMin; TI tiMac;
// Summary variables
m_dwPDBTotalBytesOfLineInformation = 0; m_dwPDBTotalBytesOfSymbolInformation = 0; m_dwPDBTotalSymbolTypesRange = 0;
if (!PDBOpenDBI(lpPdb, pdbRead, NULL, &lpDbi)) goto cleanup;
//
// Enumerate through the modules in the Dbi interface we opened...
//
while (DBIQueryNextMod(lpDbi, lpMod, &lpMod) && lpMod) { // If we had a Module Previously... close it...
if (lpPrevMod) { ModClose(lpPrevMod); lpPrevMod = NULL; }
// Check that Source line info is removed
ModQueryLines(lpMod, NULL, &cb);
// If we have lines... add these to our total...
m_dwPDBTotalBytesOfLineInformation+= cb;
// Check that local symbols are removed
ModQuerySymbols(lpMod, NULL, &cb);
// If we have symbols for this module... add these to our total...
m_dwPDBTotalBytesOfSymbolInformation+= cb;
// Save the current module (so we can close it if needed)...
lpPrevMod = lpMod; }
//
// Attempt to open the Tpi Interface
//
PDBOpenTpi(lpPdb, pdbRead, &lpTpi);
// If we
if(lpTpi) { // Find the Min and Max Index...
tiMin = TypesQueryTiMinEx(lpTpi); tiMac = TypesQueryTiMacEx(lpTpi);
if (tiMin < tiMac) { m_dwPDBTotalSymbolTypesRange = tiMac - tiMin; }
}
fReturnValue = true;
cleanup: if (lpTpi) { TypesClose(lpTpi); lpTpi = NULL; } if (lpMod) { ModClose(lpMod); lpMod = NULL; } if (lpPrevMod) { ModClose(lpPrevMod); lpPrevMod = NULL; } if (lpDbi) { DBIClose(lpDbi); }
return fReturnValue; }
|