|
|
#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; }
|