windows-nt/Source/XPSP1/NT/sdktools/debuggers/imagehlp/symchk.c
2020-09-26 16:20:57 +08:00

653 lines
21 KiB
C

#include "symutil.h"
typedef struct _FILE_INFO {
DWORD TimeDateStamp;
DWORD CheckSum;
TCHAR szName[MAX_PATH];
} FILE_INFO, *PFILE_INFO;
typedef struct _COMMAND_ARGS {
LPTSTR szDir; // Directory where source files exist
LPTSTR szFileName; // File name(s) to copy
FILE * hSymCDLog; // SymbolsCD log file
BOOL Recurse; // Recurse in subdirectories
LPTSTR szSymPath; // Directory where symbols exist
LPTSTR szExcludeFileName; // File name with list of files to exclude
// from symbol checking
LPTSTR szListFileName; // File containing a list of files to check
DWORD Split; // TRUE - check for split images
// FALSE - check for non-split images
BOOL Verbose; // Print info for every file checked,
// not just the ones that fail
LPTSTR szErrorFilterList; // Don't print errors for these files
LPTSTR szCDIncludeList; // Full path to symbols that should get
// written to the list that is used for creating
// the symbol CD. Originally used for
// international incremental builds
} COM_ARGS, *PCOM_ARGS;
typedef struct _FILE_COUNTS {
DWORD NumPassedFiles;
DWORD NumIgnoredFiles;
DWORD NumFailedFiles;
} FILE_COUNTS, *PFILE_COUNTS;
// Prototypes
PCOM_ARGS
GetCommandLineArgs(
int argc,
char **argv
);
VOID
Usage (
VOID
);
DWORD
CheckDirectory(
LPTSTR szDir,
LPTSTR szFName,
LPTSTR szSymPath,
FILE* hSymCDLog,
PEXCLUDE_LIST pExcludeList,
PFILE_COUNTS pFileCounts,
DWORD Split
);
DWORD
CheckAllDirectories(
LPTSTR szDir,
LPTSTR szFName,
LPTSTR szSymPath,
FILE* hSymCDLog,
PEXCLUDE_LIST pExcludeList,
PFILE_COUNTS pFileCounts,
DWORD Split
);
BOOL
CorrectPath(
LPTSTR szFileName,
LPTSTR szPathName,
LPTSTR szCorrectPath
);
// Global variables
BOOL Verbose = 0;
BOOL Retail = TRUE;
int
_cdecl
main( int argc, char **argv)
{
PCOM_ARGS pArgs;
DWORD NumBadFiles=0;
DWORD NumExcludeFiles=0;
DWORD i;
PEXCLUDE_LIST pExcludeList = NULL;
FILE_COUNTS FileCounts;
SYM_ERR SymErr;
TCHAR ErrMsg[MAX_SYM_ERR];
HFILE hListFile;
P_LIST FileList;
pArgs = GetCommandLineArgs(argc, argv);
Verbose = (BOOL)pArgs->Verbose;
memset( &SymErr, 0, sizeof(SymErr) );
memset( &FileCounts, 0, sizeof(FILE_COUNTS) );
if ( pArgs->szExcludeFileName != NULL ) {
pExcludeList = GetExcludeList(pArgs->szExcludeFileName);
}
if ( pArgs->szErrorFilterList != NULL ) {
pErrorFilterList = GetExcludeList(pArgs->szErrorFilterList);
}
if ( pArgs->szCDIncludeList != NULL ) {
pCDIncludeList = GetList( pArgs->szCDIncludeList );
}
// This is the section for creating the symbols CD.
if ( pArgs->szListFileName != NULL ) {
FileList = GetList(pArgs->szListFileName);
if ( FileList == NULL ) {
printf(" Cannot open the file list %s\n", pArgs->szListFileName);
exit(1);
}
if ( FileList->dNumFiles == 0 ) goto finish;
// Do the first one, so we don't have to check for it inside the loop
if ( CorrectPath(FileList->List[0].FName, FileList->List[0].Path, pArgs->szDir) ) {
NumBadFiles += CheckDirectory(
pArgs->szDir,
FileList->List[0].FName,
pArgs->szSymPath,
pArgs->hSymCDLog,
pExcludeList,
&FileCounts,
pArgs->Split
);
}
for ( i=1; i< FileList->dNumFiles; i++) {
// There may be some duplicates in the list ... skip them
// Also, only check the files that are in the path given on the command line
if ( (_tcsicmp(FileList->List[i].Path, FileList->List[i-1].Path) != 0) &&
CorrectPath(FileList->List[i].FName, FileList->List[i].Path, pArgs->szDir) ) {
NumBadFiles += CheckDirectory(
pArgs->szDir,
FileList->List[i].FName,
pArgs->szSymPath,
pArgs->hSymCDLog,
pExcludeList,
&FileCounts,
pArgs->Split
);
}
}
}
else {
if ( !pArgs->Recurse ) {
NumBadFiles += CheckDirectory(
pArgs->szDir,
pArgs->szFileName,
pArgs->szSymPath,
pArgs->hSymCDLog,
pExcludeList,
&FileCounts,
pArgs->Split
);
} else {
NumBadFiles += CheckAllDirectories(
pArgs->szDir,
pArgs->szFileName,
pArgs->szSymPath,
pArgs->hSymCDLog,
pExcludeList,
&FileCounts,
pArgs->Split
);
}
// CheckDirectory just returns the number of failed and passed. If
// no files failed or passed, then report that we couldn't find the
// file.
if ( (FileCounts.NumFailedFiles + FileCounts.NumPassedFiles) == 0 ) {
_tcscpy( SymErr.szFileName, pArgs->szFileName );
SymErr.Verbose=pArgs->Verbose;
if (InExcludeList(SymErr.szFileName, pExcludeList) ) {
LogError(ErrMsg, &SymErr, IMAGE_PASSED );
FileCounts.NumPassedFiles=1;
} else {
LogError(ErrMsg, &SymErr, FILE_NOT_FOUND);
FileCounts.NumFailedFiles=1;
}
if ( _tcscmp(ErrMsg, "") != 0 ) {
printf("SYMCHK: %s",ErrMsg);
}
}
}
finish:
if (pArgs->hSymCDLog) fclose(pArgs->hSymCDLog);
free(pArgs->szDir);
free(pArgs->szFileName);
free(pArgs);
printf("\nSYMCHK: FAILED files = %d\n",FileCounts.NumFailedFiles);
printf("SYMCHK: PASSED + IGNORED files = %d\n",FileCounts.NumPassedFiles);
if ( FileCounts.NumFailedFiles > 0 ) {
return(1);
} else {
return(0);
}
}
DWORD
CheckAllDirectories(
LPTSTR szDir,
LPTSTR szFName,
LPTSTR szSymPath,
FILE* hSymCDLog,
PEXCLUDE_LIST pExcludeList,
PFILE_COUNTS pFileCounts,
DWORD Split
)
{
HANDLE hFindFile;
TCHAR szCurPath[_MAX_PATH];
BOOL Found = FALSE;
DWORD NumBadFiles=0;
WIN32_FIND_DATA FindFileData;
LPTSTR szF = NULL;
LPTSTR szE = NULL;
FILE_COUNTS FileCounts;
NumBadFiles += CheckDirectory(szDir,
szFName,
szSymPath,
hSymCDLog,
pExcludeList,
pFileCounts,
Split
);
// Look for all the subdirectories
_tcscpy(szCurPath, szDir);
_tcscat(szCurPath, _T("\\*.*") );
Found = TRUE;
hFindFile = FindFirstFile((LPCTSTR)szCurPath, &FindFileData);
if ( hFindFile == INVALID_HANDLE_VALUE) {
Found = FALSE;
}
while ( Found ) {
if ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if ( !_tcscmp(FindFileData.cFileName, _T(".")) ||
!_tcscmp(FindFileData.cFileName, _T("..")) ||
!_tcsicmp(FindFileData.cFileName, _T("symbols")) ) {
// Don't process these directories
} else {
// Get the current path that we are searching in
_tcscpy(szCurPath, szDir);
_tcscat(szCurPath, _T("\\"));
_tcscat(szCurPath, FindFileData.cFileName);
NumBadFiles += CheckAllDirectories(
szCurPath,
szFName,
szSymPath,
hSymCDLog,
pExcludeList,
pFileCounts,
Split
);
}
}
Found = FindNextFile(hFindFile, &FindFileData);
}
FindClose(hFindFile);
return(NumBadFiles);
}
DWORD
CheckDirectory(
LPTSTR szDir,
LPTSTR szFName,
LPTSTR szSymPath,
FILE * hSymCDLog,
PEXCLUDE_LIST pExcludeList,
PFILE_COUNTS pFileCounts,
DWORD Split
)
{
HANDLE hFindFile;
TCHAR szFileName[_MAX_PATH];
TCHAR szCurPath[_MAX_PATH];
TCHAR szCurFileName[_MAX_PATH];
BOOL Found;
DWORD NumBadFiles=0;
DWORD NumGoodFiles=0;
WIN32_FIND_DATA FindFileData;
SYM_ERR SymErr;
TCHAR ErrMsg[MAX_SYM_ERR];
memset( &SymErr, 0, sizeof(SymErr) );
// Create the file name
_tcscpy(szFileName, szDir);
_tcscat(szFileName, _T("\\") );
_tcscat(szFileName, szFName);
// Get the current path that we are searching in
_tcscpy(szCurPath, szDir);
Found = TRUE;
hFindFile = FindFirstFile((LPCTSTR)szFileName, &FindFileData);
if ( hFindFile == INVALID_HANDLE_VALUE ) {
Found = FALSE;
}
while ( Found ) {
// Found a file, not a directory
if ( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
_tcscpy(szCurFileName, szCurPath);
_tcscat(szCurFileName,_T("\\") );
_tcscat(szCurFileName, FindFileData.cFileName );
// Its not in the exclude list, go ahead and test it
if (!InExcludeList(FindFileData.cFileName,pExcludeList ) ) {
if ( !CheckSymbols( ErrMsg,
szSymPath,
szCurFileName,
hSymCDLog,
Split,
Verbose,
NULL ) ) {
pFileCounts->NumFailedFiles++;
NumBadFiles++;
} else {
pFileCounts->NumPassedFiles++;
}
}
// It is in the exclude list, add it to NumPassed Files
else {
pFileCounts->NumPassedFiles++;
_tcscpy(SymErr.szFileName, szCurFileName);
SymErr.Verbose = Verbose;
LogError(ErrMsg, &SymErr, IMAGE_PASSED);
}
if ( _tcscmp(ErrMsg,"") != 0 ) {
printf("SYMCHK: %s", ErrMsg);
}
}
Found = FindNextFile(hFindFile, &FindFileData);
}
FindClose(hFindFile);
return(NumBadFiles);
}
VOID
Usage (
VOID
)
{
puts("\n"
"Usage: symchk [switches] file /s sympath \n\n"
" file Name of file(s) or directory to check.\n"
" Can include wildcards.\n\n"
" [/b] For NT4 Service Packs -- don't complain if\n"
" there is no CodeView data\n"
" [/e file] File containing a list of files to exclude.\n"
" This file can have one name per line. Comment\n"
" lines begin with a ; . \n\n"
" [/p] Check that private information is removed.\n"
" [/c dest] Create an inf for the symbols CD\n\n"
" [/r] Recurse into subdirectories. This uses the\n"
" Windows 2000 build model and assumes that the\n"
" first subdirectory to traverse into is the retail\n"
" directory. Example sympath: \"E:\\binaries\\symbols\" .\n"
" All subdirectories except \"symbols\" will be checked.\n\n"
" /s sympath symbol path delimited by ; . Checks sympath\n"
" and sympath\\ext for each string in the path, \n"
" where ext is the extension of the executable.\n\n"
" [/t] Fail if a DBG file is involved. Fails if the image points\n"
" to a dbg file or if it contains data that can be stripped\n"
" into a dbg file. Default is to fail if data can be stripped\n"
" into a dbg file, but don't fail if the image points to a\n"
" dbg file.\n\n"
" [/u] Fail if image points to a dbg file. Don't fail if image\n"
" contains data that can be split into a dbg file.\n\n"
" [/v] Give verbose information\n"
" [/x] Used with /c. Perform symbol checking on these files and\n"
" add the correct symbols to the symbol CD's inf, but\n"
" don't write error messages for the ones that are wrong.\n\n"
);
exit(1);
// The purpose of /x is to not log errors for symbols in symbad.txt. However, symchk
// should check all of the files in symbad.txt when it is creating the list of file
// in case some of them actually have correct symbols and symbad hasn't been updated yet.
}
PCOM_ARGS
GetCommandLineArgs(
int argc,
char **argv
)
{
PCOM_ARGS pArgs;
int i,cur,length;
TCHAR c;
BOOL NeedSecond = FALSE;
BOOL Exclude = FALSE;
LPTSTR szFileArg = NULL;
TCHAR szDrive[_MAX_DRIVE + 1];
TCHAR szDir[_MAX_DIR + 1];
TCHAR szFileName[_MAX_FNAME + 1];
TCHAR szExt[_MAX_EXT + 1];
TCHAR szNameExt[_MAX_FNAME + _MAX_EXT + 1];
LPTSTR szSymCDLog = NULL;
LPTSTR szSymbolsCDFile = NULL;
HANDLE fHandle;
WIN32_FIND_DATA FindFileData;
if (argc == 1) Usage();
if (!(pArgs = (PCOM_ARGS)malloc(sizeof(COM_ARGS))))
{
printf("No memory");
exit(1);
}
memset( pArgs, 0, sizeof(COM_ARGS) );
pArgs->Split = 0;
pArgs->szListFileName = NULL;
pArgs->szCDIncludeList = NULL;
CheckPrivate = FALSE;
for (i=1; i<argc; i++) {
if (!NeedSecond) {
if ( (argv[i][0] == '/') || (argv[i][0] == '-') ) {
length = _tcslen(argv[i]) -1;
for (cur=1; cur <= length; cur++) {
c = argv[i][cur];
switch (c) {
case 'c': NeedSecond = TRUE;
break;
case 'b': CheckCodeView=FALSE;
NeedSecond = FALSE;
break;
case 'e': Exclude = TRUE;
NeedSecond = TRUE;
if ( length > cur) Usage();
break;
case 'l': NeedSecond = TRUE;
break;
case 'p': NeedSecond = FALSE;
CheckPrivate = TRUE;
break;
case 'r': pArgs->Recurse = TRUE;
Recurse = TRUE;
break;
case 's': NeedSecond = TRUE;
if ( length > cur) Usage();
break;
case 't':
pArgs->Split |= ERROR_IF_NOT_SPLIT;
pArgs->Split |= ERROR_IF_SPLIT;
break;
case 'u': pArgs->Split |= ERROR_IF_SPLIT;
break;
case 'v': pArgs->Verbose = TRUE;
break;
case 'x': NeedSecond = TRUE;
break;
case 'y': NeedSecond = TRUE;
break;
default: Usage();
}
}
} else {
if (szFileArg != NULL) Usage();
szFileArg = argv[i];
}
} else {
NeedSecond = FALSE;
switch (c) {
case 'c': szSymbolsCDFile = argv[i];
break;
case 'e': pArgs->szExcludeFileName = argv[i];
break;
case 'l': pArgs->szListFileName = argv[i];
break;
case 's': pArgs->szSymPath = argv[i];
break;
case 'x': pArgs->szErrorFilterList = argv[i];
break;
case 'y': pArgs->szCDIncludeList = argv[i];
break;
default: Usage();
}
}
}
if ( pArgs->Split == 0 ) {
// This has always been the default behavior
pArgs->Split = ERROR_IF_NOT_SPLIT;
}
if ( szFileArg == NULL ) Usage();
// make the Symbol Copy log for the Support Tools CD
if ( szSymbolsCDFile != NULL ) {
if ( (pArgs->hSymCDLog = fopen(szSymbolsCDFile, "a+")) == NULL ) {
printf("Cannot open %s for appending\n",szSymbolsCDFile);
exit(1);
}
}
// Get the filenames so they are correct
_tsplitpath( szFileArg, szDrive, szDir, szFileName, szExt );
// Get current directory if they didn't enter a directory
if ( !_tcscmp(szDrive, "") && !_tcscmp(szDir,"") ) {
GetCurrentDirectory(_MAX_DIR, szDir);
}
// If szFileName and szExt are "" then put *.* in them
if ( !_tcscmp(szFileName,"") && !_tcscmp(szExt,"") ) {
_tcscpy(szFileName,"*");
}
// User may have entered a directory with an implies * for the
// file name.
fHandle = FindFirstFile( szFileArg, &FindFileData );
_tcscpy(szNameExt, szFileName);
_tcscat(szNameExt, szExt);
// If its a directory and the name of the directory matches
// the filename.ext from the command line parameter, then the user
// entered a directory, so add * to the end.
if ( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(_tcscmp( szNameExt, FindFileData.cFileName )== 0) ) {
// Move the filename to be the dir
_tcscat( szDir, "\\");
_tcscat( szDir, szFileName);
// Put the file name as *
_tcscpy(szFileName, "*");
}
pArgs->szDir=(LPTSTR) malloc( sizeof(TCHAR)* _MAX_PATH + 1 );
_tmakepath( pArgs->szDir, szDrive, szDir, NULL, NULL);
pArgs->szFileName = (LPTSTR) malloc( sizeof(TCHAR) * _MAX_PATH + 1 );
_tmakepath(pArgs->szFileName, NULL, NULL, szFileName, szExt);
// Check that everything has been entered
if (NeedSecond ||
(pArgs->szFileName == NULL) ||
(pArgs->szDir == NULL) ||
(pArgs->szSymPath == NULL) )
{
Usage();
}
return (pArgs);
}
BOOL
CorrectPath(
LPTSTR szFileName,
LPTSTR szPathName,
LPTSTR szCorrectPath
)
{
// To return TRUE, szPathName should equal szCorrectPath + \ + szFileName
// The only hitch is that there could be extraneous \'s
TCHAR CorrectPathx[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];
TCHAR PathNamex[_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];
LONG length, index, i;
// Get rid of any extra \'s
length = _tcslen(szPathName);
PathNamex[0] = szPathName[0];
index = 1;
for (i=1; i<=length; i++) {
if ( (szPathName[i-1] != '\\') || (szPathName[i] != '\\') ) {
PathNamex[index] = szPathName[i];
index++;
}
}
length = _tcslen(szCorrectPath);
CorrectPathx[0] = szCorrectPath[0];
index = 1;
for (i=1; i<=length; i++) {
if ( (szCorrectPath[i-1] != '\\') || (szCorrectPath[i] != '\\') ) {
CorrectPathx[index] = szCorrectPath[i];
index++;
}
}
// Make sure that the correct path doesn't end in a '\'
length = _tcslen(CorrectPathx);
if ( CorrectPathx[length-1] == '\\' ) CorrectPathx[length-1] = '\0';
_tcscat(CorrectPathx,"\\");
_tcscat(CorrectPathx,szFileName);
if ( _tcsicmp(CorrectPathx, szPathName) == 0) return TRUE;
else return FALSE;
}