3600 lines
105 KiB
C++
3600 lines
105 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|