/*++ Copyright (c) 1992 Microsoft Corporation Module Name: symedit.c Abstract: Author: Wesley A. Witt (wesw) 19-April-1993 Environment: Win32, User Mode --*/ #include #include #include #include #include "symcvt.h" #include "cv.h" #include "cofftocv.h" #include "symtocv.h" #include "strings.h" #include /* * 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 *); IMAGE_DEBUG_DIRECTORY DbgDirSpare; IMAGE_DEBUG_DIRECTORY DbgDirCoff; #define AdjustPtr(ptr) (((ptr) != NULL) ? ((DWORD)ptr - (DWORD)pi->fptr + (DWORD)po->fptr) : ((DWORD)(ptr))) int WINAPIV 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 --*/ { puts( "\nMicrosoft(R) Windows NT SymEdit Version 3.51\n" "(C) 1989-1995 Microsoft Corp. All rights reserved.\n"); } void PrintUsage( void ) /*++ Routine Description: Prints the command line help to stdout Arguments: void Return Value: void --*/ { PrintCopyright(); puts("\nUsage: SYMEDIT -q -o \n\n" "\t is:\n" "\tA\tAdd debug information\n" "\tC\tConvert symbol information\n" "\tN\tEdit name field\n" "\tX\tExtract debug information\n" "\tS\tStrip all debug information\n\n" "Options:\n" "\t-a\t\tAdd CodeView debug info to file\n" "\t-n\tName to change to\n" "\t-o\tspecify output file\n" "\t-q\t\tquiet mode\n" "\t-s\tSym file source"); } 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; iCV) * 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': case 'S': DoExtract(szInputFile); 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; iiptrs.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; ioptrs.cDebugDir; i++) { if (p->optrs.rgDebugDir[i] != NULL) { pDbgDir[i] = *(p->optrs.rgDebugDir[i]); p->optrs.rgDebugDir[i] = &pDbgDir[i]; } } } for (i=0; ioptrs.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; ioptrs.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; icDebugDir; 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 dbghelp.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; iiptrs.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) == (HFILE)INVALID_HANDLE_VALUE) { 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 DoExtract( char * szInput ) { char OutFile[_MAX_PATH]; // Just call SplitSymbols in dbghelp.dll SplitSymbols(szInput, NULL, OutFile, SPLITSYM_EXTRACT_ALL); printf("Symbols for \"%s\" extracted into \"%s\"\n", szInput, OutFile); }