File:  [WindowsNT SDKs] / mstools / samples / sdktools / image / symedit / symedit.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:24:28 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-nov-1993, ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993

/*++


Copyright (c) 1992  Microsoft Corporation

Module Name:

    symedit.c

Abstract:


Author:

    Wesley A. Witt (wesw) 19-April-1993

Environment:

    Win32, User Mode

--*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "symcvt.h"
#include "cv.h"
#include "cofftocv.h"
#include "symtocv.h"
#include "strings.h"

#include <imagehlp.h>


/*
 *      prototypes for this module
 */

BOOL    CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po );
void    ProcessCommandLineArgs( int argc, char *argv[] );
void    PrintCopyright( void );
void    PrintUsage( void );
void    FatalError( int, ... );
BOOL    MapOutputFile ( PPOINTERS p, char *fname, int );
void    ComputeChecksum(  char *szExeFile );
void    ReadDebugInfo( PPOINTERS p );
void    WriteDebugInfo( PPOINTERS p, BOOL, BOOL );
void    MungeDebugHeadersCoffToCv( PPOINTERS  p, BOOL fAddCV );
void    MungeExeName( PPOINTERS p, char * szExeName );
void    DoCoffToCv(char *, char *, BOOL);
void    DoSymToCv(char *, char *, char *, char *);
void    DoNameChange(char *, char *, char *);
void    DoExtract(char *, char *, char *);
void    DoStrip(char *, char *);

IMAGE_DEBUG_DIRECTORY   DbgDirSpare;
IMAGE_DEBUG_DIRECTORY   DbgDirCoff;

#define AdjustPtr(ptr) (((ptr) != NULL) ? ((DWORD)ptr - (DWORD)pi->fptr + (DWORD)po->fptr) : ((DWORD)(ptr)))



int _CRTAPI1
main(
     int        argc,
     char *     argv[]
     )
/*++

Routine Description:

    Shell for this utility.

Arguments:

    argc     - argument count
    argv     - argument pointers


Return Value:

    0        - image was converted
    >0       - image could not be converted

--*/

{
    /*
     *  Scan the command line and check what operations we are doing
     */
     
    ProcessCommandLineArgs( argc, argv );
    return 0;
}

void
PrintCopyright( void )

/*++

Routine Description:

    Prints the MS copyright message to stdout.

Arguments:

    void


Return Value:

    void

--*/

{
    printf( "\nMicrosoft(R) Windows NT SymEdit Version 1.0\n" );
    printf( "(C) 1989-1993 Microsoft Corp. All rights reserved.\n\n");
}

void
PrintUsage( void )

/*++

Routine Description:

    Prints the command line help to stdout

Arguments:

    void


Return Value:

    void

--*/

{
    PrintCopyright();
    printf("\nUsage: SYMEDIT <OPERATION> -q -o<file out> <file in>\n\n" );
    printf("\t<OPERATION> is:\n");
    printf("\tA\tAdd debug information\n");
    printf("\tC\tConvert symbol information\n" );
    printf("\tN\tEdit name field\n");
    printf("\tX\tExtract debug information\n");
    printf("\tS\tStrip all debug information\n\n");
    printf("Options:\n");
    printf("\t-a\t\tAdd CodeView debug info to file\n");
    printf("\t-n<name>\tName to change to\n");
    printf("\t-o<file>\tspecify output file\n" );
    printf("\t-q\t\tquiet mode\n" );
    printf("\t-s<file>\tSym file source\n");
}

void
ProcessCommandLineArgs( int argc, char *argv[] )

/*++

Routine Description:

    Processes the command line arguments and sets global flags to
    indicate the user's desired behavior.

Arguments:

    argc     - argument count
    argv     - argument pointers


Return Value:

    void

--*/

{
    int     i;
    BOOL        fQuiet = FALSE;
    BOOL        fSilent = FALSE;
    char *      szOutputFile = NULL;
    char *      szInputFile = NULL;
    char *      szExeName = NULL;
    char *      szDbgFile = NULL;
    char *      szSymFile = NULL;
    int         iOperation;
    BOOLEAN     fAddCV = FALSE;

    /*
     * Minimun number of of arguments is 2 -- program and operation
     */

    if (argc < 2) {
        PrintUsage();
        exit(1);
    }

    if ((strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "?") == 0)) {
        PrintUsage();
        exit(1);
    }

    /*
     *  All operations on 1 character wide
     */
    
    if (argv[1][1] != 0) {
        FatalError(ERR_OP_UNKNOWN, argv[1]);
    }

    /*
     *  Validate the operation
     */
    
    switch( argv[1][0] ) {
    case 'C':
    case 'N':
    case 'X':
    case 'S':
        iOperation = argv[1][0];
        break;
    default:
        FatalError(ERR_OP_UNKNOWN, argv[1]);
    }

    /*
     *  Parse out any other switches on the command line
     */
    
    for (i=2; i<argc; i++) {
        if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
            switch (argv[i][1]) {
                /*
                 *   Add the CV debug information section rather than
                 *  replace the COFF section with the CV info.
                 */
            case 'a':
            case 'A':
                fAddCV = TRUE;
                break;
                
                /*
                 *  Specify the output name for the DBG file
                 */
                
            case 'd':
            case 'D':
                if (argv[i][2] == 0) {
                    i += 1;
                    szDbgFile = argv[i];
                } else {
                    szDbgFile = &argv[i][2];
                }
                break;
                
                /*
                 *  Specify a new name to shove into the name of the
                 *  debuggee field in the Misc. Debug info field
                 */
                
            case 'N':
            case 'n':
                if (argv[i][2] == 0) {
                    i += 1;
                    szExeName = argv[i];
                } else {
                    szExeName = &argv[i][2];
                }
                break;
                
                /*
                 * Specify the name of the output file
                 */
                
            case 'O':
            case 'o':
                if (argv[i][2] == 0) {
                    i += 1;
                    szOutputFile = argv[i];
                } else {
                    szOutputFile = &argv[i][2];
                }
                break;
                
                /*
                 *  Be quite and don't put out the banner
                 */
                
            case 'Q':
            case 'q':
                fQuiet = TRUE;
                fSilent = TRUE;
                break;
                
                /*
                 *  Replace COFF debug information with CODEVIEW debug information
                 */
                
            case 'R':
            case 'r':
                break;
                
                /*
                 *  Convert a Symbol File to CV info
                 */
                
            case 'S':
            case 's':
                if (argv[i][2] == 0) {
                    i += 1;
                    szSymFile = argv[i];
                } else {
                    szSymFile = &argv[i][2];
                }
                break;
                
                /*
                 * Print the command line options
                 */
                
            case '?':
                PrintUsage();
                exit(1);
                break;
                
                /*
                 * Unrecognized option
                 */
                
            default:
                FatalError( ERR_OP_UNKNOWN, argv[i] );
                break;
            }
        } else {
            /*
             *  No leading switch character -- must be a file name
             */
            
            szInputFile = &argv[i][0];
            
            /*
             *  Process the file(s)
             */
            
            if (!fQuiet) {
                PrintCopyright();
                fQuiet = TRUE;
            }

            if (!fSilent) {
                printf("processing file: %s\n", szInputFile );
            }
            
            /*
             *  Do switch validation cheching and setup any missing global variables
             */
            
            switch ( iOperation ) {
                /*
                 *  Add debug information to an exe file
                 *
                 *      Must specify in input file
                 *      Optional outputfile
                 *      Must specify a debug info file
                 */
                
            case 'A':
                break;
                
                /*
                 * For conversions -- there are three types
                 *
                 *      1.  Coff to CV -- add
                 *      2.  Coff to CV -- replace
                 *      3.  SYM to CV --- add
                 *      4.  SYM to CV -- seperate file
                 *
                 *      Optional input file (not needed for case 4)
                 *      Optional output file
                 *      Optional sym file (implys sym->CV)
                 *      Optional DBG file
                 */
                
            case 'C':
                if (szSymFile == NULL) {
                    DoCoffToCv(szInputFile, szOutputFile, fAddCV);
                } else {
                    DoSymToCv(szInputFile, szOutputFile, szDbgFile, szSymFile);
                }
                szInputFile = NULL;
                szOutputFile = NULL;
                szDbgFile = NULL;
                szSymFile = NULL;
                break;
                
                /*
                 *  For changing the name of the debuggee --
                 *      Must specify input file
                 *      Must specify new name
                 *      Optional output file
                 */
                
            case 'N':
                DoNameChange(szInputFile, szOutputFile, szExeName);
                szInputFile = NULL;
                szOutputFile = NULL;
                szExeName = NULL;
                break;
                
                /*
                 *  For extraction of debug information
                 *      Must specify input file
                 *      Optional output file name
                 *      Optional debug file name
                 */
                
            case 'X':
                DoExtract(szInputFile, szOutputFile, szDbgFile);
                break;
                
                /*
                 *  For full strip of debug information
                 *      Must specify input file
                 *      Optional output file
                 *      Optional debug file name
                 */
                
            case 'S':
                DoStrip(szInputFile, szOutputFile);
                break;
            }
        }
    }
    return;
}                               /* ProcessCommandLineArgs() */


void
ReadDebugInfo(
              PPOINTERS         p
              )
/*++

Routine Description:

    This function will go out and read in all of the debug information
    into memory -- this is required because the input and output
    files might be the same, if so then writing out informaiton may
    destory data we need at a later time.

Arguments:

    p   - Supplies a pointer to the structure describing the debug info file

Return Value:

    None.

--*/

{
    int                         i;
    int                         cb;
    char *                      pb;
    PIMAGE_COFF_SYMBOLS_HEADER  pCoffDbgInfo;
    
    
    /*
     *   Allocate space to save pointers to debug info
     */
    
    p->iptrs.rgpbDebugSave = (PCHAR *) malloc(p->iptrs.cDebugDir * sizeof(PCHAR));
    memset(p->iptrs.rgpbDebugSave, 0, p->iptrs.cDebugDir * sizeof(PCHAR));

    /*
     * Check each possible debug type record
     */

    for (i=0; i<p->iptrs.cDebugDir; i++) {
        /*
         *   If there was debug information then copy over the
         *      description block and cache in the actual debug
         *      data.
         */
        
        if ((i != IMAGE_DEBUG_TYPE_COFF) && (p->iptrs.rgDebugDir[i] != NULL)) {
            p->iptrs.rgpbDebugSave[i] =
              malloc( p->iptrs.rgDebugDir[i]->SizeOfData );
            if (p->iptrs.rgpbDebugSave[i] == NULL) {
                FatalError(ERR_NO_MEMORY);
            }
            _try {
                memcpy(p->iptrs.rgpbDebugSave[i],
                       p->iptrs.fptr +
                       p->iptrs.rgDebugDir[i]->PointerToRawData,
                       p->iptrs.rgDebugDir[i]->SizeOfData );
            } _except(EXCEPTION_EXECUTE_HANDLER ) {
                free(p->iptrs.rgpbDebugSave[i]);
                p->iptrs.rgpbDebugSave[i] = NULL;
            }
        }
    }

    /*
     *  Treat COFF debug information seperately -- since the linker loves
     *  to mix it in with other things
     */

    if (p->iptrs.rgDebugDir[IMAGE_DEBUG_TYPE_COFF] != NULL) {
        DbgDirCoff = *COFF_DIR(&p->iptrs);
        
        /*
         *  Allocate space to save the coff debug info
         */
        
        pb = p->iptrs.rgpbDebugSave[i] = malloc(DbgDirCoff.SizeOfData);

        /*
         *  Copy over and point to the description for the
         *      debug info.
         */
        
        memcpy(pb, DbgDirCoff.PointerToRawData + p->iptrs.fptr,
               sizeof(IMAGE_COFF_SYMBOLS_HEADER));
        pCoffDbgInfo = (PIMAGE_COFF_SYMBOLS_HEADER) pb;

        /*
         *  Now figure out how much space we really have -- only things
         *      after the first symbol are "good" -- everything else is
         *      suspect as part of something else.
         */
        
        cb = DbgDirCoff.SizeOfData - pCoffDbgInfo->LvaToFirstSymbol;

        /*
         *  Now copy over the real symbol information and set up the
         *      new pointers in the header record
         */
        
        memcpy(pb+sizeof(IMAGE_COFF_SYMBOLS_HEADER),
               p->iptrs.fptr + DbgDirCoff.PointerToRawData +
               pCoffDbgInfo->LvaToFirstSymbol, cb);
        pCoffDbgInfo->LvaToFirstSymbol = sizeof(IMAGE_COFF_SYMBOLS_HEADER);
        DbgDirCoff.SizeOfData = cb + sizeof(IMAGE_COFF_SYMBOLS_HEADER);
        pCoffDbgInfo->NumberOfLinenumbers = 0;
        pCoffDbgInfo->LvaToFirstLinenumber = 0;
    }
    return;
}                               /* ReadDebugInfo() */



void
WriteDebugInfo(
              PPOINTERS         p,
              BOOL              fAddCV,
              BOOL              fStrip
              )
/*++

Routine Description:

    This function will go out and read in all of the debug information
    into memory -- this is required because the input and output
    files might be the same, if so then writing out informaiton may
    destory data we need at a later time.

Arguments:

    p   - Supplies a pointer to the structure describing the debug info file

Return Value:

    None.

--*/

{
    ULONG       PointerToDebugData = 0; /*  Offset from the start of the file
                                         *  to the current location to write
                                         *  debug information out.
                                         */
    ULONG       BaseOfDebugData = 0;
    int                         i;
    PIMAGE_DEBUG_DIRECTORY      pDir;
    int                         flen;
    PIMAGE_DEBUG_DIRECTORY      pDbgDir = NULL;


    if (p->optrs.debugSection) {
        BaseOfDebugData = PointerToDebugData =
          p->optrs.debugSection->PointerToRawData;
    } else if (p->optrs.sepHdr) {
        BaseOfDebugData =  PointerToDebugData =
          sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
          p->optrs.sepHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
          p->optrs.sepHdr->ExportedNamesSize;
    }


    /*
     *  Step 2. If the debug information is mapped, we know this
     *          from the section headers, then we may need to write
     *          out a new debug director to point to the debug information
     */

    if (fAddCV) {
        if (p->optrs.optHdr) {
            p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].
              VirtualAddress = p->optrs.debugSection->VirtualAddress;
            p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size +=
              sizeof(IMAGE_DEBUG_DIRECTORY);
        } else if (p->optrs.sepHdr) {
            p->optrs.sepHdr->DebugDirectorySize +=
              sizeof(IMAGE_DEBUG_DIRECTORY);
        } else {
            exit(1);
        }

        if (p->optrs.sepHdr) {
            pDbgDir = (PIMAGE_DEBUG_DIRECTORY) malloc(p->optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY));
            for (i=0; i<p->optrs.cDebugDir; i++) {
                if (p->optrs.rgDebugDir[i] != NULL) {
                    pDbgDir[i] = *(p->optrs.rgDebugDir[i]);
                    p->optrs.rgDebugDir[i] = &pDbgDir[i];
                }
            }
        }
        for (i=0; i<p->optrs.cDebugDir; i++) {
            if (p->optrs.rgDebugDir[i]) {
                pDir = (PIMAGE_DEBUG_DIRECTORY) (PointerToDebugData +
                                                 p->optrs.fptr);
                *pDir = *(p->optrs.rgDebugDir[i]);
                p->optrs.rgDebugDir[i] = pDir;
		PointerToDebugData += sizeof(IMAGE_DEBUG_DIRECTORY);
            }
        }
    }

    /*
     *  For every debug info type, write out the debug information
     *  and update any header information required
     */
    
    for (i=0; i<p->optrs.cDebugDir; i++) {
        if (p->optrs.rgDebugDir[i] != NULL) {
            if (!fStrip ||
                (i == IMAGE_DEBUG_TYPE_FPO) ||
                (i == IMAGE_DEBUG_TYPE_MISC)) {
                if (p->optrs.rgpbDebugSave[i] != NULL) {
                    p->optrs.rgDebugDir[i]->PointerToRawData =
                      PointerToDebugData;
                    if (p->optrs.debugSection) {
                        p->optrs.rgDebugDir[i]->AddressOfRawData =
                          p->optrs.debugSection->VirtualAddress +
                            PointerToDebugData - BaseOfDebugData;
                    }
                    memcpy(p->optrs.fptr + PointerToDebugData,
                           p->optrs.rgpbDebugSave[i],
                           p->optrs.rgDebugDir[i]->SizeOfData);

                    if ((i == IMAGE_DEBUG_TYPE_COFF) &&
                        (p->optrs.fileHdr != NULL)) {
                        p->optrs.fileHdr->PointerToSymbolTable =
                          PointerToDebugData + sizeof(IMAGE_COFF_SYMBOLS_HEADER);
                    }
                }
                PointerToDebugData += p->optrs.rgDebugDir[i]->SizeOfData;
            }
        }
    }

    if ((PointerToDebugData == BaseOfDebugData) && fStrip) {
        p->optrs.fileHdr->NumberOfSections -= 1;
    }
     
    /*
     *   Step 4.  Clean up any COFF structures if we are replacing
     *          the coff information with CV info.
     */

    if ((p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_COFF] == NULL) &&
        (p->optrs.fileHdr != NULL)) {
        /*
         *  Since there is no coff debug information -- clean out
         *      both fields pointing to the debug info
         */
        
        p->optrs.fileHdr->PointerToSymbolTable = 0;
        p->optrs.fileHdr->NumberOfSymbols = 0;
    }

    /*
     *  Step 5.  Correct the alignments if needed.  If there is
     *          a real .debug section in the file (i.e. it is mapped)
     *          then update the description of the section.
     */

    if (p->optrs.debugSection) {
        p->optrs.debugSection->SizeOfRawData =
          FileAlign(PointerToDebugData - BaseOfDebugData);
        /*
         * update the optional header with the new image size
         */
        
        p->optrs.optHdr->SizeOfImage =
          SectionAlign(p->optrs.debugSection->VirtualAddress +
                       p->optrs.debugSection->SizeOfRawData);
        p->optrs.optHdr->SizeOfInitializedData +=
          p->optrs.debugSection->SizeOfRawData;
    }

    /*
     *  calculate the new file size
     */

    if (p->optrs.optHdr != NULL) {
        flen = FileAlign(PointerToDebugData);
    } else {
        flen = PointerToDebugData;
    }

    /*
     *  finally, update the eof pointer and close the file
     */
    
    UnmapViewOfFile( p->optrs.fptr );
    
    if (!SetFilePointer( p->optrs.hFile, flen, 0, FILE_BEGIN )) {
        FatalError( ERR_FILE_PTRS );
    }
    
    if (!SetEndOfFile( p->optrs.hFile )) {
        FatalError( ERR_SET_EOF );
    }
    
    CloseHandle( p->optrs.hFile );

    /*
     *  Exit -- we are done.
     */
    
    return;
}                               /* WriteDebugInfo() */



void
MungeDebugHeadersCoffToCv(
                          PPOINTERS  p,
                          BOOL          fAddCV
                          )

/*++

Routine Description:


Arguments:

    p        - pointer to a POINTERS structure (see cofftocv.h)

Return Value:

    void

--*/

{
    if (!fAddCV) {
        CV_DIR(&p->optrs) = COFF_DIR(&p->optrs);
        COFF_DIR(&p->optrs) = 0;
    } else {
        CV_DIR(&p->optrs) = &DbgDirSpare;
        *(COFF_DIR(&p->optrs)) = *(COFF_DIR(&p->iptrs));
    };

    *CV_DIR(&p->optrs) = *(COFF_DIR(&p->iptrs));
    CV_DIR(&p->optrs)->Type = IMAGE_DEBUG_TYPE_CODEVIEW;
    CV_DIR(&p->optrs)->SizeOfData =  p->pCvStart.size;
    p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_CODEVIEW] = p->pCvStart.ptr;
    
    return;
}                               /* MungeDebugHeadersCoffToCv() */



BOOL
MapOutputFile ( PPOINTERS p, char *fname, int cb )

/*++

Routine Description:

    Maps the output file specified by the fname argument and saves the
    file handle & file pointer in the POINTERS structure.


Arguments:

    p        - pointer to a POINTERS structure (see cofftocv.h)
    fname    - ascii string for the file name


Return Value:

    TRUE     - file mapped ok
    FALSE    - file could not be mapped

--*/

{
    BOOL        rval;
    HANDLE      hMap   = NULL;
    DWORD       oSize;

    rval = FALSE;

    p->optrs.hFile = CreateFile( fname,
                        GENERIC_READ | GENERIC_WRITE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_ALWAYS,
                        0,
                        NULL );

    if (p->optrs.hFile == INVALID_HANDLE_VALUE) {
       goto exit;
    }

    oSize = p->iptrs.fsize;
    if (p->pCvStart.ptr != NULL) {
        oSize += p->pCvStart.size;
    }
    oSize += cb;
    oSize += p->iptrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY);

    hMap = CreateFileMapping( p->optrs.hFile, NULL, PAGE_READWRITE,
                              0, oSize, NULL );

    if (hMap == NULL) {
       goto exit;
    }

    p->optrs.fptr = MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 );

    if (p->optrs.fptr == NULL) {
       goto exit;
    }
    rval = TRUE;
exit:
    return rval;
}                               /* MapOutputFile() */

BOOL
CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po )

/*++

Routine Description:

    This function calculates the output file pointers based on the
    input file pointers.  The same address is used but they are all
    re-based off the output file's file pointer.

Arguments:

    p        - pointer to a IMAGEPOINTERS structure (see cofftocv.h)


Return Value:

    TRUE     - pointers were created
    FALSE    - pointers could not be created

--*/
{
    int i;
    
    // fixup the pointers relative the fptr for the output file
    po->dosHdr       = (PIMAGE_DOS_HEADER)      AdjustPtr(pi->dosHdr);
    po->ntHdr        = (PIMAGE_NT_HEADERS)      AdjustPtr(pi->ntHdr);
    po->fileHdr      = (PIMAGE_FILE_HEADER)     AdjustPtr(pi->fileHdr);
    po->optHdr       = (PIMAGE_OPTIONAL_HEADER) AdjustPtr(pi->optHdr);
    po->sectionHdrs  = (PIMAGE_SECTION_HEADER)  AdjustPtr(pi->sectionHdrs);
    po->sepHdr       = (PIMAGE_SEPARATE_DEBUG_HEADER) AdjustPtr(pi->sepHdr);
    po->debugSection = (PIMAGE_SECTION_HEADER)  AdjustPtr(pi->debugSection);
    po->AllSymbols   = (PIMAGE_SYMBOL)          AdjustPtr(pi->AllSymbols);
    po->stringTable  = (PUCHAR)                 AdjustPtr(pi->stringTable);

    // move the data from the input file to the output file
    memcpy( po->fptr, pi->fptr, pi->fsize );

    po->cDebugDir = pi->cDebugDir;
    po->rgDebugDir = malloc(po->cDebugDir * sizeof(po->rgDebugDir[0]));
    memset(po->rgDebugDir, 0, po->cDebugDir * sizeof(po->rgDebugDir[0]));
    
    for (i=0; i<po->cDebugDir; i++) {
        po->rgDebugDir[i] = (PIMAGE_DEBUG_DIRECTORY) AdjustPtr(pi->rgDebugDir[i]);
    }
    po->rgpbDebugSave = pi->rgpbDebugSave;

    /*
     *  Point the input stream to the modified coff descriptor
     */

    if (pi->rgDebugDir[IMAGE_DEBUG_TYPE_COFF] != NULL) {
        pi->rgDebugDir[IMAGE_DEBUG_TYPE_COFF] = &DbgDirCoff;
    }

    return TRUE;
}


void
FatalError(
           int  idMsg,
           ...
           )
/*++

Routine Description:

    Prints a message string to stderr and then exits.

Arguments:

    s        - message string to be printed

Return Value:

    void

--*/

{
    va_list     marker;
    char        rgchFormat[256];
    char        rgch[256];

    LoadString(GetModuleHandle(NULL), idMsg, rgchFormat, sizeof(rgchFormat));
    
    va_start(marker, idMsg);
    vsprintf(rgch, rgchFormat, marker);
    va_end(marker);
    
    fprintf(stderr, "%s\n", rgch);
    
    exit(1);
}                               /* FatalError() */


void
ComputeChecksum(  char *szExeFile )

/*++

Routine Description:

    Computes a new checksum for the image by calling imagehlp.dll

Arguments:

    szExeFile - exe file name


Return Value:

    void

--*/

{
    DWORD              dwHeaderSum = 0;
    DWORD              dwCheckSum = 0;
    HANDLE             hFile;
    DWORD              cb;
    IMAGE_DOS_HEADER   dosHdr;
    IMAGE_NT_HEADERS   ntHdr;

    if (MapFileAndCheckSum(szExeFile, &dwHeaderSum, &dwCheckSum) != CHECKSUM_SUCCESS) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    hFile = CreateFile( szExeFile,
                        GENERIC_READ | GENERIC_WRITE,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL
                      );

    // seek to the beginning of the file
    SetFilePointer( hFile, 0, 0, FILE_BEGIN );

    // read in the dos header
    if ((ReadFile(hFile, &dosHdr, sizeof(dosHdr), &cb, 0) == FALSE) || (cb != sizeof(dosHdr))) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    // read in the pe header
    if ((dosHdr.e_magic != IMAGE_DOS_SIGNATURE) ||
        (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L)) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    // read in the nt header
    if ((!ReadFile(hFile, &ntHdr, sizeof(ntHdr), &cb, 0)) || (cb != sizeof(ntHdr))) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    if (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    ntHdr.OptionalHeader.CheckSum = dwCheckSum;

    if (!WriteFile(hFile, &ntHdr, sizeof(ntHdr), &cb, NULL)) {
        FatalError( ERR_CHECKSUM_CALC );
    }

    CloseHandle(hFile);
    return;
}


void
MungeExeName(
             PPOINTERS          p,
             char *             szExeName
             )
/*++

Routine Description:

    description-of-function.

Arguments:

    argument-name - Supplies | Returns description of argument.
    .
    .

Return Value:

    None.

--*/

{
    PIMAGE_DEBUG_MISC   pMiscIn;
    PIMAGE_DEBUG_MISC   pMiscOut;
    int                 cb;
    int                 i;

    for (i=0; i<p->iptrs.cDebugDir; i++) {
        if (p->optrs.rgDebugDir[i] != 0) {
            *(p->optrs.rgDebugDir[i]) = *(p->iptrs.rgDebugDir[i]);
        }
    }

    pMiscIn = (PIMAGE_DEBUG_MISC)
      p->iptrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC];

    if (p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] == NULL) {
        p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] = &DbgDirSpare;
        memset(&DbgDirSpare, 0, sizeof(DbgDirSpare));
    }
        
    pMiscOut = (PIMAGE_DEBUG_MISC)
      p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC] = 
      malloc(p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +
             strlen(szExeName));
    cb = p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData;

    while ( cb > 0 ) {
        if (pMiscIn->DataType == IMAGE_DEBUG_MISC_EXENAME) {
            pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
            pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
                                strlen(szExeName) + 3) & ~3;
            pMiscOut->Unicode = FALSE;
            strcpy(&pMiscOut->Data[0], szExeName);
            szExeName = NULL;
        } else {
            memcpy(pMiscOut, pMiscIn, pMiscIn->Length);
        }

        p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +=
          (pMiscOut->Length - pMiscIn->Length);
        
        cb -= pMiscIn->Length;
        pMiscIn = (PIMAGE_DEBUG_MISC) (((char *) pMiscIn) + pMiscIn->Length);
        pMiscOut = (PIMAGE_DEBUG_MISC) (((char *) pMiscOut) + pMiscOut->Length);
    }

    if (szExeName) {
        pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
        pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
                            strlen(szExeName) + 3) & ~3;
        pMiscOut->Unicode = FALSE;
        strcpy(&pMiscOut->Data[0], szExeName);
    }
    
    return;
}                               /* MungeExeName() */


/***    DoCoffToCv
 *
 *
 */

void DoCoffToCv(char * szInput, char * szOutput, BOOL fAddCV)
{
    POINTERS    p;
    
    /*
     *  Do default checking
     */
     
    if (szOutput == NULL) {
        szOutput = szInput;
    }

    /*
     *  Open the input file name and setup the pointers into the file
     */
    
    if (!MapInputFile( &p, NULL, szInput )) {
        FatalError( ERR_OPEN_INPUT_FILE, szInput );
    }

    /*
     *  Now, if we thing we are playing with PE exes then we need
     *  to setup the pointers into the map file
     */

    if (!CalculateNtImagePointers( &p.iptrs )) {
        FatalError( ERR_INVALID_PE, szInput );
    }

    /*
     *  We are about to try and do the coff to cv symbol conversion.
     *
     *  Verify that the operation is legal.
     *
     *      1.  We need to have coff debug information to start with
     *      2.  If the debug info is not mapped then we must not
     *              be trying to add CodeView info.
     */
    
    if ((p.iptrs.AllSymbols == NULL) || (COFF_DIR(&p.iptrs) == NULL)) {
        FatalError( ERR_NO_COFF );
    }
    
    if (fAddCV && (p.iptrs.debugSection == 0) && (p.iptrs.sepHdr == NULL)) {
        FatalError( ERR_NOT_MAPPED );
    }
    
    /*
     *  Now go out an preform the acutal conversion.
     */
    
    if (!ConvertCoffToCv( &p )) {
        FatalError( ERR_COFF_TO_CV );
    }
    
    /*
     *  Read in any additional debug information in the file
     */
    
    ReadDebugInfo(&p);
    
    /*
     *  Open the output file and adjust the pointers so that
     *      we are ok.
     */
    
    if (!MapOutputFile( &p, szOutput, 0 )) {
        FatalError( ERR_MAP_FILE, szOutput );
    }
    
    CalculateOutputFilePointers( &p.iptrs, &p.optrs );
    
    /*
     *      Munge the various debug information structures
     *      to preform the correct operations
     */
    
    MungeDebugHeadersCoffToCv( &p, fAddCV );
    
    /*
     *  Write out the debug information to the end of the exe
     */
    
    WriteDebugInfo( &p, fAddCV, FALSE );

    /*
     *  and finally compute the checksum
     */

    if (p.iptrs.fileHdr != NULL) {
        ComputeChecksum( szOutput );
    }

    return;
}                               /* DoCoffToCv() */
 
/***    DoSymToCv
 *
 */

void DoSymToCv(char * szInput, char * szOutput, char * szDbg, char * szSym)
{
    POINTERS    p;
    HANDLE      hFile;
    DWORD       cb;
    OFSTRUCT    ofs;
    
    /*
     *  Open the input file name and setup the pointers into the file
     */
    
    if (!MapInputFile( &p, NULL, szSym )) {
        FatalError(ERR_OPEN_INPUT_FILE, szSym);
    }

    /*
     *   Now preform the desired operation
     */

    if ((szOutput == NULL) && (szDbg == NULL)) {
        szOutput = szInput;
    }
        
    ConvertSymToCv( &p );

    if (szOutput) {
        if (szOutput != szInput) {
            if (OpenFile(szInput, &ofs, OF_EXIST) == 0) {
                FatalError(ERR_OPEN_INPUT_FILE, szInput);
            }
            if (CopyFile(szInput, szOutput, FALSE) == 0) {
                FatalError(ERR_OPEN_WRITE_FILE, szOutput);
            }
        }
        hFile = CreateFile(szOutput, GENERIC_WRITE, 0, NULL,
                           CREATE_ALWAYS,
                           FILE_ATTRIBUTE_NORMAL,  NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            FatalError(ERR_OPEN_WRITE_FILE, szOutput);
        }
        SetFilePointer(hFile, 0, 0, FILE_END);
    } else if (szDbg) {
        hFile = CreateFile(szDbg, GENERIC_WRITE, 0, NULL,
                               OPEN_ALWAYS,
                               FILE_ATTRIBUTE_NORMAL,  NULL);
        if (hFile == INVALID_HANDLE_VALUE) {
            FatalError(ERR_OPEN_WRITE_FILE, szDbg);
        }
    }
    
    WriteFile(hFile, p.pCvStart.ptr, p.pCvStart.size, &cb, NULL);
    CloseHandle(hFile);

    return;
}                               /* DoSymToCv() */


void DoNameChange(char * szInput, char * szOutput, char * szNewName)
{
    POINTERS    p;
    
    /*
     *  Open the input file name and setup the pointers into the file
     */
    
    if (!MapInputFile( &p, NULL, szInput )) {
        FatalError(ERR_OPEN_INPUT_FILE, szInput);
    }

    /*
     *  Now, if we thing we are playing with PE exes then we need
     *  to setup the pointers into the map file
     */

    if (!CalculateNtImagePointers( &p.iptrs )) {
        FatalError(ERR_INVALID_PE, szInput);
    }

    /*
     *   Now preform the desired operation
     */

    if (szOutput == NULL) {
        szOutput = szInput;
    }
    
    if (szNewName == NULL) {
        szNewName = szOutput;
    }

    if (p.iptrs.sepHdr != NULL) {
        FatalError(ERR_EDIT_DBG_FILE);
    }
    
    /*
     *  Read in all of the debug information
     */
    
    ReadDebugInfo(&p);
    
    /*
     *   Open the output file and adjust the pointers.
     */
    
    if (!MapOutputFile(&p, szOutput,
                       sizeof(szNewName) * 2 + sizeof(IMAGE_DEBUG_MISC))) {
        FatalError(ERR_MAP_FILE, szOutput);
    }
    
    CalculateOutputFilePointers(&p.iptrs, &p.optrs);
    
    /*
     *      Munge the name of the file
     */
    
    MungeExeName(&p, szNewName);
    
    /*
     *  Write out the debug information to the end of the exe
     */
    
    WriteDebugInfo(&p, FALSE, FALSE);
    
    /*
     *  and finally compute the checksum
     */

    if (p.iptrs.fileHdr != NULL) {
        ComputeChecksum( szOutput );
    }

    return;
}                               /* DoNameChange() */


void MungeStrip(PPOINTERS p, BOOL fPartial)
{
    PIMAGE_SECTION_HEADER       pSection;
    ULONG                       flen;
    
    if (p->iptrs.debugSection == NULL) {
                                /* unmapped */
        return;
    }
    
    /*
     *  If the last section is not the debug section then
     *  we can't do this.
     */

    pSection = &p->optrs.sectionHdrs[p->iptrs.numberOfSections-1];
    if (p->optrs.debugSection != pSection) {
        exit(1);
    }
    pSection -= 1;

    /*
     *  If full strip ----
     *  Reduced the number of sections by one, but don't bother
     *  actucally removing the section descriptor, its not worth
     *  the time.
     */

    if (!fPartial) {
        p->optrs.numberOfSections -= 1;
        p->optrs.fileHdr->NumberOfSections -= 1;

        /*
         *  If we are doing a full strip then clear out all pointers
         *      to debug info
         */

        p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = 0;
        p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = 0;
        p->optrs.fileHdr->PointerToSymbolTable = 0;
        p->optrs.fileHdr->NumberOfSymbols = 0;

        p->optrs.optHdr->SizeOfImage = SectionAlign(pSection->VirtualAddress +
                                                    pSection->SizeOfRawData);
        p->optrs.optHdr->SizeOfInitializedData -=
          p->optrs.debugSection->SizeOfRawData;

        flen = FileAlign(pSection->VirtualAddress + pSection->SizeOfRawData );
        UnmapViewOfFile( p->optrs.fptr );

        if (!SetFilePointer( p->optrs.hFile, flen, 0, FILE_BEGIN )) {
            FatalError(ERR_FILE_PTRS);
        }

        if (!SetEndOfFile( p->optrs.hFile )) {
            FatalError( ERR_SET_EOF );
        }

        CloseHandle( p->optrs.hFile );

        return;
    }

    /*
     *  Partial strip
     */

    p->optrs.fileHdr->PointerToSymbolTable = 0;
    p->optrs.fileHdr->NumberOfSymbols = 0;

    WriteDebugInfo( p, FALSE, TRUE );

    return;
}                               /* MungeStrip() */

void    DoStrip(char * szInput, char * szOutput)
{
    POINTERS    p;
    
    if (szOutput == NULL) {
        szOutput = szInput;
    }

    /*
     *  Open the input file and setup the pointers into it.
     */

    if (!MapInputFile(&p, NULL, szInput)) {
        FatalError(ERR_OPEN_INPUT_FILE, szInput);
    }

    /*
     *  Now, setup the rest of the input points
     */

    if (!CalculateNtImagePointers(&p.iptrs)) {
        FatalError(ERR_INVALID_PE, szInput);
    }

    /*
     *  Open the output file and adjust the pointers
     */

    if (!MapOutputFile(&p, szOutput, 0)) {
        FatalError(ERR_MAP_FILE, szOutput);
    }

    CalculateOutputFilePointers(&p.iptrs, &p.optrs);

    /*
     *  Munge the file headers
     */

    MungeStrip(&p, FALSE);
    
    ComputeChecksum(szOutput);

    return;
}                               /* DoStrip() */

void DoExtract(char * szInput, char * szOutput, char * szDbgFile)
{
    IMAGE_SEPARATE_DEBUG_HEADER         sepHdr;
    DWORD *                             rgobDbgDir;
    PIMAGE_DEBUG_DIRECTORY              rgDbgDir;
    POINTERS                            p;
    HANDLE                              hFile;
    int                                 cb;
    int                                 i;
    DWORD                               BaseOfDebugData;
    DWORD                               PointerToDebugData;
    
    if (!MapInputFile(&p, NULL, szInput)) {
        FatalError(ERR_OPEN_INPUT_FILE, szInput);
    }

    if (!CalculateNtImagePointers(&p.iptrs)) {
        FatalError(ERR_INVALID_PE, szInput);
    }

    if (szOutput == NULL) {
        szOutput = szInput;
    }
    
    if (!MapOutputFile(&p, szOutput, 0)) {
        FatalError(ERR_MAP_FILE, szOutput);
    }

    ReadDebugInfo(&p);


    CalculateOutputFilePointers(&p.iptrs, &p.optrs);

    /*
     * Open the DBG file to be dumped
     */

    if (szDbgFile == NULL) {
        char    rgchDrive[_MAX_DRIVE];
        char    rgchPath[_MAX_PATH];
        char    rgchBase[_MAX_FNAME];

        _splitpath(szInput, rgchDrive, rgchPath, rgchBase, NULL);
        szDbgFile = malloc(strlen(rgchDrive) + strlen(rgchPath) +
                             strlen(rgchBase) + 5);
        strcpy(szDbgFile, rgchDrive);
        strcat(szDbgFile, rgchPath);
        strcat(szDbgFile, rgchBase);
        strcat(szDbgFile, ".DBG");
    }

    hFile = CreateFile(szDbgFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
                       FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        FatalError(ERR_OPEN_WRITE_FILE, szDbgFile);
    }

    /*
     *  Create a header for the Dbg File
     */

    sepHdr.Signature = IMAGE_SEPARATE_DEBUG_SIGNATURE;
    sepHdr.Flags = 0;
    sepHdr.Machine = p.optrs.fileHdr->Machine;
    sepHdr.Characteristics = 0;
    sepHdr.TimeDateStamp = 0;
    sepHdr.CheckSum = 0;
    sepHdr.ImageBase = 0;
    sepHdr.SizeOfImage = 0;
    sepHdr.NumberOfSections = p.iptrs.numberOfSections;
    sepHdr.ExportedNamesSize = 0;
    sepHdr.DebugDirectorySize = 0;

    WriteFile(hFile, &sepHdr, sizeof(sepHdr), &cb, NULL);

    /*
     *  Put out the new section headers
     */

    for (i=0; i<p.iptrs.numberOfSections; i++) {
        WriteFile(hFile, &p.iptrs.sectionHdrs[i], sizeof(IMAGE_SECTION_HEADER),
                  &cb, NULL);
    }
    
    /*
     *  Put out the export table
     */

    for (i=0; i<p.iptrs.numberOfSections; i++) {
        if (strcmp(p.iptrs.sectionHdrs[i].Name, ".edata") == 0) {
            WriteFile(hFile,
                      p.iptrs.fptr + p.iptrs.sectionHdrs[i].PointerToRawData,
                      p.iptrs.sectionHdrs[i].SizeOfRawData, &cb, NULL);
            sepHdr.ExportedNamesSize = p.iptrs.sectionHdrs[i].SizeOfRawData;
            break;
        }
    }
    
    /*
     *  Put out the new dbg directory headers
     */

    BaseOfDebugData = PointerToDebugData =
      SetFilePointer(hFile, 0, 0, FILE_CURRENT);
    
    rgobDbgDir = (DWORD *) malloc(p.optrs.cDebugDir * sizeof(DWORD));
    rgDbgDir = (PIMAGE_DEBUG_DIRECTORY)
      malloc(p.optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY));
    memset(rgobDbgDir, 0, p.optrs.cDebugDir * sizeof(DWORD));
    memset(rgDbgDir, 0, p.optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY));
    
    for (i=0; i<p.iptrs.cDebugDir; i++) {
        if (p.iptrs.rgDebugDir[i] != NULL) {
            WriteFile(hFile, p.iptrs.rgDebugDir[i],
                      sizeof(IMAGE_DEBUG_DIRECTORY), &cb, NULL);
            rgobDbgDir[i] = PointerToDebugData;
            rgDbgDir[i] = *(p.iptrs.rgDebugDir[i]);
            PointerToDebugData += sizeof(IMAGE_DEBUG_DIRECTORY);
            sepHdr.DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
        }
    }

    /*
     *  Write out debug info
     */

    for (i=0; i<p.iptrs.cDebugDir; i++) {
        if (p.iptrs.rgDebugDir[i] != NULL) {
            p.optrs.rgDebugDir[i]->AddressOfRawData = 0;
            rgDbgDir[i].AddressOfRawData = 0;
            p.optrs.rgDebugDir[i]->PointerToRawData =
              rgDbgDir[i].PointerToRawData =
                SetFilePointer(hFile, 0, 0, FILE_CURRENT);
            WriteFile(hFile, p.iptrs.rgpbDebugSave[i], rgDbgDir[i].SizeOfData,
                      &cb, NULL);
        }
    }
                      

    /*
     *
     */

    p.optrs.fileHdr->Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
    MungeStrip(&p, TRUE);

    ComputeChecksum(szOutput);

    UnmapViewOfFile( p.iptrs.fptr );
    CloseHandle( p.iptrs.hFile);

    if (!MapInputFile(&p, NULL, szOutput)) {
        FatalError(ERR_OPEN_INPUT_FILE, szOutput);
    }

    if (!CalculateNtImagePointers(&p.iptrs)) {
        FatalError(ERR_INVALID_PE, szOutput);
    }

    /*
     *   Correct the header and the debug directory records
     */

    sepHdr.Characteristics = p.iptrs.fileHdr->Characteristics;
    sepHdr.TimeDateStamp = p.iptrs.fileHdr->TimeDateStamp;
    sepHdr.CheckSum = p.iptrs.optHdr->CheckSum;
    sepHdr.ImageBase = p.iptrs.optHdr->ImageBase;
    sepHdr.SizeOfImage = p.iptrs.optHdr->SizeOfImage;
    
    SetFilePointer(hFile, 0, 0, FILE_BEGIN);
    WriteFile(hFile, &sepHdr, sizeof(sepHdr), &cb, NULL);
    SetFilePointer(hFile, BaseOfDebugData, 0, FILE_BEGIN);
    for (i=0; i<p.iptrs.cDebugDir; i++) {
        if (p.iptrs.rgDebugDir[i] != NULL) {
            WriteFile(hFile, &rgDbgDir[i],
                      sizeof(IMAGE_DEBUG_DIRECTORY), &cb, NULL);
        }
    }

    UnmapViewOfFile( p.iptrs.fptr );
    CloseHandle( p.iptrs.hFile);
    CloseHandle(hFile);

    return;
}                               /* DoExtract() */

void DoJoin(char * szInput, char * szOutput, char * szDbgFile)
{
}                               /* DoJoin() */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.