FILE.C

/*++ 


Copyright 1996 - 1997 Microsoft Corporation

Module Name:

file.c

Abstract:

This module handles all file i/o for SYMCVT. This includes the
mapping of all files and establishing all file pointers for the
mapped file(s).

Author:

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

Environment:

Win32, User Mode

--*/

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

#define _SYMCVT_SOURCE_
#include "symcvt.h"

static BOOL CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po );
static BOOL CalculateInputFilePointers( PIMAGEPOINTERS p );



BOOL
MapInputFile (
PPOINTERS p,
HANDLE hFile,
char * fname
)
/*++

Routine Description:

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


Arguments:

p - Supplies pointer to a POINTERS structure
hFile - OPTIONAL Supplies handle for file if already open
fname - Supplies ascii string for the file name

Return Value:

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

--*/

{
BOOL rVal = TRUE;
DWORD lwFsize;

memset( p, 0, sizeof(POINTERS) );

strcpy( p->iptrs.szName, fname );

if (hFile != NULL) {

p->iptrs.hFile = hFile;

} else {

p->iptrs.hFile = CreateFile( p->iptrs.szName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
}

if (p->iptrs.hFile == INVALID_HANDLE_VALUE) {

rVal = FALSE;

} else {

p->iptrs.fsize = GetFileSize( p->iptrs.hFile, NULL );
if (lwFsize == 0xffffffff) {
;
}
p->iptrs.hMap = CreateFileMapping( p->iptrs.hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL
);

if (p->iptrs.hMap == INVALID_HANDLE_VALUE) {

p->iptrs.hMap = NULL;
rVal = FALSE;

} else {

p->iptrs.fptr = MapViewOfFile( p->iptrs.hMap,
FILE_MAP_READ,
0, 0, 0 );
if (p->iptrs.fptr == NULL) {
CloseHandle( p->iptrs.hMap );
p->iptrs.hMap = NULL;
rVal = FALSE;
}
}
}

if (!hFile && p->iptrs.hFile != INVALID_HANDLE_VALUE) {
CloseHandle(p->iptrs.hFile);
p->iptrs.hFile = NULL;
}

return rVal;
} /* MapInputFile() */



BOOL
UnMapInputFile (
PPOINTERS p
)
/*++

Routine Description:

Unmaps the input file specified by the fname argument and then
closes the file.


Arguments:

p - pointer to a POINTERS structure

Return Value:

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

--*/

{
if ( p->iptrs.fptr ) {
UnmapViewOfFile( p->iptrs.fptr );
p->iptrs.fptr = NULL;
}
if ( p->iptrs.hMap ) {
CloseHandle( p->iptrs.hMap );
p->iptrs.hMap = NULL;
}
if (p->iptrs.hFile != NULL) {
CloseHandle( p->iptrs.hFile );
p->iptrs.hFile = NULL;
}
return TRUE;
} /* UnMapInputFile() */


BOOL
FillInSeparateImagePointers(
PIMAGEPOINTERS p
)
/*++

Routine Description:

This routine will go through the exe file and fill in the
pointers needed relative to the separate debug information files

Arguments:

p - Supplies the structure to fill in

Return Value:

TRUE if successful and FALSE otherwise.

--*/

{
int li;
int numDebugDirs;
PIMAGE_DEBUG_DIRECTORY pDebugDir;
PIMAGE_COFF_SYMBOLS_HEADER pCoffHdr;

p->sectionHdrs = (PIMAGE_SECTION_HEADER)
(p->fptr + sizeof(IMAGE_SEPARATE_DEBUG_HEADER));

numDebugDirs = p->sepHdr->DebugDirectorySize/sizeof(IMAGE_DEBUG_DIRECTORY);

if (numDebugDirs == 0) {
return FALSE;
}

/*
* For each debug directory, determine the debug directory type
* and cache any information about them.
*/

pDebugDir = (PIMAGE_DEBUG_DIRECTORY)
(p->fptr + sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
p->sepHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
p->sepHdr->ExportedNamesSize);

for (li=0; li<numDebugDirs; li++, pDebugDir++) {
if (((int) pDebugDir->Type) > p->cDebugDir) {
p->cDebugDir += 10;
p->rgDebugDir = realloc((char *) p->rgDebugDir,
p->cDebugDir * sizeof(p->rgDebugDir[0]));
memset(&p->rgDebugDir[p->cDebugDir-10], 0,
10*sizeof(p->rgDebugDir[0]));
}

p->rgDebugDir[pDebugDir->Type] = pDebugDir;
}

if (p->rgDebugDir[IMAGE_DEBUG_TYPE_COFF] != NULL) {
pCoffHdr = (PIMAGE_COFF_SYMBOLS_HEADER) (p->fptr +
p->rgDebugDir[IMAGE_DEBUG_TYPE_COFF]->PointerToRawData);
p->AllSymbols = (PIMAGE_SYMBOL)
((char *) pCoffHdr + pCoffHdr->LvaToFirstSymbol);
p->stringTable = pCoffHdr->NumberOfSymbols * IMAGE_SIZEOF_SYMBOL +
(char *) p->AllSymbols;
p->numberOfSymbols = pCoffHdr->NumberOfSymbols;
}
p->numberOfSections = p->sepHdr->NumberOfSections;

return TRUE;
} /* FillInSeparateImagePointers() */



BOOL
CalculateNtImagePointers(
PIMAGEPOINTERS p
)
/*++

Routine Description:

This function reads an NT image and its associated COFF headers
and file pointers and build a set of pointers into the mapped image.
The pointers are all relative to the image's mapped file pointer
and allow direct access to the necessary data.

Arguments:

p - pointer to a IMAGEPOINTERS structure

Return Value:

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

--*/
{
PIMAGE_DEBUG_DIRECTORY debugDir;
PIMAGE_SECTION_HEADER sh;
DWORD i, li, rva, numDebugDirs;
PIMAGE_FILE_HEADER pFileHdr;
PIMAGE_OPTIONAL_HEADER pOptHdr;
DWORD offDebugInfo;

try {
/*
* Based on wheither or not we find the dos (MZ) header
* at the beginning of the file, attempt to get a pointer
* to where the PE header is suppose to be.
*/

p->dosHdr = (PIMAGE_DOS_HEADER) p->fptr;
if (p->dosHdr->e_magic == IMAGE_DOS_SIGNATURE) {
p->ntHdr = (PIMAGE_NT_HEADERS)
((DWORD)p->dosHdr->e_lfanew + p->fptr);
p->fRomImage = FALSE;
} else if (p->dosHdr->e_magic == IMAGE_SEPARATE_DEBUG_SIGNATURE) {
p->sepHdr = (PIMAGE_SEPARATE_DEBUG_HEADER) p->fptr;
p->dosHdr = NULL;
p->fRomImage = FALSE;
return FillInSeparateImagePointers(p);
} else {
p->romHdr = (PIMAGE_ROM_HEADERS) p->fptr;
if (p->romHdr->FileHeader.SizeOfOptionalHeader ==
IMAGE_SIZEOF_ROM_OPTIONAL_HEADER &&
p->romHdr->OptionalHeader.Magic ==
IMAGE_ROM_OPTIONAL_HDR_MAGIC) {
//
// its a rom image
//
p->fRomImage = TRUE;
p->ntHdr = NULL;
p->dosHdr = NULL;
} else {
p->fRomImage = FALSE;
p->ntHdr = (PIMAGE_NT_HEADERS) p->fptr;
p->dosHdr = NULL;
p->romHdr = NULL;
}
}

/*
* What comes next must be a PE header. If not then pop out
*/

if ( p->ntHdr ) {
if ( p->dosHdr && (DWORD)p->dosHdr->e_lfanew > (DWORD)p->fsize ) {
return FALSE;
}

if ( p->ntHdr->Signature != IMAGE_NT_SIGNATURE ) {
return FALSE;
}

/*
* We did find a PE header so start setting pointers to various
* structures in the exe file.
*/

pFileHdr = p->fileHdr = &p->ntHdr->FileHeader;
pOptHdr = p->optHdr = &p->ntHdr->OptionalHeader;
} else if (p->romHdr) {
pFileHdr = p->fileHdr = &p->romHdr->FileHeader;
pOptHdr = (PIMAGE_OPTIONAL_HEADER) &p->romHdr->OptionalHeader;
p->optHdr = (PIMAGE_OPTIONAL_HEADER) &p->romHdr->OptionalHeader;
} else {
return FALSE;
}

if (!(pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {
return FALSE;
}

if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
return(FALSE);
}

/*
* If they exists then get a pointer to the symbol table and
* the string table
*/

if (pFileHdr->PointerToSymbolTable) {
p->AllSymbols = (PIMAGE_SYMBOL)
(pFileHdr->PointerToSymbolTable + p->fptr);
p->stringTable = (LPSTR)((ULONG)p->AllSymbols +
(IMAGE_SIZEOF_SYMBOL * pFileHdr->NumberOfSymbols));
p->numberOfSymbols = pFileHdr->NumberOfSymbols;
}

p->numberOfSections = pFileHdr->NumberOfSections;

if (p->romHdr) {

sh = p->sectionHdrs = (PIMAGE_SECTION_HEADER) (p->romHdr+1);

p->cDebugDir = 10;
p->rgDebugDir = calloc(sizeof(IMAGE_DEBUG_DIRECTORY) * 10, 1);

debugDir = 0;

for (i=0; i<pFileHdr->NumberOfSections; i++, sh++) {
if (!strcmp(sh->Name, ".rdata")) {
debugDir = (PIMAGE_DEBUG_DIRECTORY)(sh->PointerToRawData + p->fptr);
}

if (strncmp(sh->Name,".debug",8)==0) {
p->debugSection = sh;
}
}

if (debugDir) {
do {
if ((int)debugDir->Type > p->cDebugDir) {
p->cDebugDir += 10;
p->rgDebugDir = realloc((char *) p->rgDebugDir,
p->cDebugDir * sizeof(p->rgDebugDir[0]));
memset(&p->rgDebugDir[p->cDebugDir-10],
0,
10*sizeof(IMAGE_DEBUG_DIRECTORY));
}
p->rgDebugDir[debugDir->Type] = debugDir;
debugDir++;
} while (debugDir->Type != 0);
}
} else {

/*
* Locate the debug directory
*/

rva =
pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;

numDebugDirs =
pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
sizeof(IMAGE_DEBUG_DIRECTORY);

if (numDebugDirs == 0) {
return FALSE;
}

sh = p->sectionHdrs = IMAGE_FIRST_SECTION( p->ntHdr );

/*
* Find the section the debug directory is in.
*/

for (i=0; i<pFileHdr->NumberOfSections; i++, sh++) {
if (rva >= sh->VirtualAddress &&
rva < sh->VirtualAddress+sh->SizeOfRawData) {
break;
}
}

/*
* For each debug directory, determine the debug directory
* type and cache any information about them.
*/

debugDir = (PIMAGE_DEBUG_DIRECTORY) ( rva - sh->VirtualAddress +
sh->PointerToRawData +
p->fptr );

for (li=0; li<numDebugDirs; li++, debugDir++) {
if (((int) debugDir->Type) > p->cDebugDir) {
p->cDebugDir += 10;
p->rgDebugDir = realloc((char *) p->rgDebugDir,
p->cDebugDir * sizeof(p->rgDebugDir[0]));
memset(&p->rgDebugDir[p->cDebugDir-10], 0,
10*sizeof(p->rgDebugDir[0]));
}
p->rgDebugDir[debugDir->Type] = debugDir;
offDebugInfo = debugDir->AddressOfRawData;
}

/*
* Check to see if the debug information is mapped and if
* there is a section called .debug
*/

sh = p->sectionHdrs = IMAGE_FIRST_SECTION( p->ntHdr );

for (i=0; i<pFileHdr->NumberOfSections; i++, sh++) {
if ((offDebugInfo >= sh->VirtualAddress) &&
(offDebugInfo < sh->VirtualAddress+sh->SizeOfRawData)) {
p->debugSection = sh;
break;
}
}
}

return TRUE;
} except (EXCEPTION_EXECUTE_HANDLER) {
return FALSE;
}
} /* CalcuateNtImagePointers() */