mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2551 lines
72 KiB
2551 lines
72 KiB
#include <assert.h>
|
|
#include "symutil.h"
|
|
#include "private.h"
|
|
#include "dbgimage.h"
|
|
#include "cvinfo.h"
|
|
#include "exe_vxd.h"
|
|
#include "share.h"
|
|
#include "winbase.h"
|
|
|
|
// Stuff for Checking symbols
|
|
|
|
#define DBGSYM 2
|
|
#define PDBSYM 3
|
|
#define lengthof(a) (sizeof(a) / sizeof(a[0]))
|
|
|
|
BOOL CheckPrivate=FALSE;
|
|
BOOL CheckCodeView=TRUE;
|
|
PEXCLUDE_LIST pErrorFilterList=NULL;
|
|
P_LIST pCDIncludeList=NULL;
|
|
BOOL Recurse = FALSE;
|
|
BOOL LogCheckSumErrors = TRUE;
|
|
|
|
// private version of qsort used to avoid compat problems on NT4 and win2k.
|
|
// code is published from base\crts
|
|
extern
|
|
void __cdecl dbg_qsort(void *, size_t, size_t,
|
|
int (__cdecl *) (const void *, const void *));
|
|
|
|
#if defined(use_SymutilX)
|
|
|
|
static BOOL RSDSLibLoaded=FALSE;
|
|
|
|
// Typedefs
|
|
typedef BOOL ( __cdecl *PPDBOPENVALIDATE4 ) (
|
|
const wchar_t *wszPDB,
|
|
const char *szMode,
|
|
PCSIG70 pcsig70,
|
|
SIG sig,
|
|
AGE age,
|
|
OUT EC *pec,
|
|
OUT wchar_t *wszError,
|
|
size_t cchErrMax,
|
|
OUT PDB **pppdb
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PPDBCLOSE ) (
|
|
PDB* ppdb
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PDBIQUERYNEXTMOD ) (
|
|
DBI* pdbi, Mod* pmod, Mod** ppmodNext
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PMODCLOSE ) (
|
|
Mod* pmod
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PMODQUERYLINES ) (
|
|
Mod* pmod, BYTE* pbLines, long* pcb
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PMODQUERYSYMBOLS ) (
|
|
Mod* pmod, BYTE* pbSym, long* pcb
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PDBIQUERYTYPESERVER ) (
|
|
DBI* pdbi, ITSM itsm, OUT TPI** pptpi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PPDBOPENTPI ) (
|
|
PDB* ppdb, const char* szMode, OUT TPI** pptpi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PTYPESQUERYTIMINEX ) (
|
|
TPI* ptpi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PTYPESQUERYTIMACEX ) (
|
|
TPI* ptpi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PTYPESCLOSE ) (
|
|
TPI* ptpi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PPDBOPENDBI ) (
|
|
PDB* ppdb, const char* szMode, const char* szTarget, OUT DBI** ppdbi
|
|
);
|
|
|
|
typedef BOOL ( __cdecl *PDBICLOSE ) (
|
|
DBI* pdbi
|
|
);
|
|
|
|
static PPDBOPENVALIDATE4 pPDBOpenValidate4 = NULL;
|
|
static PPDBCLOSE pPDBClose = NULL;
|
|
static PDBIQUERYNEXTMOD pDBIQueryNextMod = NULL;
|
|
static PMODCLOSE pModClose = NULL;
|
|
static PMODQUERYLINES pModQueryLines = NULL;
|
|
static PMODQUERYSYMBOLS pModQuerySymbols = NULL;
|
|
static PDBIQUERYTYPESERVER pDBIQueryTypeServer = NULL;
|
|
static PPDBOPENTPI pPDBOpenTpi = NULL;
|
|
static PTYPESQUERYTIMINEX pTypesQueryTiMinEx = NULL;
|
|
static PTYPESQUERYTIMACEX pTypesQueryTiMacEx = NULL;
|
|
static PTYPESCLOSE pTypesClose = NULL;
|
|
static PPDBOPENDBI pPDBOpenDBI = NULL;
|
|
static PDBICLOSE pDBIClose = NULL;
|
|
|
|
#endif
|
|
|
|
BOOL
|
|
ansi2wcs(
|
|
PSTR psz,
|
|
PWSTR pwsz,
|
|
DWORD pwszlen
|
|
);
|
|
|
|
typedef struct _FILE_INFO {
|
|
DWORD TimeDateStamp;
|
|
DWORD SizeOfImage;
|
|
DWORD CheckSum;
|
|
TCHAR szName[MAX_PATH];
|
|
} FILE_INFO, *PFILE_INFO;
|
|
|
|
|
|
PIMAGE_DOS_HEADER
|
|
MapFileHeader (
|
|
LPTSTR szFileName,
|
|
PHANDLE phFile,
|
|
PSYM_ERR pSymErr
|
|
);
|
|
|
|
PIMAGE_NT_HEADERS
|
|
GetNtHeader (
|
|
PIMAGE_DOS_HEADER pDosHeader,
|
|
HANDLE hDosFile,
|
|
LPTSTR szFileName,
|
|
PSYM_ERR pSymErr,
|
|
LPBY_HANDLE_FILE_INFORMATION lpFileInfo
|
|
);
|
|
|
|
BOOL
|
|
ResourceOnlyDll(
|
|
PVOID pImageBase,
|
|
BOOLEAN bMappedAsImage
|
|
);
|
|
|
|
PIMAGE_SEPARATE_DEBUG_HEADER
|
|
MapDbgHeader (
|
|
LPTSTR szFileName,
|
|
PHANDLE phFile,
|
|
PSYM_ERR pSymErr
|
|
);
|
|
|
|
BOOL
|
|
UnmapFile(
|
|
LPCVOID phFileMap,
|
|
HANDLE hFile
|
|
);
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *
|
|
GetDebugDirectoryInExe(
|
|
PIMAGE_DOS_HEADER pDosHeader,
|
|
ULONG *NumberOfDebugDirectories
|
|
);
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *
|
|
GetDebugDirectoryInDbg(
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader,
|
|
ULONG *NumberOfDebugDirectories
|
|
);
|
|
|
|
PIMAGE_SEPARATE_DEBUG_HEADER
|
|
MapMatchingDbgFile(
|
|
LPTSTR szSearchPath,
|
|
PFILE_INFO pFileInfo,
|
|
LPTSTR szFoundPath
|
|
);
|
|
|
|
BOOL
|
|
VerifyCV(
|
|
LPTSTR szFileName,
|
|
PCHAR pImageBase,
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDbgDir,
|
|
LPTSTR szExtPath,
|
|
LPTSTR szSearchPath,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szRSDSDllToLoad
|
|
);
|
|
|
|
LPSTR
|
|
GetMiscFile(
|
|
PCHAR pImageBase,
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDbgDir
|
|
);
|
|
|
|
BOOL
|
|
SearchForSymbolFile (
|
|
LPTSTR szSearchPath,
|
|
LPTSTR szSymName,
|
|
LPTSTR szPathExt,
|
|
PSYM_ERR pSymErr,
|
|
DWORD SymType,
|
|
PVOID pelem1,
|
|
LPTSTR szResult,
|
|
DWORD dwResultLength,
|
|
LPTSTR szRSDSDllToLoad
|
|
);
|
|
|
|
USHORT
|
|
__cdecl
|
|
CompDbg(
|
|
PVOID pelem1,
|
|
LPTSTR szSymName,
|
|
PSYM_ERR pSymErr
|
|
);
|
|
|
|
USHORT
|
|
__cdecl
|
|
CompPdb(
|
|
PVOID pelem1,
|
|
LPTSTR szSymName,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szRSDSDllToLoad
|
|
);
|
|
|
|
BOOL
|
|
AddToSymbolsCDLog(
|
|
FILE *hSymCDLog,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szSymbolPath,
|
|
LPTSTR szFileExt
|
|
);
|
|
|
|
BOOL PDBPrivateStripped(
|
|
PDB *ppdb,
|
|
DBI *pdbi
|
|
);
|
|
|
|
#if defined(use_SymutilX)
|
|
BOOL PDBPrivateStrippedX(
|
|
PDB *ppdb,
|
|
DBI *pdbi
|
|
);
|
|
#endif
|
|
|
|
BOOL
|
|
RemoveDuplicateSlashes(
|
|
LPTSTR Str
|
|
);
|
|
|
|
int __cdecl
|
|
SymComp(
|
|
const void *e1,
|
|
const void *e2
|
|
);
|
|
|
|
PEXCLUDE_LIST
|
|
GetExcludeList(
|
|
LPTSTR szFileName
|
|
)
|
|
|
|
{
|
|
PEXCLUDE_LIST pExcList;
|
|
|
|
FILE *fFile;
|
|
TCHAR szCurFile[_MAX_FNAME+1], *c;
|
|
TCHAR fname[_MAX_FNAME+1], ext[_MAX_EXT+1];
|
|
DWORD i;
|
|
LPTSTR szEndName;
|
|
|
|
if ( (fFile = _tfopen(szFileName,_T("r") )) == NULL ) {
|
|
// printf( "Cannot open the exclude file %s\n",szFileName );
|
|
return FALSE;
|
|
}
|
|
|
|
pExcList = (PEXCLUDE_LIST)malloc(sizeof(EXCLUDE_LIST));
|
|
|
|
if (pExcList)
|
|
{
|
|
pExcList->dNumFiles = 0;
|
|
|
|
while ( _fgetts(szCurFile,_MAX_FNAME,fFile) ) {
|
|
if ( szCurFile[0] == ';' ) continue;
|
|
(pExcList->dNumFiles)++;
|
|
}
|
|
|
|
// Go back to the beginning of the file
|
|
fseek(fFile,0,0);
|
|
pExcList->szExcList = (LPTSTR*)malloc( sizeof(LPTSTR) *
|
|
(pExcList->dNumFiles));
|
|
if (pExcList->szExcList == NULL)
|
|
{
|
|
free(pExcList);
|
|
pExcList = NULL;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
while ( i < pExcList->dNumFiles )
|
|
{
|
|
pExcList->szExcList[i] = NULL;
|
|
|
|
memset(szCurFile,'\0',sizeof(TCHAR) * (_MAX_FNAME+1) );
|
|
_fgetts(szCurFile,_MAX_FNAME,fFile);
|
|
|
|
// Replace the \n with \0
|
|
c = NULL;
|
|
c = _tcschr(szCurFile, '\n');
|
|
if ( c != NULL)
|
|
{
|
|
*c='\0';
|
|
}
|
|
|
|
if ( szCurFile[0] == ';' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( _tcslen(szCurFile) > _MAX_FNAME )
|
|
{
|
|
printf("File %s has a string that is too large\n",szFileName);
|
|
continue;
|
|
}
|
|
|
|
// Allow for spaces and a ; after the file name
|
|
// Move the '\0' back until it has erased the ';' and any
|
|
// tabs and spaces that might come before it
|
|
|
|
// Set the pointer to the ; if there is a comment
|
|
szEndName = _tcschr(szCurFile, ';');
|
|
|
|
// Set the pointer to the last character in the string if
|
|
// there wasn't a comment
|
|
if (szEndName == NULL ) {
|
|
if (_tcslen(szCurFile) > 0 ) {
|
|
szEndName = szCurFile + _tcslen(szCurFile) - 1;
|
|
}
|
|
}
|
|
|
|
if (szEndName != NULL ) {
|
|
while ( *szEndName == ';' || *szEndName == ' '
|
|
|| *szEndName == '\t' ) {
|
|
*szEndName = '\0';
|
|
if ( szEndName > szCurFile ) szEndName--;
|
|
}
|
|
}
|
|
|
|
pExcList->szExcList[i]=(LPTSTR)
|
|
malloc( sizeof(TCHAR) * (_tcslen(szCurFile)+1) );
|
|
|
|
if (pExcList->szExcList[i] == NULL )
|
|
{
|
|
printf("Malloc failed for %s\n",szCurFile);
|
|
}
|
|
else
|
|
{
|
|
_tsplitpath(szCurFile,NULL,NULL,fname,ext);
|
|
|
|
_tcscpy(pExcList->szExcList[i],fname);
|
|
_tcscat(pExcList->szExcList[i],ext);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
// Sort the List
|
|
dbg_qsort( (void*)pExcList->szExcList, (size_t)pExcList->dNumFiles,
|
|
(size_t)sizeof(LPTSTR), SymComp );
|
|
}
|
|
}
|
|
|
|
fclose(fFile);
|
|
|
|
return (pExcList);
|
|
|
|
}
|
|
|
|
BOOL
|
|
InExcludeList(
|
|
LPTSTR szFileName,
|
|
PEXCLUDE_LIST pExcludeList
|
|
)
|
|
|
|
{
|
|
DWORD i;
|
|
int High;
|
|
int Low;
|
|
int Middle;
|
|
int Result;
|
|
|
|
// Lookup the name using a binary search
|
|
if ( pExcludeList == NULL ) return FALSE;
|
|
if ( pExcludeList->dNumFiles == 0 ) return FALSE;
|
|
|
|
Low = 0;
|
|
High = pExcludeList->dNumFiles - 1;
|
|
while ( High >= Low ) {
|
|
|
|
Middle = (Low + High) >> 1;
|
|
Result = _tcsicmp( szFileName, pExcludeList->szExcList[Middle] );
|
|
|
|
if ( Result < 0 ) {
|
|
High = Middle - 1;
|
|
|
|
} else if ( Result > 0 ) {
|
|
Low = Middle + 1;
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( High < Low ) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
InList(
|
|
LPTSTR szFileName,
|
|
P_LIST pExcludeList
|
|
)
|
|
|
|
{
|
|
DWORD i;
|
|
int High;
|
|
int Low;
|
|
int Middle;
|
|
int Result;
|
|
|
|
// Lookup the name using a binary search
|
|
if ( pExcludeList == NULL ) return FALSE;
|
|
if ( pExcludeList->dNumFiles == 0 ) return FALSE;
|
|
|
|
Low = 0;
|
|
High = pExcludeList->dNumFiles - 1;
|
|
while ( High >= Low ) {
|
|
|
|
Middle = (Low + High) >> 1;
|
|
Result = _tcsicmp( szFileName, pExcludeList->List[Middle].Path );
|
|
|
|
if ( Result < 0 ) {
|
|
High = Middle - 1;
|
|
|
|
} else if ( Result > 0 ) {
|
|
Low = Middle + 1;
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( High < Low ) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
SymComp(
|
|
const void *e1,
|
|
const void *e2
|
|
)
|
|
{
|
|
LPTSTR* p1;
|
|
LPTSTR* p2;
|
|
|
|
p1 = (LPTSTR*)e1;
|
|
p2 = (LPTSTR*)e2;
|
|
|
|
return ( _tcsicmp(*p1,*p2) );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckSymbols (
|
|
LPTSTR ErrMsg,
|
|
LPTSTR szSearchPath,
|
|
LPTSTR szFileName,
|
|
FILE *hSymCDLog,
|
|
ULONG SymchkFlag,
|
|
BOOL Verbose,
|
|
LPTSTR szRSDSDllToLoad
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function accepts a file name and a symbol search path
|
|
(delimited by ;) and determines if its symbols match.
|
|
|
|
Arguments:
|
|
szSearchPath Search path delimited by ;
|
|
|
|
szFileName Full path and name of the file to verify symbols for
|
|
|
|
szCopyDest If this is not a NULL value, then generate actually copy the
|
|
symbols to this destination
|
|
|
|
SymchkFlag Specifies action to take according to whether symbols are
|
|
split or not split.
|
|
|
|
Possible values:
|
|
ERROR_IF_SPLIT Print an error if the image is split already
|
|
ERROR_IF_NOT_SPLIT Error if image is not split
|
|
IGNORE_IF_SPLIT Don't check symbols for split images
|
|
|
|
Verbose If true, print an output line for every file
|
|
If false, print output only for files that fail
|
|
|
|
Return Value:
|
|
TRUE if symbols are correct, or symbol checking was ignored
|
|
FALSE if symbols are not correct
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PIMAGE_NT_HEADERS pNtHeader = NULL;
|
|
PIMAGE_DOS_HEADER pDosHeader = NULL;
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader= NULL;
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *DebugDirectory;
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDbgDir=NULL;
|
|
PIMAGE_DEBUG_MISC pDebugMisc;
|
|
|
|
PTCHAR pImageBase;
|
|
|
|
ULONG NumberOfDebugDirectories;
|
|
FILE_INFO FileInfo;
|
|
LPSTR szMiscFileName;
|
|
UINT i;
|
|
PNB10I pDebugCV;
|
|
|
|
|
|
TCHAR path_buffer[_MAX_PATH];
|
|
TCHAR drive[_MAX_DRIVE];
|
|
TCHAR dir[_MAX_DIR];
|
|
TCHAR fname[_MAX_FNAME];
|
|
TCHAR ext[_MAX_EXT];
|
|
TCHAR szDbgFileName[_MAX_PATH*sizeof(TCHAR)];
|
|
DWORD dwDbgFileNameLength = _MAX_PATH;
|
|
|
|
HANDLE DbgFile = 0;
|
|
HANDLE DosFile = 0;
|
|
|
|
BOOL SymbolsOK = TRUE;
|
|
BOOL CVFound = FALSE;
|
|
BOOL MiscFound = FALSE;
|
|
BOOL RawDataFound = FALSE;
|
|
BOOL rc= FALSE;
|
|
BY_HANDLE_FILE_INFORMATION HandleFileInfo;
|
|
|
|
SYM_ERR SymErr;
|
|
|
|
// Get the file name and the extension
|
|
_tsplitpath( szFileName,drive,dir,fname,ext);
|
|
|
|
|
|
// Initialize SymErr
|
|
memset( &SymErr,0,sizeof(SYM_ERR) );
|
|
SymErr.Verbose = Verbose;
|
|
_tcscpy( SymErr.szFileName, szFileName );
|
|
_tcscpy( SymErr.szSymbolSearchPath, szSearchPath );
|
|
_tcscpy( SymErr.szSymbolFileName, _T("") );
|
|
_tcscpy( SymErr.szPdbErr, _T("") );
|
|
_tcscpy( SymErr.szPdbFileName, _T("") );
|
|
|
|
pDosHeader = MapFileHeader( szFileName, &DosFile, &SymErr );
|
|
if ( SymErr.ErrNo > 0 ) {
|
|
LogError( ErrMsg, &SymErr, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
pNtHeader = GetNtHeader( pDosHeader, DosFile, szFileName, &SymErr, &HandleFileInfo );
|
|
if ( SymErr.ErrNo > 0 ) {
|
|
UnmapFile((LPCVOID)pDosHeader,DosFile);
|
|
LogError( ErrMsg, &SymErr,0 );
|
|
return TRUE;
|
|
}
|
|
|
|
__try {
|
|
// Resource Dll's shouldn't have symbols
|
|
if ( ResourceOnlyDll((PVOID)pDosHeader, FALSE) ) {
|
|
LogError( ErrMsg, &SymErr,RESOURCE_ONLY_DLL);
|
|
SymbolsOK = TRUE;
|
|
__leave;
|
|
}
|
|
|
|
// Get info out of file header for comparison later
|
|
if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
FileInfo.CheckSum = ((PIMAGE_NT_HEADERS32)pNtHeader)->OptionalHeader.CheckSum;
|
|
FileInfo.SizeOfImage = ((PIMAGE_NT_HEADERS32)pNtHeader)->OptionalHeader.SizeOfImage;
|
|
} else {
|
|
if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
FileInfo.CheckSum = ((PIMAGE_NT_HEADERS64)pNtHeader)->OptionalHeader.CheckSum;
|
|
FileInfo.SizeOfImage = ((PIMAGE_NT_HEADERS64)pNtHeader)->OptionalHeader.SizeOfImage;
|
|
} else {
|
|
FileInfo.CheckSum = -1;
|
|
}
|
|
}
|
|
FileInfo.TimeDateStamp = pNtHeader->FileHeader.TimeDateStamp;
|
|
_tcscpy(FileInfo.szName,szFileName);
|
|
|
|
|
|
// Locate the Debug Directory in this file
|
|
DebugDirectory = NULL;
|
|
DebugDirectory = GetDebugDirectoryInExe(
|
|
pDosHeader,
|
|
&NumberOfDebugDirectories
|
|
);
|
|
if (!DebugDirectory) {
|
|
LogError( ErrMsg, &SymErr,NO_DEBUG_DIRECTORIES);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
}
|
|
pImageBase = (PCHAR) pDosHeader;
|
|
|
|
// Do some checks on the Debug Directories
|
|
|
|
// Debug Information is stripped, we need the misc directory to find
|
|
// out the DBG file name
|
|
if ( (pNtHeader->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) ) {
|
|
if (SymchkFlag & ERROR_IF_SPLIT) {
|
|
// Image is split, log error and continue;
|
|
LogError( ErrMsg, &SymErr,ERROR_IF_SPLIT);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
} else if (SymchkFlag & IGNORE_IF_SPLIT ) {
|
|
// Image is split, don't check the symbols
|
|
LogError( ErrMsg, &SymErr,IGNORE_IF_SPLIT);
|
|
SymbolsOK = TRUE;
|
|
__leave;
|
|
}
|
|
|
|
// Get the MISC entry
|
|
i=0;
|
|
while ( (i<NumberOfDebugDirectories) &&
|
|
((DebugDirectory+i)->Type != IMAGE_DEBUG_TYPE_MISC) ) i++;
|
|
|
|
if (i >= NumberOfDebugDirectories) {
|
|
LogError( ErrMsg, &SymErr,NO_MISC_ENTRY);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
szMiscFileName = NULL;
|
|
szMiscFileName = GetMiscFile(pImageBase,DebugDirectory + i);
|
|
if (!szMiscFileName) {
|
|
LogError( ErrMsg, &SymErr,NO_FILE_IN_MISC);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
}
|
|
|
|
// Debug info is stripped.
|
|
// First, locate the correct DBG file
|
|
rc = SearchForSymbolFile (
|
|
szSearchPath,
|
|
szMiscFileName,
|
|
ext+1, // Extension of the image
|
|
&SymErr,
|
|
DBGSYM,
|
|
(PVOID)&FileInfo,
|
|
szDbgFileName,
|
|
dwDbgFileNameLength,
|
|
szRSDSDllToLoad );
|
|
|
|
if (!rc) {
|
|
LogDbgError(ErrMsg, &SymErr);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
} else if ( hSymCDLog != NULL) {
|
|
AddToSymbolsCDLog( hSymCDLog, &SymErr, SymErr.szSymbolFileName, ext+1);
|
|
}
|
|
|
|
pDbgHeader = NULL;
|
|
pDbgHeader = MapDbgHeader(szDbgFileName,&DbgFile, &SymErr);
|
|
if (!pDbgHeader) {
|
|
SymbolsOK = FALSE;
|
|
// 0 means info is inside of SymErr
|
|
LogError(ErrMsg, &SymErr,0);
|
|
__leave;
|
|
}
|
|
|
|
DebugDirectory = NULL;
|
|
DebugDirectory = GetDebugDirectoryInDbg(
|
|
pDbgHeader,
|
|
&NumberOfDebugDirectories
|
|
);
|
|
if (!DebugDirectory) {
|
|
LogError( ErrMsg, &SymErr,NO_DEBUG_DIRECTORIES_IN_DBG_HEADER);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
}
|
|
pImageBase = (PCHAR)pDbgHeader;
|
|
}
|
|
|
|
// Image is not split
|
|
else {
|
|
|
|
// VC 6 compiler always produces non-split images.
|
|
// Check the debug directories to determine if this is a VC 6 image.
|
|
|
|
RawDataFound = FALSE;
|
|
CVFound = FALSE;
|
|
MiscFound = FALSE;
|
|
for ( i=0; i< NumberOfDebugDirectories; i++ ) {
|
|
pDbgDir = DebugDirectory + i;
|
|
switch (pDbgDir->Type) {
|
|
case IMAGE_DEBUG_TYPE_MISC:
|
|
MiscFound = TRUE;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
CVFound = TRUE;
|
|
break;
|
|
|
|
default:
|
|
// Nothing except the CV entry should point to raw data
|
|
if ( pDbgDir->SizeOfData != 0 ) {
|
|
RawDataFound = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !MiscFound && CVFound ) {
|
|
|
|
// This is using the 6.0 linker. It does not
|
|
// need to be split into iamge + dbg, so don't
|
|
// give an error for it, unless there is another
|
|
// debug directory with a non-null pointer to raw data.
|
|
|
|
if ( RawDataFound ) {
|
|
LogError( ErrMsg, &SymErr, EXTRA_RAW_DATA_IN_6);
|
|
return ( FALSE);
|
|
} else {
|
|
// Continue - image should not be split
|
|
}
|
|
} else {
|
|
DWORD CertificateSize;
|
|
PVOID pCertificates = ImageDirectoryEntryToData(
|
|
(PVOID)pDosHeader,
|
|
FALSE,
|
|
IMAGE_DIRECTORY_ENTRY_SECURITY,
|
|
&CertificateSize
|
|
);
|
|
if ( pCertificates ) {
|
|
// Image is signed and non-split
|
|
// It should be split before it is signed
|
|
LogError( ErrMsg, &SymErr, SIGNED_AND_NON_SPLIT);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
} else if (SymchkFlag & ERROR_IF_NOT_SPLIT) {
|
|
// Image isn't split, log error and continue;
|
|
LogError( ErrMsg, &SymErr,ERROR_IF_NOT_SPLIT);
|
|
SymbolsOK = FALSE;
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
// File with the DBG info is the original image file name
|
|
// This line may not be necessary.
|
|
_tcscpy( SymErr.szSymbolFileName, szFileName );
|
|
}
|
|
|
|
CVFound = FALSE;
|
|
// Process the Debug Directories
|
|
for ( i=0; i<NumberOfDebugDirectories; i++) {
|
|
pDbgDir = DebugDirectory + i;
|
|
switch (pDbgDir->Type) {
|
|
|
|
// Don't need to process entry since directory table has
|
|
// already been located.
|
|
case IMAGE_DEBUG_TYPE_MISC: break;
|
|
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
CVFound = TRUE;
|
|
if ( !VerifyCV(
|
|
szFileName,
|
|
pImageBase,
|
|
pDbgDir,
|
|
ext+1,
|
|
szSearchPath,
|
|
&SymErr,
|
|
szRSDSDllToLoad
|
|
)
|
|
) {
|
|
LogPdbError(ErrMsg, &SymErr);
|
|
SymbolsOK = FALSE;
|
|
} else if (hSymCDLog != NULL && _tcscmp(SymErr.szPdbFileName, "") ) {
|
|
// Copy SymErr.szPdbFileName to Symbol Dest\ext
|
|
AddToSymbolsCDLog( hSymCDLog, &SymErr, SymErr.szPdbFileName, ext+1 );
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
if (!CVFound && CheckCodeView ) {
|
|
SymErr.ErrNo = NO_CODE_VIEW;
|
|
LogPdbError(ErrMsg, &SymErr);
|
|
SymbolsOK=FALSE;
|
|
}
|
|
} __finally {
|
|
UnmapFile((LPCVOID)pDbgHeader,DbgFile);
|
|
UnmapFile((LPCVOID)pDosHeader,DosFile);
|
|
}
|
|
|
|
if (SymbolsOK) {
|
|
LogError( ErrMsg, &SymErr, IMAGE_PASSED );
|
|
}
|
|
return SymbolsOK;
|
|
}
|
|
|
|
|
|
PIMAGE_DOS_HEADER
|
|
MapFileHeader (
|
|
LPTSTR szFileName,
|
|
PHANDLE phFile,
|
|
PSYM_ERR pSymErr
|
|
)
|
|
|
|
{
|
|
|
|
/*
|
|
Creates a file mapping and returns Handle for the DOS_HEADER
|
|
If the file does not have a DOS_HEADER, then it returns NULL.
|
|
|
|
|
|
*/
|
|
HANDLE hFileMap;
|
|
PIMAGE_DOS_HEADER pDosHeader;
|
|
DWORD dFileType;
|
|
BOOL rc;
|
|
|
|
|
|
// phFile map needs to be returned, so it can be closed later
|
|
(*phFile) = CreateFile( (LPCTSTR) szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (*phFile == INVALID_HANDLE_VALUE) {
|
|
pSymErr->ErrNo = CREATE_FILE_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
return(NULL);
|
|
}
|
|
|
|
hFileMap = CreateFileMapping( *phFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if ( hFileMap == INVALID_HANDLE_VALUE) {
|
|
pSymErr->ErrNo = CREATE_FILE_MAPPING_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
CloseHandle(*phFile);
|
|
return(NULL);
|
|
}
|
|
|
|
pDosHeader = (PIMAGE_DOS_HEADER) MapViewOfFile( hFileMap,
|
|
FILE_MAP_READ,
|
|
0, // high
|
|
0, // low
|
|
0 // whole file
|
|
);
|
|
|
|
rc = CloseHandle(hFileMap);
|
|
|
|
if ( !pDosHeader ) {
|
|
pSymErr->ErrNo = MAPVIEWOFFILE_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
CloseHandle(*phFile);
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Check to determine if this is an NT image (PE format)
|
|
|
|
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
pSymErr->ErrNo = NO_DOS_HEADER;
|
|
UnmapViewOfFile(pDosHeader);
|
|
CloseHandle(*phFile);
|
|
return(NULL);
|
|
}
|
|
return (pDosHeader);
|
|
}
|
|
|
|
|
|
PIMAGE_NT_HEADERS
|
|
GetNtHeader ( PIMAGE_DOS_HEADER pDosHeader,
|
|
HANDLE hDosFile,
|
|
LPTSTR szFileName,
|
|
PSYM_ERR pSymErr,
|
|
LPBY_HANDLE_FILE_INFORMATION lpFileInfo
|
|
)
|
|
{
|
|
|
|
/*
|
|
Returns the pointer the address of the NT Header. If there isn't
|
|
an NT header, it returns NULL
|
|
*/
|
|
PIMAGE_NT_HEADERS pNtHeader;
|
|
|
|
if (!GetFileInformationByHandle( hDosFile, lpFileInfo)) {
|
|
pSymErr->ErrNo = GET_FILE_INFO_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
return(NULL);
|
|
}
|
|
|
|
if ( ((ULONG)(pDosHeader->e_lfanew) & 3) != 0) {
|
|
|
|
//
|
|
// The image header is not aligned on a long boundary.
|
|
// Report this as an invalid protect mode image.
|
|
//
|
|
|
|
pSymErr->ErrNo = HEADER_NOT_ON_LONG_BOUNDARY;
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
if ((ULONG)(pDosHeader->e_lfanew) > lpFileInfo->nFileSizeLow) {
|
|
pSymErr->ErrNo = IMAGE_BIGGER_THAN_FILE;
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pDosHeader +
|
|
(ULONG)pDosHeader->e_lfanew);
|
|
|
|
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
|
|
pSymErr->ErrNo = NOT_NT_IMAGE;
|
|
return(NULL);
|
|
}
|
|
|
|
return (pNtHeader);
|
|
}
|
|
|
|
|
|
PIMAGE_SEPARATE_DEBUG_HEADER
|
|
MapDbgHeader (
|
|
LPTSTR szFileName,
|
|
PHANDLE phFile,
|
|
PSYM_ERR pSymErr
|
|
)
|
|
{
|
|
HANDLE hFileMap;
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader;
|
|
DWORD dFileType;
|
|
|
|
|
|
(*phFile) = CreateFile( (LPCTSTR) szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (*phFile == INVALID_HANDLE_VALUE) {
|
|
pSymErr->ErrNo = CREATE_FILE_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
CloseHandle(*phFile);
|
|
return(NULL);
|
|
}
|
|
|
|
hFileMap = CreateFileMapping( *phFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if ( hFileMap == INVALID_HANDLE_VALUE) {
|
|
pSymErr->ErrNo = CREATE_FILE_MAPPING_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
CloseHandle(*phFile);
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
pDbgHeader = (PIMAGE_SEPARATE_DEBUG_HEADER) MapViewOfFile( hFileMap,
|
|
FILE_MAP_READ,
|
|
0, // high
|
|
0, // low
|
|
0 // whole file
|
|
);
|
|
CloseHandle(hFileMap);
|
|
|
|
if ( !pDbgHeader ) {
|
|
pSymErr->ErrNo = MAPVIEWOFFILE_FAILED;
|
|
pSymErr->ErrNo2 = GetLastError();
|
|
_tcscpy( pSymErr->szFileName, szFileName);
|
|
UnmapFile((LPCVOID)pDbgHeader, *phFile);
|
|
return(NULL);
|
|
}
|
|
|
|
return (pDbgHeader);
|
|
}
|
|
|
|
BOOL
|
|
UnmapFile( LPCVOID phFileMap, HANDLE hFile )
|
|
{
|
|
BOOL rc;
|
|
|
|
if ((PHANDLE)phFileMap != NULL) {
|
|
FlushViewOfFile(phFileMap,0);
|
|
rc = UnmapViewOfFile( phFileMap );
|
|
if (rc == 0) {
|
|
printf("UnmapView of File failed with GetLastError=%d\n",GetLastError() );
|
|
}
|
|
}
|
|
if (hFile) {
|
|
rc = CloseHandle(hFile);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *
|
|
GetDebugDirectoryInExe(
|
|
PIMAGE_DOS_HEADER pDosHeader,
|
|
ULONG *NumberOfDebugDirectories
|
|
)
|
|
{
|
|
|
|
/* Exe is already mapped and a pointer to the base is
|
|
passed in. Find a pointer to the Debug Directories
|
|
*/
|
|
ULONG size;
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDebugDirectory = NULL;
|
|
ULONG DebugDirectorySize;
|
|
PIMAGE_SECTION_HEADER pSectionHeader;
|
|
|
|
size = sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
|
|
pDebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
|
|
ImageDirectoryEntryToDataEx (
|
|
(PVOID)pDosHeader,
|
|
FALSE,
|
|
IMAGE_DIRECTORY_ENTRY_DEBUG,
|
|
&DebugDirectorySize,
|
|
&pSectionHeader );
|
|
|
|
if (pDebugDirectory) {
|
|
(*NumberOfDebugDirectories) =
|
|
DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
return (pDebugDirectory);
|
|
} else return(NULL);
|
|
}
|
|
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *
|
|
GetDebugDirectoryInDbg(
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader,
|
|
ULONG *NumberOfDebugDirectories
|
|
)
|
|
/* Dbg is already mapped and a pointer to the base is
|
|
passed in. Returns a pointer to the Debug directories
|
|
*/
|
|
{
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDebugDirectory = NULL;
|
|
|
|
pDebugDirectory = (PIMAGE_DEBUG_DIRECTORY) ((PCHAR)pDbgHeader +
|
|
sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
|
|
pDbgHeader->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
|
|
pDbgHeader->ExportedNamesSize);
|
|
|
|
if (!pDebugDirectory) {
|
|
return(NULL);
|
|
}
|
|
|
|
(*NumberOfDebugDirectories) = pDbgHeader->DebugDirectorySize /
|
|
sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
return (pDebugDirectory);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
VerifyCV(
|
|
LPTSTR szFileName,
|
|
PCHAR pImageBase,
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDbgDir,
|
|
LPTSTR szExtPath,
|
|
LPTSTR szSearchPath,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szRSDSDllToLoad
|
|
)
|
|
|
|
{
|
|
TCHAR szFName[_MAX_FNAME];
|
|
TCHAR szExt[_MAX_EXT];
|
|
TCHAR szPdbFileName[_MAX_PATH*sizeof(TCHAR)];
|
|
DWORD dwPdbFileNameLength = _MAX_PATH;
|
|
BOOL rc;
|
|
|
|
|
|
PCVDD pDebugCV = (PCVDD) (pImageBase +
|
|
pDbgDir->PointerToRawData );
|
|
|
|
// Initialize pSymErr
|
|
pSymErr->PdbFileFound = FALSE;
|
|
pSymErr->PdbValid = FALSE;
|
|
_tcscpy(pSymErr->szPdbErr,_T("") );
|
|
_tcscpy(pSymErr->szPdbFileName,_T("") );
|
|
|
|
switch (pDebugCV->dwSig)
|
|
{
|
|
|
|
case '05BN':
|
|
// CVpack failed
|
|
// Symbols are not OK
|
|
_tcscpy(pSymErr->szPdbErr,_T("Codeview type is NB05") );
|
|
return (FALSE);
|
|
break;
|
|
case '90BN':
|
|
// For NB09 and NB11, the codeview info is in the image file
|
|
// Thus, no need to locate symbols. They are probably OK.
|
|
return(TRUE);
|
|
break;
|
|
case '11BN':
|
|
return(TRUE);
|
|
break;
|
|
case '01BN':
|
|
// Symbols are type NB10
|
|
// Locate the PDB information
|
|
|
|
rc = SearchForSymbolFile (
|
|
szSearchPath,
|
|
pDebugCV->nb10i.szPdb, // File Name
|
|
szExtPath,
|
|
pSymErr,
|
|
PDBSYM,
|
|
(PVOID)pDebugCV,
|
|
szPdbFileName,
|
|
dwPdbFileNameLength,
|
|
szRSDSDllToLoad
|
|
);
|
|
if (rc ) {
|
|
// SearchForSymbolFile already gave pSymErr->szPdbFilename its value
|
|
return TRUE;
|
|
} else {
|
|
_tsplitpath(pDebugCV->nb10i.szPdb,NULL,NULL,szFName,szExt);
|
|
_tcscpy(pSymErr->szPdbFileName,szFName);
|
|
_tcscat(pSymErr->szPdbFileName,szExt);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case 'SDSR':
|
|
rc = SearchForSymbolFile (
|
|
szSearchPath,
|
|
pDebugCV->rsdsi.szPdb, // File Name
|
|
szExtPath,
|
|
pSymErr,
|
|
PDBSYM,
|
|
(PVOID)pDebugCV,
|
|
szPdbFileName,
|
|
dwPdbFileNameLength,
|
|
szRSDSDllToLoad
|
|
);
|
|
if (rc ) {
|
|
// SearchForSymbolFile already gave pSymErr->szPdbFilename its value
|
|
return TRUE;
|
|
} else {
|
|
_tsplitpath(pDebugCV->rsdsi.szPdb,NULL,NULL,szFName,szExt);
|
|
_tcscpy(pSymErr->szPdbFileName,szFName);
|
|
_tcscat(pSymErr->szPdbFileName,szExt);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
_tcscpy(pSymErr->szPdbErr,
|
|
_T("Codeview info is not NB09, NB10, or NB11\n") );
|
|
return(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
LPSTR
|
|
GetMiscFile(
|
|
PCHAR pImageBase,
|
|
IMAGE_DEBUG_DIRECTORY UNALIGNED *pDbgDir
|
|
)
|
|
|
|
{
|
|
PIMAGE_DEBUG_MISC pDebugMisc;
|
|
LPSTR szData;
|
|
|
|
// Nothing to verify, but here is how to get to the DBG entry
|
|
// Get the debug directory
|
|
|
|
pDebugMisc = (PIMAGE_DEBUG_MISC)(pImageBase +
|
|
pDbgDir->PointerToRawData );
|
|
szData = (LPSTR) &pDebugMisc->Data[0];
|
|
return(szData);
|
|
}
|
|
|
|
|
|
BOOL SearchForSymbolFile ( LPTSTR szSearchPath, // ; separated search path
|
|
LPTSTR szSymName, // Symbol File to search for
|
|
LPTSTR szPathExt, // Extension directory
|
|
PSYM_ERR pSymErr,
|
|
DWORD dSymType,
|
|
PVOID pelem1,
|
|
LPTSTR szResult,
|
|
DWORD dwResultLength,
|
|
LPTSTR szRSDSDllToLoad
|
|
)
|
|
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
For each symbol path in szSearchPath, this function looks in the path
|
|
and in the path concatenated with the szPathExt subdirectory.
|
|
|
|
Arguments:
|
|
szSearchPath ; separated symbol path
|
|
|
|
szSymName Symbol file to search for
|
|
|
|
szPathExt Extension for the image that the symbol file matches
|
|
|
|
pSymErr Error structure
|
|
|
|
dSymType Type of symbol. Possible values: DBGSYM, PDBSYM
|
|
|
|
pelem1 Pointer to structure needed for comparing the symbols
|
|
|
|
szResult OUT Filename returned
|
|
dwResultLength IN Length of szResult
|
|
|
|
|
|
Return Value:
|
|
If the symbol file is found and verifies, it returns the full path and
|
|
name of the symbol file. Otherwise, it returns NULL.
|
|
|
|
--*/
|
|
|
|
TCHAR szTmpSearchPath[_MAX_PATH];
|
|
TCHAR szExtPath[_MAX_PATH];
|
|
TCHAR szFName[_MAX_FNAME];
|
|
TCHAR szExt[_MAX_EXT];
|
|
|
|
LPTSTR szResultFileName;
|
|
LPTSTR seps = _T(";");
|
|
LPTSTR szCurPath;
|
|
DWORD FoundLength;
|
|
DWORD CurLen, ExtLen;
|
|
|
|
_tcscpy( szResult,_T("") );
|
|
|
|
// Make a copy of szSearchPath because tcstok alters it
|
|
_tcscpy(szTmpSearchPath,(LPCTSTR)szSearchPath);
|
|
|
|
// Strip FileName from its path
|
|
_tsplitpath(szSymName, NULL, NULL, szFName, szExt);
|
|
_tcscat(szFName, szExt);
|
|
|
|
// Try each search path
|
|
szCurPath = _tcstok(szTmpSearchPath,seps);
|
|
|
|
while ( szCurPath != NULL ) {
|
|
|
|
FoundLength = SearchPath( szCurPath,
|
|
szFName,
|
|
NULL,
|
|
dwResultLength,
|
|
szResult,
|
|
&szResultFileName
|
|
);
|
|
if (FoundLength > 0 && FoundLength < dwResultLength) {
|
|
|
|
switch ( dSymType ) {
|
|
case DBGSYM:
|
|
// Status info, a match was found
|
|
pSymErr->SymbolFileFound = TRUE;
|
|
_tcscpy(pSymErr->szSymbolFileName, szResult);
|
|
|
|
// Validate the DBG file
|
|
if ( CompDbg(pelem1, szResult, pSymErr) ) {
|
|
return (TRUE);
|
|
}
|
|
break;
|
|
|
|
case PDBSYM:
|
|
// Status info, a match was found
|
|
pSymErr->PdbFileFound = TRUE;
|
|
_tcscpy(pSymErr->szPdbFileName, szResult);
|
|
|
|
// Validate the PDB file
|
|
if ( CompPdb(pelem1, szResult, pSymErr, szRSDSDllToLoad) ) {
|
|
return (TRUE);
|
|
}
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// Now try the path with szPathExt at the end of it
|
|
// Don't try it if current path already has the extension
|
|
// at the end of it
|
|
CurLen = _tcslen(szCurPath);
|
|
ExtLen = _tcslen(szPathExt);
|
|
|
|
if ( _tcscmp ( (szCurPath + CurLen - ExtLen), szPathExt ) ) {
|
|
|
|
_tcscpy(szExtPath, szCurPath);
|
|
_tcscat(szExtPath, _T("\\") );
|
|
_tcscat(szExtPath, szPathExt);
|
|
|
|
FoundLength = SearchPath( szExtPath,
|
|
szFName,
|
|
NULL,
|
|
dwResultLength,
|
|
szResult,
|
|
&szResultFileName
|
|
);
|
|
if (FoundLength > 0 && FoundLength < dwResultLength) {
|
|
switch ( dSymType ) {
|
|
case DBGSYM:
|
|
// Status info, a match was found
|
|
pSymErr->SymbolFileFound = TRUE;
|
|
_tcscpy(pSymErr->szSymbolFileName, szResult);
|
|
|
|
// Validate the DBG file
|
|
if ( CompDbg(pelem1, szResult, pSymErr) ) {
|
|
return (TRUE);
|
|
}
|
|
break;
|
|
case PDBSYM:
|
|
// Status info, a match was found
|
|
pSymErr->PdbFileFound = TRUE;
|
|
_tcscpy(pSymErr->szPdbFileName, szResult);
|
|
|
|
// Validate the PDB file
|
|
if ( CompPdb(pelem1, szResult, pSymErr, szRSDSDllToLoad) ) {
|
|
return (TRUE);
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
szCurPath = _tcstok(NULL,seps);
|
|
}
|
|
|
|
// Symbol wasn't found. Put name of file into SymErr for error message
|
|
switch ( dSymType ) {
|
|
case DBGSYM:
|
|
_tcscpy(pSymErr->szSymbolFileName,szFName);
|
|
break;
|
|
case PDBSYM:
|
|
_tcscpy(pSymErr->szPdbFileName, szFName);
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
USHORT
|
|
__cdecl
|
|
CompDbg(
|
|
PVOID pelem1,
|
|
LPTSTR szSymName,
|
|
PSYM_ERR pSymErr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Validates the DBG against the original image
|
|
|
|
Return Value:
|
|
TRUE - DBG matches
|
|
FALSE - DBG doesn't match timedatestamp and checksum
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PFILE_INFO pFileInfo;
|
|
PIMAGE_SEPARATE_DEBUG_HEADER pDbgHeader;
|
|
HANDLE hFile;
|
|
|
|
pFileInfo = (PFILE_INFO)(pelem1);
|
|
pDbgHeader = MapDbgHeader ( szSymName, &hFile, pSymErr );
|
|
|
|
if (pDbgHeader == NULL) {
|
|
printf("ERROR: CompDbg(), %s was not opened successfully\n",szSymName);
|
|
UnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return FALSE;
|
|
}
|
|
if (pDbgHeader->Signature != IMAGE_SEPARATE_DEBUG_SIGNATURE) {
|
|
printf("ERROR: CompDbg(), %s doesn't have Debug signature in header\n", szSymName);
|
|
UnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return FALSE;
|
|
}
|
|
|
|
// Record specifics of whether timedatestamp and checksum matched
|
|
if ( pDbgHeader->SizeOfImage == pFileInfo->SizeOfImage ) {
|
|
pSymErr->SizeOfImageMatch = TRUE;
|
|
} else pSymErr->SizeOfImageMatch = FALSE;
|
|
|
|
if ( pDbgHeader->TimeDateStamp == pFileInfo->TimeDateStamp ) {
|
|
pSymErr->TimeDateStampsMatch = TRUE;
|
|
} else pSymErr->TimeDateStampsMatch = FALSE;
|
|
|
|
if ( pDbgHeader->CheckSum == pFileInfo->CheckSum ) {
|
|
pSymErr->CheckSumsMatch = TRUE;
|
|
} else pSymErr->CheckSumsMatch = FALSE;
|
|
|
|
// Just check the timedatestamp for determining if the DBG matches
|
|
// VC and KD don't pay attention to the checksum anymore.
|
|
if ( pSymErr->TimeDateStampsMatch &&
|
|
pSymErr->SizeOfImageMatch &&
|
|
( !LogCheckSumErrors || pSymErr->CheckSumsMatch ) ) {
|
|
UnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return TRUE;
|
|
} else {
|
|
UnmapFile((LPCVOID)pDbgHeader, hFile);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
USHORT
|
|
__cdecl
|
|
CompPdb(
|
|
PVOID pelem1,
|
|
LPTSTR szSymName,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szRSDSDllToLoad
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Validates the PDB
|
|
|
|
Return Value:
|
|
TRUE PDB validates
|
|
FALSE PDB doesn't validate
|
|
--*/
|
|
|
|
{
|
|
|
|
PCVDD pPdbInfo;
|
|
WCHAR wszSymName[_MAX_PATH + 1];
|
|
|
|
BOOL valid=FALSE;
|
|
PDB *pdb;
|
|
EC ec;
|
|
char szError[cbErrMax] = _T("");
|
|
wchar_t wszError[cbErrMax] = L"";
|
|
DBI *pdbi;
|
|
HMODULE hDll;
|
|
|
|
pdb=NULL;
|
|
pPdbInfo = (PCVDD)(pelem1);
|
|
|
|
switch (pPdbInfo->dwSig)
|
|
{
|
|
case '01BN':
|
|
__try
|
|
{
|
|
valid = PDBOpenValidate(szSymName,
|
|
NULL,
|
|
_T("r"),
|
|
pPdbInfo->nb10i.sig,
|
|
pPdbInfo->nb10i.age,
|
|
&ec,
|
|
szError,
|
|
&pdb
|
|
);
|
|
|
|
if ( !valid ) {
|
|
pSymErr->PdbValid = FALSE;
|
|
__leave;
|
|
} else pSymErr->PdbValid = TRUE;
|
|
|
|
|
|
if (!CheckPrivate) {
|
|
PDBClose(pdb);
|
|
__leave;
|
|
}
|
|
|
|
// Verify that private information is stripped
|
|
// Verify that line information is removed
|
|
|
|
if ( !PDBOpenDBI(pdb, pdbRead, NULL, &pdbi) ) {
|
|
// OpenDBI failed
|
|
pSymErr->PdbValid = FALSE;
|
|
pSymErr->ErrNo = PDB_MAY_BE_CORRUPT;
|
|
DBIClose(pdbi);
|
|
__leave;
|
|
}
|
|
|
|
if ( !PDBPrivateStripped(pdb, pdbi) ) {
|
|
//Error - Source line info is not stripped
|
|
pSymErr->PdbValid = FALSE;
|
|
pSymErr->ErrNo = PRIVATE_INFO_NOT_REMOVED;
|
|
}
|
|
|
|
DBIClose(pdbi);
|
|
PDBClose(pdb);
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
pSymErr->PdbValid = FALSE;
|
|
valid=FALSE;
|
|
}
|
|
|
|
return (USHORT)pSymErr->PdbValid;
|
|
break;
|
|
|
|
case 'SDSR':
|
|
|
|
#if defined(use_SymutilX)
|
|
if ( !RSDSLibLoaded ) {
|
|
hDll = LoadLibrary( szRSDSDllToLoad );
|
|
if (hDll != NULL) {
|
|
RSDSLibLoaded = TRUE;
|
|
pPDBOpenValidate4 = ( PPDBOPENVALIDATE4 ) GetProcAddress( hDll, "PDBOpenValidate4" );
|
|
if (pPDBOpenValidate4 == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBOpenValidate4");
|
|
return (FALSE);
|
|
}
|
|
pPDBClose = ( PPDBCLOSE ) GetProcAddress( hDll, "PDBClose" );
|
|
if (pPDBClose == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBClose");
|
|
return (FALSE);
|
|
}
|
|
} else {
|
|
if (_tcslen(szRSDSDllToLoad) + _tcslen("Cannot load ") + 1 < MAX_PDB_ERR ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load ");
|
|
_tcscat(pSymErr->szPdbErr, szRSDSDllToLoad);
|
|
} else {
|
|
pSymErr->ErrNo = CANNOT_LOAD_RSDS;
|
|
}
|
|
pSymErr->PdbValid = FALSE;
|
|
return (FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ansi2wcs(szSymName, wszSymName, lengthof(wszSymName));
|
|
|
|
__try
|
|
{
|
|
#if defined(use_SymutilX)
|
|
valid = pPDBOpenValidate4(wszSymName,
|
|
#else
|
|
valid = PDBOpenValidate4(wszSymName,
|
|
#endif
|
|
_T("r"),
|
|
(PCSIG70) &(pPdbInfo->rsdsi.guidSig),
|
|
0,
|
|
(AGE) pPdbInfo->rsdsi.age,
|
|
&ec,
|
|
wszError,
|
|
cbErrMax,
|
|
&pdb
|
|
);
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
valid = FALSE;
|
|
}
|
|
|
|
if ( !valid ) {
|
|
pSymErr->PdbValid = FALSE;
|
|
|
|
return FALSE;
|
|
} else pSymErr->PdbValid = TRUE;
|
|
|
|
|
|
if (!CheckPrivate) {
|
|
#if defined(use_SymutilX)
|
|
pPDBClose(pdb);
|
|
#else
|
|
PDBClose(pdb);
|
|
#endif
|
|
return (USHORT)pSymErr->PdbValid;
|
|
}
|
|
|
|
// Verify that private information is stripped
|
|
// Verify that line information is removed
|
|
|
|
#if defined(use_SymutilX)
|
|
if ( pDBIQueryNextMod == NULL ) {
|
|
pDBIQueryNextMod = ( PDBIQUERYNEXTMOD ) GetProcAddress( hDll, "DBIQueryNextMod" );
|
|
if (pPDBOpenValidate4 == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBClose, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pModClose == NULL ) {
|
|
pModClose = ( PMODCLOSE ) GetProcAddress( hDll, "ModClose" );
|
|
if (pModClose == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBClose, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pModQueryLines == NULL ) {
|
|
pModQueryLines = ( PMODQUERYLINES ) GetProcAddress( hDll, "ModQueryLines" );
|
|
if (pModQueryLines == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load ModQueryLines, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pModQuerySymbols == NULL ) {
|
|
pModQuerySymbols = ( PMODQUERYSYMBOLS ) GetProcAddress( hDll, "ModQuerySymbols" );
|
|
if (pModQuerySymbols == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load ModQuerySymbols, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pDBIQueryTypeServer == NULL ) {
|
|
pDBIQueryTypeServer = ( PDBIQUERYTYPESERVER ) GetProcAddress( hDll, "DBIQueryTypeServer" );
|
|
if (pDBIQueryTypeServer == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load DBIQueryTypeServer, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pPDBOpenTpi == NULL ) {
|
|
pPDBOpenTpi = ( PPDBOPENTPI ) GetProcAddress( hDll, "PDBOpenTpi" );
|
|
if (pPDBOpenTpi == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBOpenTpi, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pTypesQueryTiMinEx == NULL ) {
|
|
pTypesQueryTiMinEx = ( PTYPESQUERYTIMINEX ) GetProcAddress( hDll, "TypesQueryTiMinEx" );
|
|
if (pTypesQueryTiMinEx == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load TypesQueryTiMinEx, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pTypesQueryTiMacEx == NULL ) {
|
|
pTypesQueryTiMacEx = ( PTYPESQUERYTIMACEX ) GetProcAddress( hDll, "TypesQueryTiMacEx" );
|
|
if (pTypesQueryTiMacEx == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load TypesQueryTiMacEx, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pTypesClose == NULL ) {
|
|
pTypesClose = ( PTYPESCLOSE ) GetProcAddress( hDll, "TypesClose" );
|
|
if (pTypesClose == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load TypesClose, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pPDBOpenDBI == NULL ) {
|
|
pPDBOpenDBI = ( PPDBOPENDBI ) GetProcAddress( hDll, "PDBOpenDBI" );
|
|
if (pPDBOpenDBI == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load PDBOpenDBI, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( pDBIClose == NULL ) {
|
|
pDBIClose = ( PDBICLOSE ) GetProcAddress( hDll, "DBIClose" );
|
|
if (pDBIClose == NULL ) {
|
|
_tcscpy(pSymErr->szPdbErr,"Cannot load DBIClose, GetProcAddress failed.");
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
if ( !pPDBOpenDBI(pdb, pdbRead, NULL, &pdbi) ) {
|
|
// OpenDBI failed
|
|
pSymErr->ErrNo = PDB_MAY_BE_CORRUPT;
|
|
pDBIClose(pdbi);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !PDBPrivateStrippedX(pdb, pdbi) ) {
|
|
//Error - Source line info is not stripped
|
|
pSymErr->PdbValid = FALSE;
|
|
pSymErr->ErrNo = PRIVATE_INFO_NOT_REMOVED;
|
|
}
|
|
|
|
pDBIClose(pdbi);
|
|
pPDBClose(pdb);
|
|
return (USHORT)pSymErr->PdbValid;
|
|
break;
|
|
#else
|
|
if ( !PDBOpenDBI(pdb, pdbRead, NULL, &pdbi) ) {
|
|
// OpenDBI failed
|
|
pSymErr->ErrNo = PDB_MAY_BE_CORRUPT;
|
|
DBIClose(pdbi);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !PDBPrivateStripped(pdb, pdbi) ) {
|
|
//Error - Source line info is not stripped
|
|
pSymErr->PdbValid = FALSE;
|
|
pSymErr->ErrNo = PRIVATE_INFO_NOT_REMOVED;
|
|
}
|
|
|
|
DBIClose(pdbi);
|
|
PDBClose(pdb);
|
|
return (USHORT)pSymErr->PdbValid;
|
|
break;
|
|
|
|
#endif
|
|
|
|
default: break;
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ResourceOnlyDll(
|
|
PVOID pImageBase,
|
|
BOOLEAN bMappedAsImage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns true if the image is a resource only dll.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PVOID pExports, pImports, pResources;
|
|
DWORD dwExportSize, dwImportSize, dwResourceSize;
|
|
BOOL fResourceOnlyDll;
|
|
|
|
pExports = ImageDirectoryEntryToData(pImageBase,
|
|
bMappedAsImage,
|
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
|
&dwExportSize);
|
|
|
|
pImports = ImageDirectoryEntryToData(pImageBase,
|
|
bMappedAsImage,
|
|
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
|
&dwImportSize);
|
|
|
|
pResources = ImageDirectoryEntryToData(pImageBase,
|
|
bMappedAsImage,
|
|
IMAGE_DIRECTORY_ENTRY_RESOURCE,
|
|
&dwResourceSize);
|
|
|
|
if (pResources && dwResourceSize &&
|
|
!pImports && !dwImportSize &&
|
|
!pExports && !dwExportSize) {
|
|
return (TRUE);
|
|
} else {
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
LogError(
|
|
LPTSTR ErrMsg,
|
|
PSYM_ERR pSymErr,
|
|
UINT ErrNo )
|
|
{
|
|
|
|
TCHAR szFName[_MAX_FNAME];
|
|
TCHAR szExt[_MAX_EXT];
|
|
TCHAR szCurName[_MAX_FNAME];
|
|
|
|
|
|
if (pSymErr->ErrNo != 0) ErrNo = pSymErr->ErrNo;
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szCurName,szFName);
|
|
_tcscat(szCurName,szExt);
|
|
|
|
_tcscpy(ErrMsg,_T(""));
|
|
|
|
// See if this is a file that we aren't supposed to report errors
|
|
// for. If it is, just return without writing an error.
|
|
|
|
if ( pErrorFilterList != NULL ) {
|
|
if ( InExcludeList( szCurName, pErrorFilterList ) ) {
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
switch (ErrNo) {
|
|
case NO_DEBUG_DIRECTORIES:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Built with no debugging information\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case NO_DEBUG_DIRECTORIES_IN_DBG_HEADER:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Image header has no debugging information\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case NO_MISC_ENTRY:
|
|
_stprintf(ErrMsg, "%-20s FAILED - No MISC entry in debug directories\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case NO_FILE_IN_MISC:
|
|
_stprintf(ErrMsg, "%-20s FAILED - MISC entry contains no .dbg file information\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case ERROR_IF_SPLIT:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Image points to a .DBG symbol file - fix with dbgtopdb.exe\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case ERROR_IF_NOT_SPLIT:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Image contains .DBG file data - fix with dbgtopdb.exe\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case EXTRA_RAW_DATA_IN_6:
|
|
_stprintf(ErrMsg, "%-20s FAILED - No misc entry, but debug directories point to non-Codeview data\n",
|
|
szCurName );
|
|
return (TRUE);
|
|
|
|
case IGNORE_IF_SPLIT:
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image is already split\n",szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
|
|
case NO_CODE_VIEW:
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s does not have a pointer to CodeView information\n",
|
|
szCurName, pSymErr->szSymbolFileName);
|
|
return(TRUE);
|
|
|
|
case FILE_NOT_FOUND:
|
|
_stprintf(ErrMsg, "%-20s FAILED - File does not exist\n",szCurName);
|
|
return(TRUE);
|
|
|
|
case CREATE_FILE_FAILED :
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image is not a valid NT image.\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case CREATE_FILE_MAPPING_FAILED :
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image is not a valid NT image.\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case MAPVIEWOFFILE_FAILED :
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image is not a valid NT image.\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case GET_FILE_INFO_FAILED :
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image is not a valid NT image.\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case HEADER_NOT_ON_LONG_BOUNDARY:
|
|
// Not an NT image - ignore the error
|
|
if (pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - This is either corrupt or a DOS image\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case IMAGE_BIGGER_THAN_FILE:
|
|
if (pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - This is either corrupt or a DOS image\n", szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case INVALID_ADDRESSOFRAWDATA_ZERO_DEBUG:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Invalid AddressOfRawData for zero sized debug info\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case INVALID_POINTERTORAWDATA_NON_ZERO:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Invalid PointerToRawData for non-zero sized debug info\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case INVALID_POINTERTORAWDATA_ZERO_DEBUG:
|
|
_stprintf(ErrMsg, "%-20s FAILED - Invalid PointerToRawData for zero sized debug info\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
case NO_DOS_HEADER:
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image does not have a DOS header\n",
|
|
szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case NOT_NT_IMAGE:
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Image does not have an NT header\n",
|
|
szCurName);
|
|
}
|
|
return(TRUE);
|
|
case IMAGE_PASSED :
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s PASSED \n",szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case RESOURCE_ONLY_DLL:
|
|
if ( pSymErr->Verbose) {
|
|
_stprintf(ErrMsg, "%-20s IGNORED - Resource only DLL\n",szCurName);
|
|
}
|
|
return(TRUE);
|
|
|
|
case SIGNED_AND_NON_SPLIT:
|
|
_stprintf(ErrMsg, "%-20s FAILED - It is signed and debug info can't be stripped without invalidating the signature\n",
|
|
szCurName);
|
|
return(TRUE);
|
|
|
|
default:
|
|
return(TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
LogDbgError(
|
|
LPTSTR ErrMsg,
|
|
PSYM_ERR pSymErr
|
|
)
|
|
|
|
{
|
|
|
|
TCHAR szFName[_MAX_FNAME];
|
|
TCHAR szExt[_MAX_EXT];
|
|
TCHAR szCurName[_MAX_FNAME];
|
|
TCHAR szSymName[_MAX_FNAME];
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szCurName,szFName);
|
|
_tcscat(szCurName,szExt);
|
|
|
|
_tcscpy(ErrMsg,_T("") );
|
|
|
|
// See if this is a file that we aren't supposed to report errors
|
|
// for. If it is, just return without writing an error.
|
|
|
|
if ( pErrorFilterList != NULL ) {
|
|
if ( InExcludeList( szCurName, pErrorFilterList ) ) {
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szSymbolFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szSymName,szFName);
|
|
_tcscat(szSymName,szExt);
|
|
|
|
|
|
if ( !pSymErr->SymbolFileFound ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - Image is split correctly, but %s is missing\n",
|
|
szCurName, szSymName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( LogCheckSumErrors && !pSymErr->CheckSumsMatch) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - Checksum doesn't match with %s\n",
|
|
szCurName, szSymName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( !pSymErr->SizeOfImageMatch) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - Size of image doesn't match with %s\n",
|
|
szCurName, szSymName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( !pSymErr->TimeDateStampsMatch) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - Timedate stamp doesn't match with %s\n",
|
|
szCurName, szSymName);
|
|
return(TRUE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
LogPdbError(
|
|
LPTSTR ErrMsg,
|
|
PSYM_ERR pSymErr
|
|
)
|
|
|
|
{
|
|
|
|
TCHAR szFName[_MAX_FNAME];
|
|
TCHAR szExt[_MAX_EXT];
|
|
TCHAR szCurName[_MAX_FNAME];
|
|
TCHAR szSymName[_MAX_FNAME];
|
|
TCHAR szPdbName[_MAX_FNAME];
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szCurName,szFName);
|
|
_tcscat(szCurName,szExt);
|
|
|
|
_tcscpy(ErrMsg,_T("") );
|
|
|
|
// See if this is a file that we aren't supposed to report errors
|
|
// for. If it is, just return without writing an error.
|
|
|
|
if ( pErrorFilterList != NULL ) {
|
|
if ( InExcludeList( szCurName, pErrorFilterList ) ) {
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szSymbolFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szSymName,szFName);
|
|
_tcscat(szSymName,szExt);
|
|
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szPdbFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szPdbName,szFName);
|
|
_tcscat(szPdbName,szExt);
|
|
|
|
if (pSymErr->ErrNo == NO_CODE_VIEW) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s does not point to CodeView information\n",
|
|
szCurName, szSymName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pSymErr->ErrNo == PRIVATE_INFO_NOT_REMOVED) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s contains private information\n",
|
|
szCurName, szPdbName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pSymErr->ErrNo == PDB_MAY_BE_CORRUPT) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s may be corrupt\n",
|
|
szCurName, szPdbName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pSymErr->ErrNo == CANNOT_LOAD_RSDS) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - Cannot load the RSDS dll \n",
|
|
szCurName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( _tcscmp(pSymErr->szPdbErr,_T("") ) ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s\n",szCurName, pSymErr->szPdbErr );
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( pSymErr->SymbolFileFound && !pSymErr->PdbFileFound ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s is correct, but %s is missing\n",
|
|
szCurName, szSymName, szPdbName);
|
|
return(TRUE);
|
|
}
|
|
|
|
if ( !pSymErr->PdbFileFound ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s is missing \n",szCurName,szPdbName );
|
|
return(TRUE);
|
|
}
|
|
|
|
// There was a DBG file, but PDB file didn't validate
|
|
|
|
if ( pSymErr->SymbolFileFound && !pSymErr->PdbValid ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - %s and %s signatures do not match\n",
|
|
szCurName, szSymName, szPdbName);
|
|
return(TRUE);
|
|
}
|
|
|
|
// There isn't supposed to be a DBG file. PDB doesn't validate against
|
|
// image.
|
|
|
|
if ( !pSymErr->PdbValid ) {
|
|
_stprintf(ErrMsg, "%-20s FAILED - signature does not match %s\n",
|
|
szCurName, szPdbName );
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
BOOL AddToSymbolsCDLog(
|
|
FILE *hSymCDLog,
|
|
PSYM_ERR pSymErr,
|
|
LPTSTR szSymbolPath,
|
|
LPTSTR szFileExt
|
|
)
|
|
|
|
/*
|
|
szSymbolPath is the full path and name to the symbol file
|
|
szFileExt is the extension of the image without the '.' at
|
|
the front
|
|
*/
|
|
|
|
{
|
|
|
|
LPTSTR szSrc;
|
|
LPTSTR szDest;
|
|
LPTSTR szTmp;
|
|
|
|
TCHAR szFName[_MAX_FNAME+1];
|
|
TCHAR szExt[_MAX_EXT+1];
|
|
TCHAR szCurName[_MAX_FNAME + _MAX_EXT + 1];
|
|
TCHAR szDestDir[_MAX_PATH];
|
|
TCHAR szSymName[_MAX_FNAME + 1];
|
|
TCHAR szSymExt[_MAX_EXT + 1];
|
|
|
|
// If there is a list of the files that belong on the
|
|
// CD, then only write this file to the log for the
|
|
// symbol CD if the file is in the list
|
|
//
|
|
// Originally, this was used for the international
|
|
// incremental builds.
|
|
//
|
|
if ( pCDIncludeList != NULL ) {
|
|
if ( !InList( szSymbolPath, pCDIncludeList ) ) {
|
|
return (TRUE);
|
|
}
|
|
}
|
|
|
|
// Get the file name without any path info:
|
|
_tsplitpath(pSymErr->szFileName,NULL,NULL,szFName,szExt);
|
|
_tcscpy(szCurName,szFName);
|
|
|
|
|
|
// Put the path below "binaries" as the source
|
|
szSrc = _tcsstr(szSymbolPath, _T("symbols\\") );
|
|
|
|
if (szSrc == NULL) {
|
|
printf("%s: Cannot find \"symbols\\\" in the symbol file's path\n",
|
|
szCurName);
|
|
exit(1);
|
|
}
|
|
if ( _tcscmp( szSrc, _T("symbols\\") ) == 0 ) {
|
|
printf("Symbol file name cannot end with \"symbols\\\"\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Move the Destination up to the directory after symbols. If this is
|
|
// the retail directory, don't include retail in the path.
|
|
szDest = szSrc + _tcslen(_T("symbols\\"));
|
|
|
|
if ( _tcsncmp( szDest, _T("retail\\"), _tcslen(_T("retail\\")) ) == 0 ) {
|
|
szDest = szDest + _tcslen(_T("retail\\"));
|
|
}
|
|
|
|
_tsplitpath(szDest,NULL,szDestDir,NULL,NULL);
|
|
|
|
// Remove the '\' from the end of the string;
|
|
szTmp = szDestDir + _tcslen(szDestDir) - 1;
|
|
while ( _tcscmp( szTmp, _T("\\")) == 0 ) {
|
|
_tcscpy( szTmp, _T("") );
|
|
szTmp--;
|
|
}
|
|
|
|
// get the symbol file name
|
|
_tsplitpath(szSymbolPath,NULL,NULL,szSymName,szSymExt);
|
|
|
|
RemoveDuplicateSlashes(pSymErr->szFileName);
|
|
|
|
fprintf(hSymCDLog, "%s,%s%s,%s,%s\n", pSymErr->szFileName,
|
|
szSymName,szSymExt,szSrc,szDestDir);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
|
|
P_LIST
|
|
GetList(
|
|
LPTSTR szFileName
|
|
)
|
|
|
|
{
|
|
|
|
/* GetList gets the list and keeps the original file name which could
|
|
* have included the path to the file
|
|
* Note, it can be merged with GetExcludeList. I first created it for
|
|
* use in creating the symbols CD, and didn't want to risk entering a
|
|
* bug into symchk
|
|
*/
|
|
|
|
P_LIST pList;
|
|
|
|
FILE *fFile;
|
|
TCHAR szCurFile[_MAX_FNAME+1], *c;
|
|
TCHAR fname[_MAX_FNAME+1], ext[_MAX_EXT+1];
|
|
DWORD i;
|
|
LPTSTR szEndName;
|
|
|
|
|
|
if ( (fFile = _tfopen(szFileName,_T("r") )) == NULL )
|
|
{
|
|
// printf( "Cannot open the exclude file %s\n",szFileName );
|
|
return NULL;
|
|
}
|
|
|
|
pList = (P_LIST)malloc(sizeof(LIST));
|
|
|
|
if (pList)
|
|
{
|
|
pList->dNumFiles = 0;
|
|
while ( _fgetts(szCurFile,_MAX_FNAME,fFile) )
|
|
{
|
|
if ( szCurFile[0] == ';' ) continue;
|
|
(pList->dNumFiles)++;
|
|
}
|
|
|
|
// Go back to the beginning of the file
|
|
fseek(fFile,0,0);
|
|
pList->List = (LIST_ELEM*)malloc( sizeof(LIST_ELEM) *
|
|
(pList->dNumFiles));
|
|
if (pList->List == NULL)
|
|
{
|
|
free(pList);
|
|
pList = NULL;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
while ( i < pList->dNumFiles )
|
|
{
|
|
memset(szCurFile,'\0',sizeof(TCHAR) * (_MAX_FNAME+1) );
|
|
_fgetts(szCurFile,_MAX_FNAME,fFile);
|
|
|
|
// Replace the \n with \0
|
|
c = NULL;
|
|
c = _tcschr(szCurFile, '\n');
|
|
if ( c != NULL) *c='\0';
|
|
|
|
if ( szCurFile[0] == ';' ) continue;
|
|
|
|
if ( _tcslen(szCurFile) > _MAX_FNAME ) {
|
|
printf("File %s has a string that is too large\n",szFileName);
|
|
free(pList->List);
|
|
free(pList);
|
|
fclose(fFile);
|
|
return(NULL);
|
|
}
|
|
|
|
// Allow for spaces and a ; after the file name
|
|
// Move the '\0' back until it has erased the ';' and any
|
|
// tabs and spaces that might come before it
|
|
szEndName = _tcschr(szCurFile, ';');
|
|
|
|
// Set the pointer to the last character in the string if
|
|
// there wasn't a comment
|
|
if (szEndName == NULL ) {
|
|
if (_tcslen(szCurFile) > 0 ) {
|
|
szEndName = szCurFile + _tcslen(szCurFile) - 1;
|
|
}
|
|
}
|
|
|
|
if (szEndName != NULL ) {
|
|
while ( *szEndName == ';' || *szEndName == ' '
|
|
|| *szEndName == '\t' ) {
|
|
*szEndName = '\0';
|
|
if ( szEndName > szCurFile ) szEndName--;
|
|
}
|
|
}
|
|
|
|
_tcscpy(pList->List[i].Path,szCurFile);
|
|
|
|
_tsplitpath(szCurFile,NULL,NULL,fname,ext);
|
|
|
|
_tcscpy(pList->List[i].FName,fname);
|
|
_tcscat(pList->List[i].FName,ext);
|
|
|
|
i++;
|
|
}
|
|
|
|
// Sort the List
|
|
dbg_qsort( (void*)pList->List, (size_t)pList->dNumFiles,
|
|
(size_t)sizeof(LIST_ELEM), SymComp2 );
|
|
}
|
|
}
|
|
|
|
fclose(fFile);
|
|
|
|
return (pList);
|
|
}
|
|
|
|
int __cdecl
|
|
SymComp2(
|
|
const void *e1,
|
|
const void *e2
|
|
)
|
|
{
|
|
LPTSTR p1,n1;
|
|
LPTSTR p2,n2;
|
|
int rc;
|
|
|
|
p1 = ((LIST_ELEM*)e1)->FName;
|
|
p2 = ((LIST_ELEM*)e2)->FName;
|
|
|
|
n1 = ((LIST_ELEM*)e1)->Path;
|
|
n2 = ((LIST_ELEM*)e2)->Path;
|
|
|
|
rc = _tcsicmp(p1,p2);
|
|
if (rc == 0) return ( _tcsicmp(n1,n2) );
|
|
else return (rc);
|
|
}
|
|
|
|
|
|
|
|
BOOL PDBPrivateStripped(
|
|
PDB *ppdb,
|
|
DBI *pdbi
|
|
)
|
|
{
|
|
// Return values:
|
|
// FALSE - Private Information has NOT been stripped
|
|
// TRUE - Private Information has been stripped
|
|
|
|
Mod *pmod;
|
|
Mod *prevmod;
|
|
long cb;
|
|
|
|
unsigned itsm;
|
|
TPI *ptpi;
|
|
TI tiMin;
|
|
TI tiMac;
|
|
|
|
pmod = NULL;
|
|
prevmod=NULL;
|
|
while (DBIQueryNextMod(pdbi, pmod, &pmod) && pmod) {
|
|
if (prevmod != NULL) ModClose(prevmod);
|
|
|
|
// Check that Source line info is removed
|
|
ModQueryLines(pmod, NULL, &cb);
|
|
|
|
if (cb != 0) {
|
|
ModClose(pmod);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check that local symbols are removed
|
|
ModQuerySymbols(pmod, NULL, &cb);
|
|
|
|
if (cb != 0) {
|
|
ModClose(pmod);
|
|
return FALSE;
|
|
}
|
|
prevmod=pmod;
|
|
}
|
|
if (pmod != NULL) ModClose(pmod);
|
|
if (prevmod != NULL) ModClose(prevmod);
|
|
|
|
// Check that types are removed
|
|
for ( itsm = 0; itsm < 256; itsm++) {
|
|
ptpi = 0;
|
|
if (DBIQueryTypeServer(pdbi, (ITSM) itsm, &ptpi)) {
|
|
continue;
|
|
}
|
|
if (!ptpi) {
|
|
|
|
PDBOpenTpi(ppdb, pdbRead, &ptpi);
|
|
tiMin = TypesQueryTiMinEx(ptpi);
|
|
tiMac = TypesQueryTiMacEx(ptpi);
|
|
if (tiMin < tiMac) {
|
|
TypesClose(ptpi);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
TypesClose(ptpi);
|
|
return (TRUE);
|
|
}
|
|
|
|
#if defined(use_SymutilX)
|
|
|
|
BOOL PDBPrivateStrippedX(
|
|
PDB *ppdb,
|
|
DBI *pdbi
|
|
)
|
|
{
|
|
// Return values:
|
|
// FALSE - Private Information has NOT been stripped
|
|
// TRUE - Private Information has been stripped
|
|
|
|
Mod *pmod;
|
|
Mod *prevmod;
|
|
long cb;
|
|
|
|
unsigned itsm;
|
|
TPI *ptpi;
|
|
TI tiMin;
|
|
TI tiMac;
|
|
|
|
pmod = NULL;
|
|
prevmod=NULL;
|
|
while (pDBIQueryNextMod(pdbi, pmod, &pmod) && pmod) {
|
|
if (prevmod != NULL) pModClose(prevmod);
|
|
|
|
// Check that Source line info is removed
|
|
pModQueryLines(pmod, NULL, &cb);
|
|
|
|
if (cb != 0) {
|
|
pModClose(pmod);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check that local symbols are removed
|
|
pModQuerySymbols(pmod, NULL, &cb);
|
|
|
|
if (cb != 0) {
|
|
pModClose(pmod);
|
|
return FALSE;
|
|
}
|
|
prevmod=pmod;
|
|
}
|
|
if (pmod != NULL) pModClose(pmod);
|
|
if (prevmod != NULL) pModClose(prevmod);
|
|
|
|
// Check that types are removed
|
|
for ( itsm = 0; itsm < 256; itsm++) {
|
|
ptpi = 0;
|
|
if (pDBIQueryTypeServer(pdbi, (ITSM) itsm, &ptpi)) {
|
|
continue;
|
|
}
|
|
if (!ptpi) {
|
|
|
|
pPDBOpenTpi(ppdb, pdbRead, &ptpi);
|
|
tiMin = pTypesQueryTiMinEx(ptpi);
|
|
tiMac = pTypesQueryTiMacEx(ptpi);
|
|
if (tiMin < tiMac) {
|
|
pTypesClose(ptpi);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
pTypesClose(ptpi);
|
|
return (TRUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
RemoveDuplicateSlashes(
|
|
LPTSTR Str
|
|
) {
|
|
|
|
ULONG i,j;
|
|
BOOL prev;
|
|
LPTSTR cur;
|
|
|
|
prev = FALSE; // False means the previous character was not a '\'
|
|
// True means the previous character was a '\'
|
|
|
|
j = _tcslen(Str);
|
|
if (j == 0 ) return TRUE;
|
|
cur = Str;
|
|
|
|
for (i=0; i< j; i++ ) {
|
|
if ( *(Str+i) == _T('\\') ) {
|
|
|
|
if ( prev == FALSE ) {
|
|
|
|
prev=TRUE;
|
|
*cur=*(Str+i);
|
|
cur++;
|
|
|
|
} else {
|
|
|
|
// do nothing
|
|
}
|
|
|
|
} else {
|
|
|
|
prev=FALSE;
|
|
*cur=*(Str+i);
|
|
cur++;
|
|
}
|
|
}
|
|
|
|
*cur=_T('\0');
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
ansi2wcs(
|
|
PSTR psz,
|
|
PWSTR pwsz,
|
|
DWORD pwszlen
|
|
)
|
|
{
|
|
BOOL rc;
|
|
int len;
|
|
|
|
assert(psz && pwsz);
|
|
|
|
len = strlen(psz);
|
|
if (!len)
|
|
return FALSE;
|
|
|
|
rc = MultiByteToWideChar(CP_ACP,
|
|
MB_COMPOSITE,
|
|
psz,
|
|
len,
|
|
pwsz,
|
|
pwszlen);
|
|
if (!rc)
|
|
return FALSE;
|
|
|
|
pwsz[len] = 0;
|
|
|
|
return TRUE;
|
|
}
|