/*++
Copyright 1996 - 1997 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 "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);
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;
#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;
}
__inline void PrintCopyright( void )
{
puts( "\nMicrosoft(R) Windows NT SymEdit Version 1.0\n"
"(C) 1989-1995 Microsoft Corp. All rights reserved.\n");
}
__inline void PrintUsage( void )
{
PrintCopyright();
puts ("\nUsage: SYMEDIT <OPERATION> -q -o<file out> <file in>\n\n"
"\t<OPERATION> is:\n"
"\tC\tModify CodeView 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<name>\tName to change to\n"
"\t-o<file>\tspecify output file\n"
"\t-q\t\tquiet mode\n"
"\t-r\t\tReplace COFF debug info with CV info\n"
"\t-s<file>\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 ||
(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 (toupper(argv[i][1])) {
// Add the CV debug information section rather than
// replace the COFF section with the CV info.
case 'A':
fAddCV = TRUE;
break;
// Specify the output name for the DBG file
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':
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':
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':
fQuiet = TRUE;
fSilent = TRUE;
break;
// Replace COFF debug information with CODEVIEW debug information
case 'R':
break;
// Convert a Symbol File to CV info
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 ) {
// 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
case 'S':
DoStrip(szInputFile, szOutputFile);
break;
}
}
}
return;
}
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 (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;
}
}
}
return;
}
void
WriteDebugInfo(
PPOINTERS p,
BOOL fAddCV
)
/*++
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, flen;
PIMAGE_DEBUG_DIRECTORY pDir, 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);
}
}
}
// Step 3. 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 (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)) {
PIMAGE_COFF_SYMBOLS_HEADER pCoffDbgInfo;
pCoffDbgInfo = (PIMAGE_COFF_SYMBOLS_HEADER)p->optrs.rgpbDebugSave[i];
p->optrs.fileHdr->PointerToSymbolTable =
PointerToDebugData + pCoffDbgInfo->LvaToFirstSymbol;
}
}
PointerToDebugData += p->optrs.rgDebugDir[i]->SizeOfData;
}
}
// 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 it.
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;
}
void
MungeDebugHeadersCoffToCv(
PPOINTERS p,
BOOL fAddCV
)
/*++
Routine Description:
Arguments:
p - pointer to a POINTERS structure (see symcvt.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;
}
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 symcvt.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 );
CloseHandle(hMap);
if (p->optrs.fptr == NULL) {
goto exit;
}
rval = TRUE;
exit:
return rval;
}
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 symcvt.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;
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);
}
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;
}
/*** 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 );
// Free our handles on the input file
UnMapInputFile(&p);
// Write out the debug information to the end of the exe
WriteDebugInfo( &p, fAddCV );
// and finally compute the checksum
if (p.iptrs.fileHdr != NULL) {
ComputeChecksum( szOutput );
}
return;
}
/*** 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;
}
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);
// Close the input file
UnMapInputFile(&p);
// Write out the debug information to the end of the exe
WriteDebugInfo(&p, FALSE);
// and finally compute the checksum
if (p.iptrs.fileHdr != NULL) {
ComputeChecksum( szOutput );
}
return;
}
void
DoStrip(
char * szInput,
char * szOutput
)
{
char OutputFile[_MAX_PATH];
// Make sure we only have the path to the output file (it will always be
// named filename.DBG)
if (szOutput != NULL) {
CopyFileA(szInput, szOutput, FALSE);
}
SplitSymbols(szOutput, NULL, OutputFile, SPLITSYM_EXTRACT_ALL);
// Always delete the output file.
DeleteFileA(OutputFile);
return;
}
void
DoExtract(
char * szInput,
char * szOutput,
char * szDbgFile
)
{
char OutputFile[_MAX_PATH];
char szExt[_MAX_EXT];
char szFileName[_MAX_FNAME];
if (szOutput != NULL) {
CopyFileA(szInput, szOutput, FALSE);
szInput = strdup(szOutput);
_splitpath(szOutput, NULL, NULL, szFileName, szExt);
*(szOutput + strlen(szOutput) - strlen(szFileName) - strlen(szExt)) = '\0';
}
SplitSymbols(szInput, szOutput, OutputFile, 0);
CopyFileA(szDbgFile, OutputFile, TRUE);
if (szOutput) {
free(szInput);
}
return;
}