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() */