home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / image / symedit / symedit.c < prev   
C/C++ Source or Header  |  1997-10-05  |  32KB  |  1,210 lines

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