SYMEDIT.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:31k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*++
  2. Copyright 1996 - 1997 Microsoft Corporation
  3. Module Name:
  4.     symedit.c
  5. Abstract:
  6. Author:
  7.     Wesley A. Witt (wesw) 19-April-1993
  8. Environment:
  9.     Win32, User Mode
  10. --*/
  11. #include <windows.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include "symcvt.h"
  16. #include "cv.h"
  17. #include "strings.h"
  18. #include <imagehlp.h>
  19. //  prototypes for this module
  20. BOOL    CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po );
  21. void    ProcessCommandLineArgs( int argc, char *argv[] );
  22. void    PrintCopyright( void );
  23. void    PrintUsage( void );
  24. void    FatalError( int, ... );
  25. BOOL    MapOutputFile ( PPOINTERS p, char *fname, int );
  26. void    ComputeChecksum(  char *szExeFile );
  27. void    ReadDebugInfo( PPOINTERS p );
  28. void    WriteDebugInfo( PPOINTERS p, BOOL);
  29. void    MungeDebugHeadersCoffToCv( PPOINTERS  p, BOOL fAddCV );
  30. void    MungeExeName( PPOINTERS p, char * szExeName );
  31. void    DoCoffToCv(char *, char *, BOOL);
  32. void    DoSymToCv(char *, char *, char *, char *);
  33. void    DoNameChange(char *, char *, char *);
  34. void    DoExtract(char *, char *, char *);
  35. void    DoStrip(char *, char *);
  36. IMAGE_DEBUG_DIRECTORY   DbgDirSpare;
  37. #define AdjustPtr(ptr) (((ptr) != NULL) ? 
  38.                           ((DWORD)ptr - (DWORD)pi->fptr + (DWORD)po->fptr) : 
  39.                           ((DWORD)(ptr)))
  40. int _CRTAPI1
  41. main(
  42.     int        argc,
  43.     char *     argv[]
  44.     )
  45. /*++
  46. Routine Description:
  47.     Shell for this utility.
  48. Arguments:
  49.     argc     - argument count
  50.     argv     - argument pointers
  51. Return Value:
  52.     0        - image was converted
  53.     >0       - image could not be converted
  54. --*/
  55. {
  56.     // Scan the command line and check what operations we are doing
  57.     ProcessCommandLineArgs( argc, argv );
  58.     return 0;
  59. }
  60. __inline void PrintCopyright( void )
  61. {
  62.     puts( "nMicrosoft(R) Windows NT SymEdit Version 1.0n"
  63.           "(C) 1989-1995 Microsoft Corp. All rights reserved.n");
  64. }
  65. __inline void PrintUsage( void )
  66. {
  67.     PrintCopyright();
  68.     puts ("nUsage: SYMEDIT <OPERATION> -q -o<file out> <file in>nn"
  69.           "t<OPERATION> is:n"
  70.           "tCtModify CodeView symbol informationn"
  71.           "tNtEdit name fieldn"
  72.           "tXtExtract debug informationn"
  73.           "tStStrip all debug informationnn"
  74.           "Options:n"
  75.           "t-attAdd CodeView debug info to filen"
  76.           "t-n<name>tName to change ton"
  77.           "t-o<file>tspecify output filen"
  78.           "t-qttquiet moden"
  79.           "t-rttReplace COFF debug info with CV infon"
  80.           "t-s<file>tSym file source");
  81. }
  82. void
  83. ProcessCommandLineArgs(
  84.     int argc,
  85.     char *argv[]
  86.     )
  87. /*++
  88. Routine Description:
  89.     Processes the command line arguments and sets global flags to
  90.     indicate the user's desired behavior.
  91. Arguments:
  92.     argc     - argument count
  93.     argv     - argument pointers
  94. Return Value:
  95.     void
  96. --*/
  97. {
  98.     int     i;
  99.     BOOL    fQuiet = FALSE;
  100.     BOOL    fSilent = FALSE;
  101.     char *  szOutputFile = NULL;
  102.     char *  szInputFile = NULL;
  103.     char *  szExeName = NULL;
  104.     char *  szDbgFile = NULL;
  105.     char *  szSymFile = NULL;
  106.     int     iOperation;
  107.     BOOLEAN fAddCV = FALSE;
  108.     // Minimun number of of arguments is 2 -- program and operation
  109.     if (argc < 2 ||
  110.         (strcmp(argv[1], "-?") == 0) ||
  111.         (strcmp(argv[1], "?") == 0) )
  112.     {
  113.         PrintUsage();
  114.         exit(1);
  115.     }
  116.     // All operations on 1 character wide
  117.     if (argv[1][1] != 0) {
  118.         FatalError(ERR_OP_UNKNOWN, argv[1]);
  119.     }
  120.     // Validate the operation
  121.     switch( argv[1][0] ) {
  122.         case 'C':
  123.         case 'N':
  124.         case 'X':
  125.         case 'S':
  126.             iOperation = argv[1][0];
  127.             break;
  128.         default:
  129.             FatalError(ERR_OP_UNKNOWN, argv[1]);
  130.     }
  131.     // Parse out any other switches on the command line
  132.     for (i=2; i<argc; i++) {
  133.         if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
  134.             switch (toupper(argv[i][1])) {
  135.                 // Add the CV debug information section rather than
  136.                 // replace the COFF section with the CV info.
  137.                 case 'A':
  138.                     fAddCV = TRUE;
  139.                     break;
  140.                 // Specify the output name for the DBG file
  141.                 case 'D':
  142.                     if (argv[i][2] == 0) {
  143.                         i += 1;
  144.                         szDbgFile = argv[i];
  145.                     } else {
  146.                         szDbgFile = &argv[i][2];
  147.                     }
  148.                     break;
  149.                 // Specify a new name to shove into the name of the
  150.                 // debuggee field in the Misc. Debug info field
  151.                 case 'N':
  152.                     if (argv[i][2] == 0) {
  153.                         i += 1;
  154.                         szExeName = argv[i];
  155.                     } else {
  156.                         szExeName = &argv[i][2];
  157.                     }
  158.                     break;
  159.                 // Specify the name of the output file
  160.                 case 'O':
  161.                     if (argv[i][2] == 0) {
  162.                         i += 1;
  163.                         szOutputFile = argv[i];
  164.                     } else {
  165.                         szOutputFile = &argv[i][2];
  166.                     }
  167.                     break;
  168.                 // Be quite and don't put out the banner
  169.                 case 'Q':
  170.                     fQuiet = TRUE;
  171.                     fSilent = TRUE;
  172.                     break;
  173.                 //  Replace COFF debug information with CODEVIEW debug information
  174.                 case 'R':
  175.                     break;
  176.                 //  Convert a Symbol File to CV info
  177.                 case 'S':
  178.                     if (argv[i][2] == 0) {
  179.                         i += 1;
  180.                         szSymFile = argv[i];
  181.                     } else {
  182.                         szSymFile = &argv[i][2];
  183.                     }
  184.                     break;
  185.                 // Print the command line options
  186.                 case '?':
  187.                     PrintUsage();
  188.                     exit(1);
  189.                     break;
  190.                 // Unrecognized option
  191.                 default:
  192.                     FatalError( ERR_OP_UNKNOWN, argv[i] );
  193.                     break;
  194.             }
  195.         } else {
  196.             //  No leading switch character -- must be a file name
  197.             szInputFile = &argv[i][0];
  198.             //  Process the file(s)
  199.             if (!fQuiet) {
  200.                 PrintCopyright();
  201.                 fQuiet = TRUE;
  202.             }
  203.             if (!fSilent) {
  204.                 printf("processing file: %sn", szInputFile );
  205.             }
  206.             //  Do switch validation cheching and setup any missing global variables
  207.             switch ( iOperation ) {
  208.                 // For conversions -- there are three types
  209.                 //
  210.                 //      1.  Coff to CV -- add
  211.                 //      2.  Coff to CV -- replace
  212.                 //      3.  SYM to CV --- add
  213.                 //      4.  SYM to CV -- seperate file
  214.                 //
  215.                 //      Optional input file (not needed for case 4)
  216.                 //      Optional output file
  217.                 //      Optional sym file (implys sym->CV)
  218.                 //      Optional DBG file
  219.                 case 'C':
  220.                     if (szSymFile == NULL) {
  221.                         DoCoffToCv(szInputFile, szOutputFile, fAddCV);
  222.                     } else {
  223.                         DoSymToCv(szInputFile, szOutputFile, szDbgFile, szSymFile);
  224.                     }
  225.                     szInputFile = NULL;
  226.                     szOutputFile = NULL;
  227.                     szDbgFile = NULL;
  228.                     szSymFile = NULL;
  229.                     break;
  230.                 //  For changing the name of the debuggee --
  231.                 //      Must specify input file
  232.                 //      Must specify new name
  233.                 //      Optional output file
  234.                 case 'N':
  235.                     DoNameChange(szInputFile, szOutputFile, szExeName);
  236.                     szInputFile = NULL;
  237.                     szOutputFile = NULL;
  238.                     szExeName = NULL;
  239.                     break;
  240.                 //  For extraction of debug information
  241.                 //      Must specify input file
  242.                 //      Optional output file name
  243.                 //      Optional debug file name
  244.                 case 'X':
  245.                     DoExtract(szInputFile, szOutputFile, szDbgFile);
  246.                     break;
  247.                 //  For full strip of debug information
  248.                 //      Must specify input file
  249.                 //      Optional output file
  250.                 case 'S':
  251.                     DoStrip(szInputFile, szOutputFile);
  252.                     break;
  253.             }
  254.         }
  255.     }
  256.     return;
  257. }
  258. void
  259. ReadDebugInfo(
  260.     PPOINTERS   p
  261.     )
  262. /*++
  263. Routine Description:
  264.     This function will go out and read in all of the debug information
  265.     into memory -- this is required because the input and output
  266.     files might be the same, if so then writing out informaiton may
  267.     destory data we need at a later time.
  268. Arguments:
  269.     p   - Supplies a pointer to the structure describing the debug info file
  270. Return Value:
  271.     None.
  272. --*/
  273. {
  274.     int                         i;
  275. //    int                         cb;
  276. //    char *                      pb;
  277. //    PIMAGE_COFF_SYMBOLS_HEADER  pCoffDbgInfo;
  278.     // Allocate space to save pointers to debug info
  279.     p->iptrs.rgpbDebugSave = (PCHAR *) malloc(p->iptrs.cDebugDir * sizeof(PCHAR));
  280.     memset(p->iptrs.rgpbDebugSave, 0, p->iptrs.cDebugDir * sizeof(PCHAR));
  281.     // Check each possible debug type record
  282.     for (i=0; i<p->iptrs.cDebugDir; i++) {
  283.         // If there was debug information then copy over the
  284.         // description block and cache in the actual debug data.
  285.         if (p->iptrs.rgDebugDir[i] != NULL) {
  286.             p->iptrs.rgpbDebugSave[i] =
  287.               malloc( p->iptrs.rgDebugDir[i]->SizeOfData );
  288.             if (p->iptrs.rgpbDebugSave[i] == NULL) {
  289.                 FatalError(ERR_NO_MEMORY);
  290.             }
  291.             __try {
  292.                 memcpy(p->iptrs.rgpbDebugSave[i],
  293.                        p->iptrs.fptr +
  294.                        p->iptrs.rgDebugDir[i]->PointerToRawData,
  295.                        p->iptrs.rgDebugDir[i]->SizeOfData );
  296.             } __except(EXCEPTION_EXECUTE_HANDLER ) {
  297.                 free(p->iptrs.rgpbDebugSave[i]);
  298.                 p->iptrs.rgpbDebugSave[i] = NULL;
  299.             }
  300.         }
  301.     }
  302.     return;
  303. }
  304. void
  305. WriteDebugInfo(
  306.     PPOINTERS   p,
  307.     BOOL        fAddCV
  308.     )
  309. /*++
  310. Routine Description:
  311.     This function will go out and read in all of the debug information
  312.     into memory -- this is required because the input and output
  313.     files might be the same, if so then writing out informaiton may
  314.     destory data we need at a later time.
  315. Arguments:
  316.     p   - Supplies a pointer to the structure describing the debug info file
  317. Return Value:
  318.     None.
  319. --*/
  320. {
  321.     ULONG  PointerToDebugData = 0; //  Offset from the start of the file
  322.                                    //  to the current location to write
  323.                                    //  debug information out.
  324.     ULONG  BaseOfDebugData = 0;
  325.     int    i, flen;
  326.     PIMAGE_DEBUG_DIRECTORY  pDir, pDbgDir = NULL;
  327.     if (p->optrs.debugSection) {
  328.         BaseOfDebugData = PointerToDebugData =
  329.           p->optrs.debugSection->PointerToRawData;
  330.     } else if (p->optrs.sepHdr) {
  331.         BaseOfDebugData =  PointerToDebugData =
  332.           sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
  333.           p->optrs.sepHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
  334.           p->optrs.sepHdr->ExportedNamesSize;
  335.     }
  336.     //  Step 2. If the debug information is mapped, we know this
  337.     //          from the section headers, then we may need to write
  338.     //          out a new debug director to point to the debug information
  339.     if (fAddCV) {
  340.         if (p->optrs.optHdr) {
  341.             p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].
  342.               VirtualAddress = p->optrs.debugSection->VirtualAddress;
  343.             p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size +=
  344.               sizeof(IMAGE_DEBUG_DIRECTORY);
  345.         } else if (p->optrs.sepHdr) {
  346.             p->optrs.sepHdr->DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  347.         } else {
  348.             exit(1);
  349.         }
  350.         if (p->optrs.sepHdr) {
  351.             pDbgDir = (PIMAGE_DEBUG_DIRECTORY) malloc(p->optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY));
  352.             for (i=0; i<p->optrs.cDebugDir; i++) {
  353.                 if (p->optrs.rgDebugDir[i] != NULL) {
  354.                     pDbgDir[i] = *(p->optrs.rgDebugDir[i]);
  355.                     p->optrs.rgDebugDir[i] = &pDbgDir[i];
  356.                 }
  357.             }
  358.         }
  359.         for (i=0; i<p->optrs.cDebugDir; i++) {
  360.             if (p->optrs.rgDebugDir[i]) {
  361.                 pDir = (PIMAGE_DEBUG_DIRECTORY) (PointerToDebugData +
  362.                                                  p->optrs.fptr);
  363.                 *pDir = *(p->optrs.rgDebugDir[i]);
  364.                 p->optrs.rgDebugDir[i] = pDir;
  365.                 PointerToDebugData += sizeof(IMAGE_DEBUG_DIRECTORY);
  366.             }
  367.         }
  368.     }
  369.     // Step 3.  For every debug info type, write out the debug information
  370.     //          and update any header information required
  371.     for (i=0; i<p->optrs.cDebugDir; i++) {
  372.         if (p->optrs.rgDebugDir[i] != NULL) {
  373.             if (p->optrs.rgpbDebugSave[i] != NULL) {
  374.                 p->optrs.rgDebugDir[i]->PointerToRawData =
  375.                   PointerToDebugData;
  376.                 if (p->optrs.debugSection) {
  377.                     p->optrs.rgDebugDir[i]->AddressOfRawData =
  378.                       p->optrs.debugSection->VirtualAddress +
  379.                         PointerToDebugData - BaseOfDebugData;
  380.                 }
  381.                 memcpy(p->optrs.fptr + PointerToDebugData,
  382.                        p->optrs.rgpbDebugSave[i],
  383.                        p->optrs.rgDebugDir[i]->SizeOfData);
  384.                 if ((i == IMAGE_DEBUG_TYPE_COFF) &&
  385.                     (p->optrs.fileHdr != NULL)) {
  386.                     PIMAGE_COFF_SYMBOLS_HEADER  pCoffDbgInfo;
  387.                     pCoffDbgInfo = (PIMAGE_COFF_SYMBOLS_HEADER)p->optrs.rgpbDebugSave[i];
  388.                     p->optrs.fileHdr->PointerToSymbolTable =
  389.                       PointerToDebugData + pCoffDbgInfo->LvaToFirstSymbol;
  390.                 }
  391.             }
  392.             PointerToDebugData += p->optrs.rgDebugDir[i]->SizeOfData;
  393.         }
  394.     }
  395.     // Step 4.  Clean up any COFF structures if we are replacing
  396.     //          the coff information with CV info.
  397.     if ((p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_COFF] == NULL) &&
  398.         (p->optrs.fileHdr != NULL)) {
  399.         // Since there is no coff debug information -- clean out
  400.         // both fields pointing to the debug info
  401.         p->optrs.fileHdr->PointerToSymbolTable = 0;
  402.         p->optrs.fileHdr->NumberOfSymbols = 0;
  403.     }
  404.     // Step 5.  Correct the alignments if needed.  If there is a real .debug
  405.     //          section in the file (i.e. it is mapped) then update it.
  406.     if (p->optrs.debugSection) {
  407.         p->optrs.debugSection->SizeOfRawData =
  408.           FileAlign(PointerToDebugData - BaseOfDebugData);
  409.         // update the optional header with the new image size
  410.         p->optrs.optHdr->SizeOfImage =
  411.           SectionAlign(p->optrs.debugSection->VirtualAddress +
  412.                        p->optrs.debugSection->SizeOfRawData);
  413.         p->optrs.optHdr->SizeOfInitializedData +=
  414.           p->optrs.debugSection->SizeOfRawData;
  415.     }
  416.     // calculate the new file size
  417.     if (p->optrs.optHdr != NULL) {
  418.         flen = FileAlign(PointerToDebugData);
  419.     } else {
  420.         flen = PointerToDebugData;
  421.     }
  422.     // finally, update the eof pointer and close the file
  423.     UnmapViewOfFile( p->optrs.fptr );
  424.     if (!SetFilePointer( p->optrs.hFile, flen, 0, FILE_BEGIN )) {
  425.         FatalError( ERR_FILE_PTRS );
  426.     }
  427.     if (!SetEndOfFile( p->optrs.hFile )) {
  428.         FatalError( ERR_SET_EOF );
  429.     }
  430.     CloseHandle( p->optrs.hFile );
  431.     // Exit -- we are done.
  432.     return;
  433. }
  434. void
  435. MungeDebugHeadersCoffToCv(
  436.     PPOINTERS   p,
  437.     BOOL        fAddCV
  438.     )
  439. /*++
  440. Routine Description:
  441. Arguments:
  442.     p        - pointer to a POINTERS structure (see symcvt.h)
  443. Return Value:
  444.     void
  445. --*/
  446. {
  447.     if (!fAddCV) {
  448.         CV_DIR(&p->optrs) = COFF_DIR(&p->optrs);
  449.         COFF_DIR(&p->optrs) = 0;
  450.     } else {
  451.         CV_DIR(&p->optrs) = &DbgDirSpare;
  452.         *(COFF_DIR(&p->optrs)) = *(COFF_DIR(&p->iptrs));
  453.     };
  454.     *CV_DIR(&p->optrs) = *(COFF_DIR(&p->iptrs));
  455.     CV_DIR(&p->optrs)->Type = IMAGE_DEBUG_TYPE_CODEVIEW;
  456.     CV_DIR(&p->optrs)->SizeOfData =  p->pCvStart.size;
  457.     p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_CODEVIEW] = p->pCvStart.ptr;
  458.     return;
  459. }
  460. BOOL
  461. MapOutputFile (
  462.     PPOINTERS p,
  463.     char *fname,
  464.     int cb
  465.     )
  466. /*++
  467. Routine Description:
  468.     Maps the output file specified by the fname argument and saves the
  469.     file handle & file pointer in the POINTERS structure.
  470. Arguments:
  471.     p        - pointer to a POINTERS structure (see symcvt.h)
  472.     fname    - ascii string for the file name
  473. Return Value:
  474.     TRUE     - file mapped ok
  475.     FALSE    - file could not be mapped
  476. --*/
  477. {
  478.     BOOL    rval;
  479.     HANDLE  hMap   = NULL;
  480.     DWORD   oSize;
  481.     rval = FALSE;
  482.     p->optrs.hFile = CreateFile( fname,
  483.                         GENERIC_READ | GENERIC_WRITE,
  484.                         FILE_SHARE_READ | FILE_SHARE_WRITE,
  485.                         NULL,
  486.                         OPEN_ALWAYS,
  487.                         0,
  488.                         NULL );
  489.     if (p->optrs.hFile == INVALID_HANDLE_VALUE) {
  490.        goto exit;
  491.     }
  492.     oSize = p->iptrs.fsize;
  493.     if (p->pCvStart.ptr != NULL) {
  494.         oSize += p->pCvStart.size;
  495.     }
  496.     oSize += cb;
  497.     oSize += p->iptrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY);
  498.     hMap = CreateFileMapping( p->optrs.hFile, NULL, PAGE_READWRITE,
  499.                                 0, oSize, NULL );
  500.     if (hMap == NULL) {
  501.        goto exit;
  502.     }
  503.     p->optrs.fptr = MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 );
  504.     CloseHandle(hMap);
  505.     if (p->optrs.fptr == NULL) {
  506.        goto exit;
  507.     }
  508.     rval = TRUE;
  509. exit:
  510.     return rval;
  511. }
  512. BOOL
  513. CalculateOutputFilePointers(
  514.     PIMAGEPOINTERS pi,
  515.     PIMAGEPOINTERS po
  516.     )
  517. /*++
  518. Routine Description:
  519.     This function calculates the output file pointers based on the
  520.     input file pointers.  The same address is used but they are all
  521.     re-based off the output file's file pointer.
  522. Arguments:
  523.     p        - pointer to a IMAGEPOINTERS structure (see symcvt.h)
  524. Return Value:
  525.     TRUE     - pointers were created
  526.     FALSE    - pointers could not be created
  527. --*/
  528. {
  529.     int i;
  530.     // fixup the pointers relative the fptr for the output file
  531.     po->dosHdr       = (PIMAGE_DOS_HEADER)      AdjustPtr(pi->dosHdr);
  532.     po->ntHdr        = (PIMAGE_NT_HEADERS)      AdjustPtr(pi->ntHdr);
  533.     po->fileHdr      = (PIMAGE_FILE_HEADER)     AdjustPtr(pi->fileHdr);
  534.     po->optHdr       = (PIMAGE_OPTIONAL_HEADER) AdjustPtr(pi->optHdr);
  535.     po->sectionHdrs  = (PIMAGE_SECTION_HEADER)  AdjustPtr(pi->sectionHdrs);
  536.     po->sepHdr       = (PIMAGE_SEPARATE_DEBUG_HEADER) AdjustPtr(pi->sepHdr);
  537.     po->debugSection = (PIMAGE_SECTION_HEADER)  AdjustPtr(pi->debugSection);
  538.     po->AllSymbols   = (PIMAGE_SYMBOL)          AdjustPtr(pi->AllSymbols);
  539.     po->stringTable  = (PUCHAR)                 AdjustPtr(pi->stringTable);
  540.     // move the data from the input file to the output file
  541.     memcpy( po->fptr, pi->fptr, pi->fsize );
  542.     po->cDebugDir = pi->cDebugDir;
  543.     po->rgDebugDir = malloc(po->cDebugDir * sizeof(po->rgDebugDir[0]));
  544.     memset(po->rgDebugDir, 0, po->cDebugDir * sizeof(po->rgDebugDir[0]));
  545.     for (i=0; i<po->cDebugDir; i++) {
  546.         po->rgDebugDir[i] = (PIMAGE_DEBUG_DIRECTORY) AdjustPtr(pi->rgDebugDir[i]);
  547.     }
  548.     po->rgpbDebugSave = pi->rgpbDebugSave;
  549.     return TRUE;
  550. }
  551. void
  552. FatalError(
  553.     int  idMsg,
  554.     ...
  555.     )
  556. /*++
  557. Routine Description:
  558.     Prints a message string to stderr and then exits.
  559. Arguments:
  560.     s        - message string to be printed
  561. Return Value:
  562.     void
  563. --*/
  564. {
  565.     va_list marker;
  566.     char    rgchFormat[256];
  567.     char    rgch[256];
  568.     LoadString(GetModuleHandle(NULL), idMsg, rgchFormat, sizeof(rgchFormat));
  569.     va_start(marker, idMsg);
  570.     vsprintf(rgch, rgchFormat, marker);
  571.     va_end(marker);
  572.     fprintf(stderr, "%sn", rgch);
  573.     exit(1);
  574. }
  575. void
  576. ComputeChecksum(
  577.     char *szExeFile
  578.     )
  579. /*++
  580. Routine Description:
  581.     Computes a new checksum for the image by calling imagehlp.dll
  582. Arguments:
  583.     szExeFile - exe file name
  584. Return Value:
  585.     void
  586. --*/
  587. {
  588.     DWORD              dwHeaderSum = 0;
  589.     DWORD              dwCheckSum = 0;
  590.     HANDLE             hFile;
  591.     DWORD              cb;
  592.     IMAGE_DOS_HEADER   dosHdr;
  593.     IMAGE_NT_HEADERS   ntHdr;
  594.     if (MapFileAndCheckSum(szExeFile, &dwHeaderSum, &dwCheckSum) != CHECKSUM_SUCCESS) {
  595.         FatalError( ERR_CHECKSUM_CALC );
  596.     }
  597.     hFile = CreateFile( szExeFile,
  598.                         GENERIC_READ | GENERIC_WRITE,
  599.                         FILE_SHARE_READ | FILE_SHARE_WRITE,
  600.                         NULL,
  601.                         OPEN_EXISTING,
  602.                         0,
  603.                         NULL
  604.                       );
  605.     // seek to the beginning of the file
  606.     SetFilePointer( hFile, 0, 0, FILE_BEGIN );
  607.     // read in the dos header
  608.     if ((ReadFile(hFile, &dosHdr, sizeof(dosHdr), &cb, 0) == FALSE) || (cb != sizeof(dosHdr))) {
  609.         FatalError( ERR_CHECKSUM_CALC );
  610.     }
  611.     // read in the pe header
  612.     if ((dosHdr.e_magic != IMAGE_DOS_SIGNATURE) ||
  613.         (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L)) {
  614.         FatalError( ERR_CHECKSUM_CALC );
  615.     }
  616.     // read in the nt header
  617.     if ((!ReadFile(hFile, &ntHdr, sizeof(ntHdr), &cb, 0)) || (cb != sizeof(ntHdr))) {
  618.         FatalError( ERR_CHECKSUM_CALC );
  619.     }
  620.     if (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L) {
  621.         FatalError( ERR_CHECKSUM_CALC );
  622.     }
  623.     ntHdr.OptionalHeader.CheckSum = dwCheckSum;
  624.     if (!WriteFile(hFile, &ntHdr, sizeof(ntHdr), &cb, NULL)) {
  625.         FatalError( ERR_CHECKSUM_CALC );
  626.     }
  627.     CloseHandle(hFile);
  628.     return;
  629. }
  630. void
  631. MungeExeName(
  632.     PPOINTERS   p,
  633.     char *      szExeName
  634.     )
  635. /*++
  636. Routine Description:
  637.     description-of-function.
  638. Arguments:
  639.     argument-name - Supplies | Returns description of argument.
  640.     .
  641.     .
  642. Return Value:
  643.     None.
  644. --*/
  645. {
  646.     PIMAGE_DEBUG_MISC   pMiscIn;
  647.     PIMAGE_DEBUG_MISC   pMiscOut;
  648.     int                 cb;
  649.     int                 i;
  650.     for (i=0; i<p->iptrs.cDebugDir; i++) {
  651.         if (p->optrs.rgDebugDir[i] != 0) {
  652.             *(p->optrs.rgDebugDir[i]) = *(p->iptrs.rgDebugDir[i]);
  653.         }
  654.     }
  655.     pMiscIn = (PIMAGE_DEBUG_MISC)
  656.       p->iptrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC];
  657.     if (p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] == NULL) {
  658.         p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] = &DbgDirSpare;
  659.         memset(&DbgDirSpare, 0, sizeof(DbgDirSpare));
  660.     }
  661.     pMiscOut = (PIMAGE_DEBUG_MISC)
  662.       p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC] =
  663.       malloc(p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +
  664.              strlen(szExeName));
  665.     cb = p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData;
  666.     while ( cb > 0 ) {
  667.         if (pMiscIn->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  668.             pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
  669.             pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
  670.                                 strlen(szExeName) + 3) & ~3;
  671.             pMiscOut->Unicode = FALSE;
  672.             strcpy(&pMiscOut->Data[0], szExeName);
  673.             szExeName = NULL;
  674.         } else {
  675.             memcpy(pMiscOut, pMiscIn, pMiscIn->Length);
  676.         }
  677.         p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +=
  678.           (pMiscOut->Length - pMiscIn->Length);
  679.         cb -= pMiscIn->Length;
  680.         pMiscIn = (PIMAGE_DEBUG_MISC) (((char *) pMiscIn) + pMiscIn->Length);
  681.         pMiscOut = (PIMAGE_DEBUG_MISC) (((char *) pMiscOut) + pMiscOut->Length);
  682.     }
  683.     if (szExeName) {
  684.         pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
  685.         pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
  686.                             strlen(szExeName) + 3) & ~3;
  687.         pMiscOut->Unicode = FALSE;
  688.         strcpy(&pMiscOut->Data[0], szExeName);
  689.     }
  690.     return;
  691. }
  692. /***    DoCoffToCv
  693.  *
  694.  *
  695.  */
  696. void DoCoffToCv(
  697.     char * szInput,
  698.     char * szOutput,
  699.     BOOL fAddCV
  700.     )
  701. {
  702.     POINTERS    p;
  703.     // Do default checking
  704.     if (szOutput == NULL) {
  705.         szOutput = szInput;
  706.     }
  707.     // Open the input file name and setup the pointers into the file
  708.     if (!MapInputFile( &p, NULL, szInput )) {
  709.         FatalError( ERR_OPEN_INPUT_FILE, szInput );
  710.     }
  711.     // Now, if we thing we are playing with PE exes then we need
  712.     // to setup the pointers into the map file
  713.     if (!CalculateNtImagePointers( &p.iptrs )) {
  714.         FatalError( ERR_INVALID_PE, szInput );
  715.     }
  716.     // We are about to try and do the coff to cv symbol conversion.
  717.     //
  718.     // Verify that the operation is legal.
  719.     //
  720.     // 1.  We need to have coff debug information to start with
  721.     // 2.  If the debug info is not mapped then we must not
  722.     //     be trying to add CodeView info.
  723.     if ((p.iptrs.AllSymbols == NULL) || (COFF_DIR(&p.iptrs) == NULL)) {
  724.         FatalError( ERR_NO_COFF );
  725.     }
  726.     if (fAddCV && (p.iptrs.debugSection == 0) && (p.iptrs.sepHdr == NULL)) {
  727.         FatalError( ERR_NOT_MAPPED );
  728.     }
  729.     // Now go out an preform the acutal conversion.
  730.     if (!ConvertCoffToCv( &p )) {
  731.         FatalError( ERR_COFF_TO_CV );
  732.     }
  733.     // Read in any additional debug information in the file
  734.     ReadDebugInfo(&p);
  735.     // Open the output file and adjust the pointers so that we are ok.
  736.     if (!MapOutputFile( &p, szOutput, 0 )) {
  737.         FatalError( ERR_MAP_FILE, szOutput );
  738.     }
  739.     CalculateOutputFilePointers( &p.iptrs, &p.optrs );
  740.     // Munge the various debug information structures to preform the correct
  741.     // operations
  742.     MungeDebugHeadersCoffToCv( &p, fAddCV );
  743.     // Free our handles on the input file
  744.     UnMapInputFile(&p);
  745.     // Write out the debug information to the end of the exe
  746.     WriteDebugInfo( &p, fAddCV );
  747.     // and finally compute the checksum
  748.     if (p.iptrs.fileHdr != NULL) {
  749.         ComputeChecksum( szOutput );
  750.     }
  751.     return;
  752. }
  753. /***    DoSymToCv
  754.  *
  755.  */
  756. void
  757. DoSymToCv(
  758.     char * szInput,
  759.     char * szOutput,
  760.     char * szDbg,
  761.     char * szSym
  762.     )
  763. {
  764.     POINTERS    p;
  765.     HANDLE      hFile;
  766.     DWORD       cb;
  767.     OFSTRUCT    ofs;
  768.     // Open the input file name and setup the pointers into the file
  769.     if (!MapInputFile( &p, NULL, szSym )) {
  770.         FatalError(ERR_OPEN_INPUT_FILE, szSym);
  771.     }
  772.     // Now preform the desired operation
  773.     if ((szOutput == NULL) && (szDbg == NULL)) {
  774.         szOutput = szInput;
  775.     }
  776.     ConvertSymToCv( &p );
  777.     if (szOutput) {
  778.         if (szOutput != szInput) {
  779.             if (OpenFile(szInput, &ofs, OF_EXIST) == 0) {
  780.                 FatalError(ERR_OPEN_INPUT_FILE, szInput);
  781.             }
  782.             if (CopyFile(szInput, szOutput, FALSE) == 0) {
  783.                 FatalError(ERR_OPEN_WRITE_FILE, szOutput);
  784.             }
  785.         }
  786.         hFile = CreateFile(szOutput, GENERIC_WRITE, 0, NULL,
  787.                            CREATE_ALWAYS,
  788.                            FILE_ATTRIBUTE_NORMAL,  NULL);
  789.         if (hFile == INVALID_HANDLE_VALUE) {
  790.             FatalError(ERR_OPEN_WRITE_FILE, szOutput);
  791.         }
  792.         SetFilePointer(hFile, 0, 0, FILE_END);
  793.     } else if (szDbg) {
  794.         hFile = CreateFile(szDbg, GENERIC_WRITE, 0, NULL,
  795.                                OPEN_ALWAYS,
  796.                                FILE_ATTRIBUTE_NORMAL,  NULL);
  797.         if (hFile == INVALID_HANDLE_VALUE) {
  798.             FatalError(ERR_OPEN_WRITE_FILE, szDbg);
  799.         }
  800.     }
  801.     WriteFile(hFile, p.pCvStart.ptr, p.pCvStart.size, &cb, NULL);
  802.     CloseHandle(hFile);
  803.     return;
  804. }
  805. void
  806. DoNameChange(
  807.     char * szInput,
  808.     char * szOutput,
  809.     char * szNewName
  810.     )
  811. {
  812.     POINTERS    p;
  813.     // Open the input file name and setup the pointers into the file
  814.     if (!MapInputFile( &p, NULL, szInput )) {
  815.         FatalError(ERR_OPEN_INPUT_FILE, szInput);
  816.     }
  817.     // Now, if we thing we are playing with PE exes then we need
  818.     // to setup the pointers into the map file
  819.     if (!CalculateNtImagePointers( &p.iptrs )) {
  820.         FatalError(ERR_INVALID_PE, szInput);
  821.     }
  822.     //  Now preform the desired operation
  823.     if (szOutput == NULL) {
  824.         szOutput = szInput;
  825.     }
  826.     if (szNewName == NULL) {
  827.         szNewName = szOutput;
  828.     }
  829.     if (p.iptrs.sepHdr != NULL) {
  830.         FatalError(ERR_EDIT_DBG_FILE);
  831.     }
  832.     // Read in all of the debug information
  833.     ReadDebugInfo(&p);
  834.     // Open the output file and adjust the pointers.
  835.     if (!MapOutputFile(&p, szOutput,
  836.                        sizeof(szNewName) * 2 + sizeof(IMAGE_DEBUG_MISC))) {
  837.         FatalError(ERR_MAP_FILE, szOutput);
  838.     }
  839.     CalculateOutputFilePointers(&p.iptrs, &p.optrs);
  840.     // Munge the name of the file
  841.     MungeExeName(&p, szNewName);
  842.     // Close the input file
  843.     UnMapInputFile(&p);
  844.     // Write out the debug information to the end of the exe
  845.     WriteDebugInfo(&p, FALSE);
  846.     // and finally compute the checksum
  847.     if (p.iptrs.fileHdr != NULL) {
  848.         ComputeChecksum( szOutput );
  849.     }
  850.     return;
  851. }
  852. void
  853. DoStrip(
  854.     char * szInput,
  855.     char * szOutput
  856.     )
  857. {
  858.     char OutputFile[_MAX_PATH];
  859.     // Make sure we only have the path to the output file (it will always be
  860.     //  named filename.DBG)
  861.     if (szOutput != NULL) {
  862.         CopyFileA(szInput, szOutput, FALSE);
  863.     }
  864.     SplitSymbols(szOutput, NULL, OutputFile, SPLITSYM_EXTRACT_ALL);
  865.     // Always delete the output file.
  866.     DeleteFileA(OutputFile);
  867.     return;
  868. }
  869. void
  870. DoExtract(
  871.     char * szInput,
  872.     char * szOutput,
  873.     char * szDbgFile
  874.     )
  875. {
  876.     char OutputFile[_MAX_PATH];
  877.     char szExt[_MAX_EXT];
  878.     char szFileName[_MAX_FNAME];
  879.     if (szOutput != NULL) {
  880.         CopyFileA(szInput, szOutput, FALSE);
  881.         szInput = strdup(szOutput);
  882.         _splitpath(szOutput, NULL, NULL, szFileName, szExt);
  883.         *(szOutput + strlen(szOutput) - strlen(szFileName) - strlen(szExt)) = '';
  884.     }
  885.     SplitSymbols(szInput, szOutput, OutputFile, 0);
  886.     CopyFileA(szDbgFile, OutputFile, TRUE);
  887.     if (szOutput) {
  888.         free(szInput);
  889.     }
  890.     return;
  891. }