/* * Module Name: WSPDUMP.C * * Program: WSPDUMP * * * Description: * * Dumps the contents of a WSP file. * * Contitional compilation notes: * * Modification History: * * 6-12-92: Adapted OS/2 version of wspdump for NT marklea * 6-17-92: Modified wspDumpBits to dump in correct order marklea * 6-18-92: Added page useage information marklea * 8-31-92: Made single exe from wspdump, wsreduce and wstune marklea * */ #include "wstune.h" /* * Global variable declaration and initialization. */ typedef struct fxn_t{ CHAR szFxnName[192]; ULONG cbFxn; ULONG ulTmiIndex; ULONG ulOrigIndex; }FXN; typedef FXN *PFXN; /* * Function prototypes. */ VOID wspDumpUsage( VOID ); VOID wspDumpSetup( VOID ); VOID wspDumpRandom( VOID ); UINT wspDumpBits( VOID ); VOID wspDumpExit( UINT, USHORT, UINT, ULONG, PSZ ); VOID wspDumpSeq(VOID); int _CRTAPI1 wspCompare(const void *fxn1, const void *fxn2); static CHAR *pszVersion = "V2.0"; // Current program version number static CHAR szProgName[20]; // Program name (initialized in Main) static CHAR szFileWSP[CCHMAXPATHCOMP] = ""; // WSP file name static CHAR szFileTMI[CCHMAXPATHCOMP] = ""; // TMI file name static CHAR szFileWSR[CCHMAXPATHCOMP] = ""; // WSR file name static CHAR szWSDIRPath[CCHMAXPATHCOMP] = ""; static CHAR szDatFile[48]; // DAT file name static ULONG rc = NO_ERROR; // Return code static ULONG ulTmp; // Temp variable for Dos API returns static ULONG ulFxnIndex; // Original index in symbol table static FILE *hFileWSP; // Input WSP file handle static FILE *hFileTMI; // Input TMI file handle FILE *hFileDAT; // Data file for dump static wsphdr_t WspHdr; // Input WSP file header static tmihdr_t TmiHdr; // Input TMI file header static tmirec_t TmiRec; // Input TMI file record static ULONG cbRead; // Byte cnt returned from DosRead static BOOL fVerbose = FALSE; // Flag for verbose mode static BOOL fRandom = FALSE; // Flag for random WSR access static ULONG ulFxnTot = 0; // Total number of functions static ULONG clVarTot = 0; // Total number of dwords in bitstr static CHAR szModName[CCHMAXPATHCOMP] = ""; // Module pathname static ULONG *pulFxnBitstring; // Function bitstring static CHAR szTmpName[CCHMAXPATHCOMP] = ""; // Temporary name static USHORT usSetSym = 0; // Number of symbols set BOOL fDatFile = FALSE; /* * Procedure MAIN * * *** * Effects: * * Parses the WSPDUMP command line. Displays the function reference data * for each function in the specified module WSP file. * * The command line interface to WSPDUMP is * * [d:][path]WSPDUMP [/V] [/FFile.wsp] [/R[File.wsr]] [/TFile.tmi] * * where: * * /V Specifies verbose mode (displays reference bitstrings) * /F Specifies a module WSP file name * /R For non-sequential access, specifies the input WSR file * /T Specifies the input TMI file */ BOOL wspDumpMain(INT vargc, CHAR **vargv) { INT c; // Counter CHAR szDrive[_MAX_DRIVE]; // Drive name CHAR szDir[_MAX_DIR]; // Directory name CHAR szExt[_MAX_EXT]; // Module extension fRandom = FALSE; fVerbose = FALSE; fDatFile = FALSE; // Initialize global variable containing name of program. // strcpy(szProgName, vargv[0]); _strupr(szProgName); /* * Parse command line. */ if (vargc == 1) { wspDumpUsage(); } else { hFileDAT = stdout; for (c = 1; c < vargc; c++) { // If the argument looks like it might be a switch... // if (vargv[c][0] == '/' || vargv[c][0] == '-') { /* Validate switch. */ switch (vargv[c][1]) { case 'F': /* Input WSP file name */ case 'f': if (vargv[c][2] == '\0') { if (++c >= vargc) { wspDumpUsage(); } else { strcpy(szFileWSP, (char *) vargv[c]); } } else { strcpy(szFileWSP, (char *) &vargv[c][2]); } break; case 'R': /* Input WSR file name */ case 'r': fRandom = TRUE; // regardless of whether WSR specified if (vargv[c][2] == '\0') { if ((++c >= vargc) || (vargv[c][0] == '/' || vargv[c][0] == '-')) { --c; break; } else { strcpy(szFileWSR, (char *) vargv[c]); } } else { strcpy(szFileWSR, (char *) &vargv[c][2]); } break; case 'T': /* Input TMI file name */ case 't': if (vargv[c][2] == '\0') { if (++c >= vargc) { wspDumpUsage(); } else { strcpy(szFileTMI, (char *) vargv[c]); } } else { strcpy(szFileTMI, (char *) &vargv[c][2]); } break; case 'V': /* Verbose */ case 'v': fVerbose = TRUE; break; case 'D': case 'd': strcpy(szDatFile, (char *) &vargv[c][2]); fDatFile = TRUE; break; case '?': /* Help */ case 'H': case 'h': wspDumpUsage(); break; default: /* Invalid switch specified */ fprintf(stdout,"%s %s: Invalid switch: '%s'\n", szProgName, pszVersion, vargv[c]); wspDumpUsage(); break; } } } } rc = WsGetWSDIR(szWSDIRPath); if (szFileWSP[0] == '\0') { strcat(szFileWSP, szWSDIRPath); strcat(szFileWSP, "DAT.WSP"); } _splitpath(szFileWSP, szDrive, szDir, szTmpName, szExt); if (szFileTMI[0] == '\0') { strcat(szFileTMI, "STD"); strcat(szFileTMI, ".TMI"); } if (fRandom == TRUE) { if (szFileWSR[0] == '\0') { strcat(szFileWSR, "STD"); strcat(szFileWSR, ".WSR"); } } // Setup input files for dump processing. wspDumpSetup(); /* Print the WSP file info, either randomly (based on WSR file * input) or sequentially (the default). */ if (fRandom == TRUE) wspDumpRandom(); else wspDumpSeq(); _fcloseall(); return(NO_ERROR); } /* * ***LP wspDumpSetup * * * Effects: * * Opens the module's WSP and TMI input files, seeks to the start of the * first function's bitstring data in the WSP file, and allocates memory * to hold one function's bitstring. * * Returns: * * Void. If an error is encountered, exits through wspDumpExit() * with ERROR. * */ VOID wspDumpSetup() { CHAR szLineTMI[MAXLINE]; // Line from TMI file if(fDatFile){ hFileDAT = fopen (szDatFile, "wt"); if (hFileDAT == NULL) { printf("Error creating file %s, will send output to stdout.\n", szDatFile); hFileDAT = stdout; } } /* Open input WSP file. Read and validate WSP file header.*/ rc = WsWSPOpen(szFileWSP, &hFileWSP,(PFN)wspDumpExit,&WspHdr,ERROR); usSetSym = WspHdr.wsphdr_dtqo.dtqo_SymCnt; clVarTot = WspHdr.wsphdr_ulSnaps; fprintf(stdout, "\n%s: Set symbol count=%d - Segment size=%ld\n", szDatFile, WspHdr.wsphdr_dtqo.dtqo_SymCnt, WspHdr.wsphdr_dtqo.dtqo_clSegSize); /* Open TMI file (contains function names, obj:offset, size, etc.). * Verify that the TMI file identifier matches the module * identifier from the WSP file. */ ulFxnTot = WsTMIOpen(szFileTMI, &hFileTMI, (PFN) wspDumpExit, 0, (PCHAR)0); fseek(hFileTMI, 0L, SEEK_SET); fgets(szLineTMI, MAXLINE, hFileTMI); /* Print module header information for output file */ szLineTMI[strlen(szLineTMI)-1] = '\0'; fprintf(hFileDAT,"\nDUMP OF FUNCTION REFERENCES FOR '%s':\n\n",szLineTMI); fclose (hFileTMI); ulFxnTot = WsTMIOpen(szFileTMI, &hFileTMI, (PFN) wspDumpExit, 0, (PCHAR)0); /* Allocate memory to hold one function's entire bitstring. */ pulFxnBitstring = (ULONG *) malloc(clVarTot * sizeof(ULONG)); if (pulFxnBitstring == NULL) wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM, clVarTot * sizeof(ULONG), "pulFxnBitstring[]"); } /* * ***LP wspDumpSeq * * * Effects: * * For each function, prints the bitstring in ASCII form. * * Returns: * * Void. If an error is encountered, exits through wspDumpExit() * with ERROR. * */ VOID wspDumpSeq(VOID) { UINT uiFxn = 0; // Function number UINT cTouched=0; // Count of touched pages BOOL fTouched; // Flag to indicate page is touched. UINT i=0; // Generic counter ULONG cbFxnCum =0; // Cumulative function sizes PFXN Fxn; // pointer to array of fxn name ptrs FILE *fpFileWSR = NULL; // WSR file pointer ULONG cbFBits = 0; // Count of bytes in bitstring UINT uiPageCount=0; // Pages touched. ULONG ulMaxBytes=0; // Bytes of touched pages. /* Allocate memory for function names. */ Fxn = (PFXN) malloc(ulFxnTot * sizeof(FXN)); if (Fxn == NULL) wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM, ulFxnTot * sizeof(FXN), "Fxn[]"); /* Read function names from TMI file. */ for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++) { Fxn[uiFxn].cbFxn = WsTMIReadRec(szTmpName, &ulFxnIndex, &ulTmp, hFileTMI, (PFN) wspDumpExit, (PCHAR)0); strcpy(Fxn[uiFxn].szFxnName, szTmpName); Fxn[uiFxn].ulOrigIndex = ulFxnIndex; Fxn[uiFxn].ulTmiIndex = (ULONG)uiFxn; } qsort(Fxn, ulFxnTot, sizeof(FXN), wspCompare); cbFBits = clVarTot * sizeof(ULONG); for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++) { /* Seek to function's bitstring in WSP file. */ if ((rc = fseek(hFileWSP,(WspHdr.wsphdr_ulOffBits+(Fxn[uiFxn].ulTmiIndex*cbFBits)),SEEK_SET))!=NO_ERROR) wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET, rc, szFileWSP); fprintf(hFileDAT,"Fxn '%s' (#%d):\n\t", Fxn[uiFxn].szFxnName, Fxn[uiFxn].ulOrigIndex); // Print this function's reference bitstring. // and if it has had a bit set, set touched flag to true if(wspDumpBits()){ fTouched |=1; ulMaxBytes += Fxn[uiFxn].cbFxn; } fprintf(hFileDAT,"%-28s %10ld bytes.\n","Function size:", Fxn[uiFxn].cbFxn); cbFxnCum += Fxn[uiFxn].cbFxn; fprintf(hFileDAT,"%-28s %10ld bytes.\n\n","Cumulative function sizes:", cbFxnCum); //Checck to see if a 4k page boundry has been reached if(cbFxnCum >= (4096+(4096 * uiPageCount))){ for(i=0; i < 60; i++){ fprintf(hFileDAT, "*"); } fprintf(hFileDAT,"\n\nTotal function sizes has reached or exceeds %d bytes.\n\n", (4096+(4096*uiPageCount))); ++uiPageCount; //Check to see of the page has been touched. if(fTouched){ fprintf(hFileDAT,"This page has been touched.\n"); ++cTouched; } else{ fprintf(hFileDAT,"This page has not been touched.\n"); } fTouched = 0; //fprintf(hFileDAT,"Total pages touched: %d\n\n", uiPageCount); for(i=0; i < 60; i++){ fprintf(hFileDAT, "*"); } fprintf(hFileDAT, "\n\n"); } } ++uiPageCount; if(fTouched){ fprintf(hFileDAT,"\n\n"); for(i=0; i < 70; i++){ fprintf(hFileDAT, "="); } ++cTouched; fprintf(hFileDAT,"\n\nThis page has been touched."); } fprintf(hFileDAT,"\n\n"); for(i=0; i < 70; i++){ fprintf(hFileDAT, "="); } fprintf(hFileDAT,"\n\n%-28s %10ld bytes\n\n","Cumulative function size:", cbFxnCum); fprintf(hFileDAT,"%-28s %10d bytes\n\n", "Size of functions touched:", ulMaxBytes); fprintf(hFileDAT,"%-28s %10d\n\n", "Total page count:", uiPageCount); fprintf(hFileDAT,"%-28s %10d\n\n", "Total pages touched:", cTouched); } /* * ***LP wspDumpBits * * * Effects: * * Prints a function's reference bitstring (verbose mode only), followed * by the sum of the "on" bits. * * Returns: * * Void. If an error is encountered, exits through wspDumpExit() * with ERROR. * */ UINT wspDumpBits() { ULONG clVar = 0; // Current dword of bitstring UINT uiBit = 0; // Result of bit test (1 or 0) UINT cBitsOn; // Count of "on" bits ULONG *pulBits; // Pointer to ULONG packets of bits CHAR szTmp[33]; CHAR szBits[33]; cBitsOn = 0; pulBits = pulFxnBitstring; /* Read next dword of function's bitstring. */ szBits[0] = '\0'; szTmp[0] = '\0'; for (clVar = 0; clVar < clVarTot; clVar++, pulBits++) { rc = fread((PVOID)pulBits, (ULONG) sizeof(ULONG),1, hFileWSP); if(rc == 1) rc = NO_ERROR; else rc = 2; if (rc != NO_ERROR) wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_READ, rc, szFileWSP); if (*pulBits == 0) { if (fVerbose == TRUE) fprintf(hFileDAT,"00000000000000000000000000000000"); } else for (uiBit = 0; uiBit < NUM_VAR_BITS; uiBit++) { if (*pulBits & 1) { cBitsOn++; if (fVerbose == TRUE){ strcpy(szTmp,szBits); strcpy(szBits,"1"); strcat(szBits,szTmp); } } else { if (fVerbose == TRUE){ strcpy(szTmp,szBits); strcpy(szBits,"0"); strcat(szBits,szTmp); } } *pulBits = *pulBits >> 1; } if (fVerbose == TRUE) { if ((clVar % 2) != 0){ fprintf(hFileDAT,"%s",szBits); szBits[0]='\0'; fprintf(hFileDAT,"\n\t"); } else{ fprintf(hFileDAT,"%s",szBits); szBits[0]='\0'; fprintf(hFileDAT," "); } } } fprintf(hFileDAT,"\n\t*** Sum of '1' bits = %ld\n\n", cBitsOn); return(cBitsOn); } /* * ***LP wspDumpRandom * * * Effects: * * For each function ordinal specified in the WSR file, prints the * corresponding function's reference bitstring in ASCII form (verbose * mode only), followed by a sum of the "on" bits.. * * Returns: * * Void. If an error is encountered, exits through wspDumpExit() * with ERROR. */ VOID wspDumpRandom() { UINT uiFxn = 0; // Function number UINT cTouched=0; // Count of touched pages BOOL fTouched; // Flag to indicate page is touched. UINT i=0; // Generic counter ULONG cbFxnCum =0; // Cumulative function sizes PFXN Fxn; // pointer to array of fxn name ptrs ULONG ulFxnOrd; // function number within module FILE *fpFileWSR = NULL; // WSR file pointer ULONG cbFBits = 0; // Count of bytes in bitstring UINT uiPageCount=0; // Pages touched. ULONG ulMaxBytes=0; // Bytes of touched pages. /* Open WSR file (contains function ordinal numbers in ASCII). */ if ((fpFileWSR = fopen(szFileWSR, "r")) == NULL) { wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OPEN, rc, szFileWSR); } /* Allocate memory for function names. */ Fxn = (PFXN) malloc(ulFxnTot * sizeof(FXN)); if (Fxn == NULL) wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM, ulFxnTot * sizeof(FXN), "Fxn[]"); /* Read function names from TMI file. */ for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++) { Fxn[uiFxn].cbFxn = WsTMIReadRec(szTmpName, &ulFxnIndex, &ulTmp, hFileTMI, (PFN) wspDumpExit, (PCHAR)0); strcpy(Fxn[uiFxn].szFxnName, szTmpName); } cbFBits = clVarTot * sizeof(ULONG); for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++) { /* Read function number from WSR file. */ rc = fscanf(fpFileWSR, "%ld\n", &ulFxnOrd); if (rc != 1) wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_READ, rc, szFileWSR); /* Seek to function's bitstring in WSP file. */ if ((rc = fseek(hFileWSP,(WspHdr.wsphdr_ulOffBits+(ulFxnOrd*cbFBits)),SEEK_SET))!=NO_ERROR) wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET, rc, szFileWSP); fprintf(hFileDAT,"Fxn '%s' (#%d):\n\t", Fxn[ulFxnOrd].szFxnName, ulFxnOrd); // Print this function's reference bitstring. // and if it has had a bit set, set touched flag to true if(uiFxn < (UINT) usSetSym){ if(wspDumpBits()){ fTouched |= 1; ulMaxBytes += Fxn[ulFxnOrd].cbFxn; } } else{ fprintf(hFileDAT,"\n\t*** Sum of '1' bits = %ld\n\n", 0L); } fprintf(hFileDAT,"%-28s %10ld bytes.\n","Function size:", Fxn[ulFxnOrd].cbFxn); cbFxnCum += Fxn[ulFxnOrd].cbFxn; fprintf(hFileDAT,"%-28s %10ld bytes.\n\n","Cumulative function sizes:", cbFxnCum); //Checck to see if a 4k page boundry has been reached if(cbFxnCum >= (4096+(4096 * uiPageCount))){ for(i=0; i < 60; i++){ fprintf(hFileDAT, "*"); } fprintf(hFileDAT,"\n\nTotal function sizes has reached or exceeds %d bytes.\n\n", (4096+(4096*uiPageCount))); ++uiPageCount; //Check to see of the page has been touched. if(fTouched){ fprintf(hFileDAT,"This page has been touched.\n"); ++cTouched; } else{ fprintf(hFileDAT,"This page has not been touched.\n"); } fTouched = 0; //fprintf(hFileDAT,"Total pages touched: %d\n\n", uiPageCount); for(i=0; i < 60; i++){ fprintf(hFileDAT, "*"); } fprintf(hFileDAT, "\n\n"); } } ++uiPageCount; if(fTouched){ fprintf(hFileDAT,"\n\n"); for(i=0; i < 70; i++){ fprintf(hFileDAT, "="); } ++cTouched; fprintf(hFileDAT,"\n\nThis page has been touched."); } fprintf(hFileDAT,"\n\n"); for(i=0; i < 70; i++){ fprintf(hFileDAT, "="); } fprintf(hFileDAT,"\n\n%-28s %10ld bytes\n\n","Cumulative function size:", cbFxnCum); fprintf(hFileDAT,"%-28s %10d bytes\n\n", "Size of functions touched:", ulMaxBytes); fprintf(hFileDAT,"%-28s %10d\n\n", "Total page count:", uiPageCount); fprintf(hFileDAT,"%-28s %10d\n\n", "Total pages touched:", cTouched); } /* * ***LP wspDumpUsage * * * Effects: * * Prints out usage message, and exits with an error. * * Returns: * * Exits with ERROR. */ VOID wspDumpUsage() { fprintf(stdout,"\nUsage: %s [/V] [/FFile.wsp] [/TFile.tmi] [/RFile.wsr]\n", szProgName); fprintf(stdout," /V Specifies verbose mode (print bit reference strings)\n"); fprintf(stdout," /F Specifies the input WSP file (default is %%WSDIR%%\\DAT.WSP)\n"); fprintf(stdout," /T Specifies the input TMI file\n\t\t(default is %%WSDIR%%\\ + WSP basename + .TMI)\n"); fprintf(stdout," /R For non-sequential access, specifies the input WSR file\n\t\t(default is %%WSDIR%%\\ + WSP basename + .WSR)\n"); fprintf(stdout," /? Causes this usage message to be displayed.\n"); exit(ERROR); } /* * ***LP wspDumpExit * * *** * * Effects: * * Frees up resources (as necessary). Exits with the specified * exit code, or returns void if exit code is NOEXIT. * *** * Returns: * * Void, else exits. */ VOID wspDumpExit(uiExitCode, fPrintMsg, uiMsgCode, ulParam1, pszParam2) UINT uiExitCode; USHORT fPrintMsg; UINT uiMsgCode; ULONG ulParam1; PSZ pszParam2; { /* Print message, if necessary. */ if (fPrintMsg == TRUE) { printf(pchMsg[uiMsgCode], szProgName, pszVersion, ulParam1, pszParam2); } // Special case: do NOT exit if called with NOEXIT. if (uiExitCode == NOEXIT) return; exit(uiExitCode); } int _CRTAPI1 wspCompare(const void *fxn1, const void *fxn2) { return (((PFXN)fxn1)->ulOrigIndex < ((PFXN)fxn2)->ulOrigIndex ? -1: ((PFXN)fxn1)->ulOrigIndex == ((PFXN)fxn2)->ulOrigIndex ? 0: 1); }