diff -r e1b950c65cb4 -r 837f303aceeb epoc32/include/f32image.h --- a/epoc32/include/f32image.h Wed Mar 31 12:27:01 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1239 +0,0 @@ -// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the License "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members -// which accompanies this distribution, and is available -// at the URL "http://www.symbianfoundation.org/legal/licencesv10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// f32\inc\f32image.h -// -// - - - -/** - @file f32\inc\f32image.h - @internalTechnology -*/ - -#ifndef __F32IMAGE_H__ -#define __F32IMAGE_H__ -#include - -/** -Value used for E32ImageHeader::iCpuIdentifier. -*/ -enum TCpu - { - ECpuUnknown=0, ECpuX86=0x1000, ECpuArmV4=0x2000, ECpuArmV5=0x2001, ECpuArmV6=0x2002, ECpuMCore=0x4000 - }; - -/** -Ordinal value of the first entry in an executables export directory. -@see E32ImageHeader::iExportDirOffset. -*/ -const TInt KOrdinalBase=1; - -/** -Value used to initialise E32ImageHeader::iHeaderCrc prior to CRC generation. -*/ -const TUint32 KImageCrcInitialiser = 0xc90fdaa2u; - - -/** -Byte offset from an executable's entrypoint to the code segment ID storage location. -*/ -const TUint KCodeSegIdOffset = 12; - -// -// Flags fields for E32ImageHeader::iFlags -// - -const TUint KImageDll = 0x00000001u; ///< Flag set if executable is a DLL, clear if an EXE. - -const TUint KImageNoCallEntryPoint = 0x00000002u; ///< Obsolete flag ignored since Symbian OS version 8.1b. - -const TUint KImageFixedAddressExe = 0x00000004u; ///< Executable's data should not move when running on the moving memory model. - -const TUint KImageABIMask = 0x00000018u; ///< Bitmask for ABI value. -const TInt KImageABIShift = 3; ///< Bit shift count for ABI value. -const TUint KImageABI_GCC98r2 = 0x00000000u; ///< Obsolete ABI for ARM targets. -const TUint KImageABI_EABI = 0x00000008u; ///< ARM EABI - -const TUint KImageEptMask = 0x000000e0u; ///< Bitmask for Entrypoint value. -const TInt KImageEptShift = 5; ///< Bit shift count for Entrypoint value -const TUint KImageEpt_Eka1 = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b. -const TUint KImageEpt_Eka2 = 0x00000020u; ///< Standard entrypoint for ARM executable. - -const TUint KImageUnpaged = 0x00000100u; ///< Executable image should not be demand paged. Exclusive with KImagePaged, -const TUint KImagePaged = 0x00000200u; ///< Executable image should be demand paged. Exclusive with KImageUnpaged, - -const TUint KImageNmdExpData = 0x00000400u; ///< Flag to indicate when named symbol export data present in image - -const TUint KImageDebuggable = 0x00000800u; ///< Flag to indicate image is debuggable - -const TUint KImageHWFloatMask = 0x00f00000u; ///< Bitmask for Floating Point type. -const TInt KImageHWFloatShift = 20; ///< Bit shift count for Floating Point type. -const TUint KImageHWFloat_None = EFpTypeNone << KImageHWFloatShift; ///< No hardware floating point used. -const TUint KImageHWFloat_VFPv2 = EFpTypeVFPv2 << KImageHWFloatShift; ///< ARM VFPv2 floating point used. - -const TUint KImageHdrFmtMask = 0x0f000000u; ///< Bitmask for header format type. -const TInt KImageHdrFmtShift = 24; ///< Bit shift count for header format type. -const TUint KImageHdrFmt_Original = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b. -const TUint KImageHdrFmt_J = 0x01000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b. -const TUint KImageHdrFmt_V = 0x02000000u; ///< Header has format given by class E32ImageHeaderV. - -const TUint KImageImpFmtMask = 0xf0000000u; ///< Bitmask for import section format type. -const TInt KImageImpFmtShift = 28; ///< Bit shift count for import section format type. -const TUint KImageImpFmt_PE = 0x00000000u; ///< PE-derived imports. -const TUint KImageImpFmt_ELF = 0x10000000u; ///< ELF-derived imports. -const TUint KImageImpFmt_PE2 = 0x20000000u; ///< PE-derived imports without redundant copy of import ordinals. - - - - -// forward references... -class RFile; -class E32RelocSection; - - -/** -Structure for an executable image's header. -This is extended by E32ImageHeaderComp and E32ImageHeaderV. -All executables since Symbian OS version 8.1b have an header given by class E32ImageHeaderV. - -Summary of an executable image structure... - -- Header, 0..iCodeOffset-1 -- Code part, iCodeOffset..iCodeOffset+iCodeSize-1 - - .text section, 0 + iTextSize - - Import Address Table (IAT), iText + ? - - Export Directory, iExportDirOffset + iExportDirCount*4 (in .text Section) -- Rest of data, iCodeOffset+iCodeSize..EOF - - .data section, iDataOffset + iDataSize - - Import section, iImportOffset + sizeof(E32ImportSection)+? - - Code relocation section, iCodeRelocOffset + sizeof(E32RelocSection)+? - - Data relocation section, iDataRelocOffset + sizeof(E32RelocSection)+? -*/ -class E32ImageHeader - { -public: - static TInt New(E32ImageHeader*& aHdr, RFile& aFile); - static TInt New(E32ImageHeader*& aHdr, TUint8* aFileData, TUint32 aFileSize); - TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const; - - inline static TUint ABIFromFlags(TUint aFlags); - inline static TUint EptFromFlags(TUint aFlags); - inline static TUint HdrFmtFromFlags(TUint aFlags); - inline static TUint ImpFmtFromFlags(TUint aFlags); - - inline TUint ABI() const; - inline TUint EntryPointFormat() const; - inline TUint HeaderFormat() const; - inline TUint ImportFormat() const; - - inline TUint32 CompressionType() const; - inline TUint32 ModuleVersion() const; - inline TInt TotalSize() const; - inline TInt UncompressedFileSize() const; - inline void GetSecurityInfo(SSecurityInfo& aInfo) const; - inline TCpu CpuIdentifier() const; - inline TProcessPriority ProcessPriority() const; - inline TUint32 ExceptionDescriptor() const; -public: - TUint32 iUid1; ///< KDynamicLibraryUidValue or KExecutableImageUidValue - TUint32 iUid2; ///< Second UID for executable. - TUint32 iUid3; ///< Third UID for executable. - TUint32 iUidChecksum; ///< Checksum for iUid1, iUid2 and iUid3. - TUint iSignature; ///< Contains 'EPOC'. - TUint32 iHeaderCrc; ///< CRC-32 of entire header. @see #KImageCrcInitialiser. - TUint32 iModuleVersion; ///< Version number for this executable (used in link resolution). - TUint32 iCompressionType; ///< Type of compression used for file contents located after the header. (UID or 0 for none). - TVersion iToolsVersion; ///< Version number of tools which generated this file. - TUint32 iTimeLo; ///< Least significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000. - TUint32 iTimeHi; ///< Most significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000. - TUint iFlags; ///< Contains various bit-fields of attributes for the image. - TInt iCodeSize; ///< Size of executables code. Includes import address table, constant data and export directory. - TInt iDataSize; ///< Size of executables initialised data. - TInt iHeapSizeMin; ///< Minimum size for an EXEs runtime heap memory. - TInt iHeapSizeMax; ///< Maximum size for an EXEs runtime heap memory. - TInt iStackSize; ///< Size for stack required by an EXEs initial thread. - TInt iBssSize; ///< Size of executables uninitialised data. - TUint iEntryPoint; ///< Offset into code of the entry point. - TUint iCodeBase; ///< Virtual address that the executables code is linked for. - TUint iDataBase; ///< Virtual address that the executables data is linked for. - TInt iDllRefTableCount; ///< Number of executable against which this executable is linked. The number of files mention in the import section at iImportOffset. - TUint iExportDirOffset; ///< Byte offset into file of the export directory. - TInt iExportDirCount; ///< Number of entries in the export directory. - TInt iTextSize; ///< Size of just the text section, also doubles as the offset for the Import Address Table w.r.t. the code section. - TUint iCodeOffset; ///< Offset into file of the code section. Also doubles the as header size. - TUint iDataOffset; ///< Offset into file of the data section. - TUint iImportOffset; ///< Offset into file of the import section (E32ImportSection). - TUint iCodeRelocOffset; ///< Offset into file of the code relocation section (E32RelocSection). - TUint iDataRelocOffset; ///< Offset into file of the data relocation section (E32RelocSection). - TUint16 iProcessPriority; ///< Initial runtime process priorty for an EXE. (Value from enum TProcessPriority.) - TUint16 iCpuIdentifier; ///< Value from enum TCpu which indicates the CPU architecture for which the image was created - }; - - -/** -Extends E32ImageHeader. -*/ -class E32ImageHeaderComp : public E32ImageHeader - { -public: - TUint32 iUncompressedSize; ///< Uncompressed size of file data after the header, or zero if file not compressed. - }; - - -/** -Extends E32ImageHeaderComp. -All Symbian OS executable files have a header in this format since OS version 8.1b. -*/ -class E32ImageHeaderV : public E32ImageHeaderComp - { -public: - SSecurityInfo iS; ///< Platform Security information of executable. - TUint32 iExceptionDescriptor; ///< Offset in bytes from start of code section to Exception Descriptor, bit 0 set if valid. - TUint32 iSpare2; ///< Reserved for future use. Set to zero. - TUint16 iExportDescSize; ///< Size of export description stored in iExportDesc. - TUint8 iExportDescType; ///< Type of description of holes in export table - TUint8 iExportDesc[1]; ///< Description of holes in export table, size given by iExportDescSize.. -public: - TInt ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const; - TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const; - TInt ValidateExportDescription() const; - TInt ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const; - TInt ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const; - TInt ValidateAndAdjust(TUint32 aFileSize); - }; - -// export description type E32ImageHeaderV::iExportDescType -const TUint KImageHdr_ExpD_NoHoles =0x00; ///< No holes, all exports present. -const TUint KImageHdr_ExpD_FullBitmap =0x01; ///< Full bitmap present at E32ImageHeaderV::iExportDesc -const TUint KImageHdr_ExpD_SparseBitmap8 =0x02; ///< Sparse bitmap present at E32ImageHeaderV::iExportDesc, granularity 8 -const TUint KImageHdr_ExpD_Xip =0xff; ///< XIP file - - -// -// inline getters for E32ImageHeader -// - -/** -Extract ABI type from aFlags. -*/ -inline TUint E32ImageHeader::ABIFromFlags(TUint aFlags) - { - return aFlags & KImageABIMask; - } - -/** -Extract ABI type from #iFlags. -*/ -inline TUint E32ImageHeader::ABI() const - { - return ABIFromFlags(iFlags); - } - -/** -Extract entrypoint format from aFlags. -*/ -inline TUint E32ImageHeader::EptFromFlags(TUint aFlags) - { - return aFlags & KImageEptMask; - } - -/** -Extract entrypoint format from #iFlags. -*/ -inline TUint E32ImageHeader::EntryPointFormat() const - { - return EptFromFlags(iFlags); - } - -/** -Extract header format from aFlags. -*/ -inline TUint E32ImageHeader::HdrFmtFromFlags(TUint aFlags) - { - return aFlags & KImageHdrFmtMask; - } - -/** -Extract header format from #iFlags. -*/ -inline TUint E32ImageHeader::HeaderFormat() const - { - return HdrFmtFromFlags(iFlags); - } - -/** -Extract import format from aFlags. -*/ -inline TUint E32ImageHeader::ImpFmtFromFlags(TUint aFlags) - { - return aFlags & KImageImpFmtMask; - } - -/** -Extract import format from #iFlags. -*/ -inline TUint E32ImageHeader::ImportFormat() const - { - return ImpFmtFromFlags(iFlags); - } - -/** -Return #iCompressionType. -*/ -inline TUint32 E32ImageHeader::CompressionType() const - { - return iCompressionType; - } - -/** -Return #iModuleVersion. -*/ -inline TUint32 E32ImageHeader::ModuleVersion() const - { - return iModuleVersion; - } - -/** -Return size of this header. -*/ -inline TInt E32ImageHeader::TotalSize() const - { - return iCodeOffset; - } - -/** -Return total size of file after decompression, or -1 if file not compressed. -*/ -inline TInt E32ImageHeader::UncompressedFileSize() const - { - if(iCompressionType==0) - return -1; // not compressed - else - return ((E32ImageHeaderComp*)this)->iUncompressedSize + TotalSize(); - } - -/** -Return copy of security info, #E32ImageHeaderV::iS. -*/ -inline void E32ImageHeader::GetSecurityInfo(SSecurityInfo& aInfo) const - { - aInfo = ((E32ImageHeaderV*)this)->iS; - } - -/** -Return #iCpuIdentifier. -*/ -inline TCpu E32ImageHeader::CpuIdentifier() const - { - return (TCpu)iCpuIdentifier; - } - -/** -Return #iProcessPriority. -*/ -inline TProcessPriority E32ImageHeader::ProcessPriority() const - { - return (TProcessPriority)iProcessPriority; - } - -/** -Return fffset in bytes from start of code section for the Exception Descriptor. -Or zero if not present. -*/ -inline TUint32 E32ImageHeader::ExceptionDescriptor() const - { - TUint32 xd = ((E32ImageHeaderV*)this)->iExceptionDescriptor; - - if((xd & 1) && (xd != 0xffffffffu)) - return (xd & ~1); - - return 0; - } - - -/** -A block of imports from a single executable. -These structures are conatined in a images Import Section (E32ImportSection). -*/ -class E32ImportBlock - { -public: - inline const E32ImportBlock* NextBlock(TUint aImpFmt) const; - inline TInt Size(TUint aImpFmt) const; - inline const TUint* Imports() const; // import list if present -public: - TUint32 iOffsetOfDllName; ///< Offset from start of import section for a NUL terminated executable (DLL or EXE) name. - TInt iNumberOfImports; ///< Number of imports from this executable. -// TUint iImport[iNumberOfImports]; ///< For ELF-derived executes: list of code section offsets. For PE, list of imported ordinals. Omitted in PE2 import format - }; - -/** -Return size of this import block. -@param aImpFmt Import format as obtained from image header. -*/ -inline TInt E32ImportBlock::Size(TUint aImpFmt) const - { - TInt r = sizeof(E32ImportBlock); - if(aImpFmt!=KImageImpFmt_PE2) - r += iNumberOfImports * sizeof(TUint); - return r; - } - -/** -Return pointer to import block which immediately follows this one. -@param aImpFmt Import format as obtained from image header. -*/ -inline const E32ImportBlock* E32ImportBlock::NextBlock(TUint aImpFmt) const - { - const E32ImportBlock* next = this + 1; - if(aImpFmt!=KImageImpFmt_PE2) - next = (const E32ImportBlock*)( (TUint8*)next + iNumberOfImports * sizeof(TUint) ); - return next; - } - -/** -Return address of first import in this block. -For import format KImageImpFmt_ELF, imports are list of code section offsets. -For import format KImageImpFmt_PE, imports are a list of imported ordinals. -For import format KImageImpFmt_PE2, the import list is not present and should not be accessed. -*/ -inline const TUint* E32ImportBlock::Imports() const - { - return (const TUint*)(this + 1); - } - - -/** -Header for the Import Section in an image, as referenced by E32ImageHeader::iImportOffset. -Immediately following this structure are an array of E32ImportBlock structures. -The number of these is given by E32ImageHeader::iDllRefTableCount. -*/ -class E32ImportSection - { -public: - TInt iSize; ///< Size of this section excluding 'this' structure -// E32ImportBlock iImportBlock[iDllRefTableCount]; - }; - - -/** -A block of relocations for a single page (4kB) of code/data. - -Immediately following this structure are an array of TUint16 values -each representing a single value in the page which is to be relocated. -The lower 12 bits of each entry is the offset, in bytes, from start of this page. -The Upper 4 bits are the relocation type to be applied to the 32-bit value located -at that offset. - - 1 means relocate relative to code section. - - 2 means relocate relative to data section. - - 3 means relocate relative to code or data section; calculate which. - -A value of all zeros (0x0000) is ignored. (Used for padding structure to 4 byte alignment). -*/ -class E32RelocBlock - { -public: - TUint32 iPageOffset; ///< Offset, in bytes, for the page being relocated; relative to the section start. Always a multiple of the page size: 4096 bytes. - TUint32 iBlockSize; ///< Size, in bytes, for this block structure. Always a multiple of 4. -// TUint16 iEntry[] - }; - - -/** -Header for a Relocation Section in an image, as referenced by E32ImageHeader::iCodeRelocOffset -or E32ImageHeader::iDataRelocOffset. - -Immediately following this structure are an array of E32RelocBlock structures. -*/ -class E32RelocSection - { -public: - TInt iSize; ///< Size of this relocation section including 'this' structure. Always a multiple of 4. - TInt iNumberOfRelocs; ///< Number of relocations in this section. -// E32RelocBlock iRelockBlock[]; - }; - - -/** -Structure contained in the export directory in text section of the stdexe/stddll. -It contains information on the names of symbols exported by this stdexe/stddll and -pointers to a E32EpocExpSymInfoHdr structure of any stddlls that are dependencies of -this stdexe/stddll. - -This is not used for emulator images see E32EmulExpSymInfoHdr below. -@see E32EmulExpSymInfoHdr -*/ -class E32EpocExpSymInfoHdr - { -public: - TInt iSize; // size of this Table - TInt16 iFlags; - TInt16 iSymCount; // number of symbols - TInt iSymbolTblOffset; // start of the symbol table - offset from byte 0 of this header - TInt iStringTableSz; // size of the string table - TInt iStringTableOffset; // start of the string table having names of the symbols - offset from byte 0 of this header - TInt iDllCount; // Number of dependent DLLs - TInt iDepDllZeroOrdTableOffset; // offset of the DLL dependency table - offset from byte 0 of this header. - }; - - -/** -Header of the structure contained in the 'KWin32SectionName_NmdExpData' -segment of emulator stdexe & stddll images. -The segment contains addresses of symbols and NULL -terminated ASCII strings of the names of static dependencies. -For a stdexe, this segment contains the following: - a) symbol count (iSymCount) and static dependency count (iDllCount) - b) iSymCount * symbol addresses - c) iSymCount * symbol names - d) iDllCount * dependency names - -For a stddll, this segment contains the following: - a) symbol count (iSymCout) is always 0 - b) static dependency count (iDllCount) - c) iDllCount * dependency names -The symbol addresses and names are not required for a stddll as the Windows API, -GetProcAddress may be used to get the addresses for symbol names. -Since this API works only on DLL handles, we explicitly list them for stdexes. -This is used for emulator images only. -*/ -class E32EmulExpSymInfoHdr - { -public: - TInt32 iSymCount; // Number of symbols - TInt32 iDllCount; // Number of static dependency DLLs - }; - - - -#ifdef INCLUDE_E32IMAGEHEADER_IMPLEMENTATION - -// include code which implements validation functions... - -#ifndef RETURN_FAILURE -#define RETURN_FAILURE(_r) return (_r) -#endif - -#ifndef E32IMAGEHEADER_TRACE -#define E32IMAGEHEADER_TRACE(_t) ((void)0) -#endif - - -#include - - -/** -Validate this image header. - -After successful validation the following are true: - - File size is big enough to contain the entire header. - - Values #iUidChecksum, #iSignature and #iHeaderCrc are correct. - - CPU type (#iCpuIdentifier), ABI type (#iFlags&#KImageABIMask) and - entrypoint type (#iFlags&#KImageEptMask) are valid for this system. - - Code part of file as specified by #iCodeOffset and #iCodeSize is fully within the file. - - Text section size (#iTextSize) is within code part. - - Entrypoint value (#iEntryPoint) lies within the code part and is aligned correctly. - - Export directory as specified by #iExportDirCount and #iExportDirOffset is fully - within code part and is aligned correctly. - - Exception description (E32ImageHeaderV::iExceptionDescriptor), if present, - lies within the code part. - - Data part of file as specified by #iDataOffset and #iDataSize is fully within the file. - Or data is not present (#iDataOffset==#iDataSize==0). - - Import section (class E32ImportSection at #iImportOffset) is within 'rest of data' - and aligned correctly. Data following the E32ImportSection header is NOT validated or - checked if it is fully contained within the file. - - Code relocations (class E32RelocSection at #iCodeRelocOffset) is within 'rest of data' - and aligned correctly. Data following the E32RelocSection header is NOT validated or - checked if it is fully contained within the file. - - Data relocations (class E32RelocSection at #iDataRelocOffset) is within 'rest of data' - and aligned correctly. Data following the E32RelocSection header is NOT validated or - checked if it is fully contained within the file. - - Export description is validated by E32ImageHeaderV::ValidateExportDescription(). - - #iUid1 is consistant with #iFlags&#KImageDll. I.e. if flaged as a DLL, #iUid1 is - KDynamicLibraryUidValue, otherwise it is KExecutableImageUidValue. - - Version number (#iModuleVersion) is valid. (Major and minor versions are <32768). - - File compression type (#iCompressionType) is supported. - - #iHeapSizeMax>=#iHeapSizeMin - - All signed values in header are not negative. - -@param aFileSize Total size of the file from which this header was created. -@param[out] aUncompressedSize Returns the total size that the file data would be once decompressed. - -@return KErrNone if no errors detected; - KErrCorrupt if errors found; - KErrNotSupported if image format not supported on this platform. -*/ -TInt E32ImageHeader::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const - { - // check file is big enough for any header... - if(TUint(aFileSize)ValidateHeader(aFileSize,aUncompressedSize); - - return KErrNotSupported; // header format unrecognised - } - -/** -Validate this image header. - -@param aFileSize Total size of the file from which this header was created. -@param[out] aUncompressedSize Returns the total size that the file data would be once decompressed. - -@return KErrNone if no errors detected; - KErrCorrupt if errors found; - KErrNotSupported if image format not supported on this platform. -*/ -TInt E32ImageHeaderV::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const - { - const TUint KMaxDesSize = 0x0fffffffu; // maximum size of descriptor - if(aFileSize==-1) - { - // file size unknown, set to maximum valid so rest of validation works... - aFileSize = KMaxDesSize; - } - if(TUint(aFileSize)>KMaxDesSize) - RETURN_FAILURE(KErrCorrupt); // file size negative or too big - - aUncompressedSize = 0; - - // check file is big enough to contain this header... - if(aFileSize<(TInt)sizeof(*this)) - RETURN_FAILURE(KErrCorrupt); - - // check header format version... - if((iFlags&KImageHdrFmtMask)!=KImageHdrFmt_V) - RETURN_FAILURE(KErrNotSupported); - - // check header size... - TUint headerSize = iCodeOffset; - if(headerSize>TUint(aFileSize)) - RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because Loader will fail earlier when reading header from file - - // check iCpuIdentifier... - TCpu cpu = (TCpu)iCpuIdentifier; - TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6); -#if defined(__CPU_ARM) - if(!isARM) - RETURN_FAILURE(KErrNotSupported); -#elif defined(__CPU_X86) - if(cpu!=ECpuX86) - RETURN_FAILURE(KErrNotSupported); -#endif - TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets - - // check iUid1,iUid2,iUid3,iUidChecksum... - TUidType uids = *(const TUidType*)&iUid1; - TCheckedUid chkuid(uids); - const TUint32* pChkUid = (const TUint32*)&chkuid; // need hackery to verify the UID checksum since everything is private - if(pChkUid[3]!=iUidChecksum) - RETURN_FAILURE(KErrCorrupt); - - // check iSignature... - if(iSignature!=0x434f5045) // 'EPOC' - RETURN_FAILURE(KErrCorrupt); - - // check iHeaderCrc... - TUint32 supplied_crc = iHeaderCrc; - ((E32ImageHeaderV*)this)->iHeaderCrc = KImageCrcInitialiser; - TUint32 crc = 0; - Mem::Crc32(crc, this, headerSize); - ((E32ImageHeaderV*)this)->iHeaderCrc = supplied_crc; - if(crc!=supplied_crc) - RETURN_FAILURE(KErrCorrupt); - - // check iModuleVersion... - TUint32 mv = iModuleVersion; - if(mv>=0x80000000u || (mv&0x0000ffffu)>0x8000u) - RETURN_FAILURE(KErrNotSupported); - - // check iCompressionType and get uncompressed size... - TUint compression = iCompressionType; - TUint uncompressedSize = aFileSize; - if(compression!=KFormatNotCompressed) - { - if(compression!=KUidCompressionDeflate && compression!=KUidCompressionBytePair) - RETURN_FAILURE(KErrNotSupported); // unknown compression method - uncompressedSize = headerSize+iUncompressedSize; - if(uncompressedSizeKMaxDesSize) - RETURN_FAILURE(KErrCorrupt); - - // check KImageDll in iFlags... - if(iFlags&KImageDll) - { - if(iUid1!=TUint32(KDynamicLibraryUidValue)) - RETURN_FAILURE(KErrNotSupported); - } - else if(iUid1!=TUint32(KExecutableImageUidValue)) - RETURN_FAILURE(KErrNotSupported); - - // check iFlags for ABI and entry point types... - if(isARM) - { - if((iFlags&KImageEptMask)!=KImageEpt_Eka2) - RETURN_FAILURE(KErrNotSupported); - #if defined(__EABI__) - if((iFlags&KImageABIMask)!=KImageABI_EABI) - RETURN_FAILURE(KErrNotSupported); - #elif defined(__GCC32__) - if((iFlags&KImageABIMask)!=KImageABI_GCC98r2) - RETURN_FAILURE(KErrNotSupported); - #endif - } - else - { - if(iFlags&KImageEptMask) - RETURN_FAILURE(KErrNotSupported); // no special entry point type allowed on non-ARM targets - if(iFlags&KImageABIMask) - RETURN_FAILURE(KErrNotSupported); - } - - // check iFlags for import format... - if((iFlags&KImageImpFmtMask)>KImageImpFmt_PE2) - RETURN_FAILURE(KErrNotSupported); - - // check iHeapSizeMin... - if(iHeapSizeMin<0) - RETURN_FAILURE(KErrCorrupt); - - // check iHeapSizeMax... - if(iHeapSizeMax=TUint(iCodeSize)) - RETURN_FAILURE(KErrCorrupt); - if(iEntryPoint+KCodeSegIdOffset+sizeof(TUint32)>TUint(iCodeSize)) - RETURN_FAILURE(KErrCorrupt); - if(iEntryPoint&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned - - // check iCodeBase... - if(iCodeBase&3) - RETURN_FAILURE(KErrCorrupt); // not aligned - - // check iDataBase... - if(iDataBase&3) - RETURN_FAILURE(KErrCorrupt); // not aligned - - // check iDllRefTableCount... - if(iDllRefTableCount<0) - RETURN_FAILURE(KErrCorrupt); - if(iDllRefTableCount) - { - if(!iImportOffset) - RETURN_FAILURE(KErrCorrupt); // we link to DLLs but have no import data - } - - // check iCodeOffset and iCodeSize specify region in file... - TUint codeStart = iCodeOffset; - TUint codeEnd = codeStart+iCodeSize; - if(codeEnduncompressedSize) - RETURN_FAILURE(KErrCorrupt); - - // check iDataOffset and iDataSize specify region in file... - TUint dataStart = iDataOffset; - TUint dataEnd = dataStart+iDataSize; - if(dataEnduncompressedSize) - RETURN_FAILURE(KErrCorrupt); - if((dataStart-codeStart)&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // data not aligned with respect to code - } - - - // check total data size isn't too bit... - TUint totalDataSize = iDataSize+iBssSize; - if(totalDataSize>0x7fff0000) - RETURN_FAILURE(KErrNoMemory); - - // check iExportDirOffset and iExportDirCount specify region in code part... - if(TUint(iExportDirCount)>65535) - RETURN_FAILURE(KErrCorrupt); // too many exports - if(iExportDirCount) - { - TUint exportsStart = iExportDirOffset; - TUint exportsEnd = exportsStart+iExportDirCount*sizeof(TUint32); - if(iFlags&KImageNmdExpData) - exportsStart -= sizeof(TUint32); // allow for 0th ordinal - if(exportsEndcodeEnd) - RETURN_FAILURE(KErrCorrupt); - if((exportsStart-codeStart)&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned within code section - } - - // check iTextSize... - if(TUint(iTextSize)>TUint(iCodeSize)) - RETURN_FAILURE(KErrCorrupt); - - // check iImportOffset... - TUint start = iImportOffset; - if(start) - { - TUint end = start+sizeof(E32ImportSection); // minimum valid size - if(enduncompressedSize) - RETURN_FAILURE(KErrCorrupt); - if((start-codeEnd)&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data' - } - - // check iCodeRelocOffset... - start = iCodeRelocOffset; - if(start) - { - TUint end = start+sizeof(E32RelocSection); // minimum valid size - if(enduncompressedSize) - RETURN_FAILURE(KErrCorrupt); - if((start-codeEnd)&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data' - } - - // check iDataRelocOffset... - start = iDataRelocOffset; - if(start) - { - TUint end = start+sizeof(E32RelocSection); // minimum valid size - if(enduncompressedSize) - RETURN_FAILURE(KErrCorrupt); - if((start-codeEnd)&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data' - } - - // check exception descriptor... - if(iExceptionDescriptor&1) // if valid... - if(iExceptionDescriptor>=TUint(iCodeSize)) - RETURN_FAILURE(KErrCorrupt); - - TInt r = ValidateExportDescription(); - if(r!=KErrNone) - RETURN_FAILURE(r); - - // done... - aUncompressedSize = uncompressedSize; - return KErrNone; - } - - -/** -Valdate that the export description is valid. -*/ -TInt E32ImageHeaderV::ValidateExportDescription() const - { - TUint headerSize = iCodeOffset; - - // check export description... - TUint edSize = iExportDescSize + sizeof(iExportDescSize) + sizeof(iExportDescType); - edSize = (edSize+3)&~3; - TUint edEnd = _FOFF(E32ImageHeaderV,iExportDescSize)+edSize; - if(edEnd!=headerSize) - RETURN_FAILURE(KErrCorrupt); - - // size of bitmap of exports... - TUint bitmapSize = (iExportDirCount+7) >> 3; - - // check export description bitmap... - switch(iExportDescType) - { - case KImageHdr_ExpD_NoHoles: - // no bitmap to check... - E32IMAGEHEADER_TRACE(("ValidateExportDescription NoHoles")); - return KErrNone; - - case KImageHdr_ExpD_FullBitmap: - // full bitmap present... - E32IMAGEHEADER_TRACE(("ValidateExportDescription FullBitmap")); - if(bitmapSize!=iExportDescSize) - RETURN_FAILURE(KErrCorrupt); - return KErrNone; - - case KImageHdr_ExpD_SparseBitmap8: - { - // sparse bitmap present... - E32IMAGEHEADER_TRACE(("ValidateExportDescription SparseBitmap8")); - - // get size of meta-bitmap... - TUint metaBitmapSize = (bitmapSize+7) >> 3; - if(metaBitmapSize>iExportDescSize) - RETURN_FAILURE(KErrCorrupt); // doesn't fit - - TUint totalSize = metaBitmapSize; - - // scan meta-bitmap counting extra bytes which should be present... - const TUint8* metaBitmap = iExportDesc; - const TUint8* metaBitmapEnd = metaBitmap + metaBitmapSize; - while(metaBitmap>=1); - } - - if(totalSize!=iExportDescSize) - RETURN_FAILURE(KErrCorrupt); - } - return KErrNone; - - default: - E32IMAGEHEADER_TRACE(("ValidateExportDescription ?")); - RETURN_FAILURE(KErrNotSupported); - } - } - - -/** -Validate a relocation section. - -@param aBufferStart Start of buffer containing the data after the code part in the image file. -@param aBufferSize Size of data at aBufferStart. -@param aRelocationInfoOffset File offset for relocation section. (#iCodeRelocOffset or #iDataRelocOffset.) -@param aRelocatedSectionSize Size of section being relocated. (#iCodeSize or #iDataSize.) -@param[out] aRelocationSection Set to the start of the relocation section in the given buffer. - -@return KErrNone if relocation section is valid, else KErrCorrupt. -*/ -TInt E32ImageHeaderV::ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const - { - aRelocationSection = 0; - if(!aRelocationInfoOffset) - return KErrNone; // no relocations - - // get alignment requirements... - TCpu cpu = (TCpu)iCpuIdentifier; - TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6); - TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets - - // buffer pointer to read relocation from... - TUint8* bufferStart = (TUint8*)aBufferStart; - TUint8* bufferEnd = bufferStart+aBufferSize; - TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart - TUint8* sectionStart = (bufferStart+aRelocationInfoOffset-baseOffset); - TUint8* p = sectionStart; - - // read section header (ValidateHeader has alread checked this is OK)... - E32RelocSection* sectionHeader = (E32RelocSection*)p; - TUint size = sectionHeader->iSize; - TUint relocsRemaining = sectionHeader->iNumberOfRelocs; - E32IMAGEHEADER_TRACE(("E32RelocSection 0x%x %d",size,relocsRemaining)); - if(size&3) - RETURN_FAILURE(KErrCorrupt); // not multiple of word size - - // calculate buffer range for block data... - p = (TUint8*)(sectionHeader+1); // start of first block - TUint8* sectionEnd = p+size; - if(sectionEndbufferEnd) - RETURN_FAILURE(KErrCorrupt); // overflows buffer - - // process each block... - while(p!=sectionEnd) - { - E32RelocBlock* block = (E32RelocBlock*)p; - - // get address of first entry in this block... - TUint16* entryPtr = (TUint16*)(block+1); - if((TUint8*)entryPtr<(TUint8*)block || (TUint8*)entryPtr>sectionEnd) - RETURN_FAILURE(KErrCorrupt); // overflows relocation section - - // read block header... - TUint pageOffset = block->iPageOffset; - TUint blockSize = block->iBlockSize; - E32IMAGEHEADER_TRACE(("E32RelocSection block 0x%x 0x%x",pageOffset,blockSize)); - if(pageOffset&0xfff) - RETURN_FAILURE(KErrCorrupt); // not page aligned - if(blockSize(TUint16*)sectionEnd) - RETURN_FAILURE(KErrCorrupt); // overflows relocation section - - // process each entry in this block... - while(entryPtr=aRelocatedSectionSize || offset+4>aRelocatedSectionSize) - RETURN_FAILURE(KErrCorrupt); // not within section - if(offset&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not aligned correctly - - // count each relocation processed... - --relocsRemaining; - } - - // next sub block... - p = (TUint8*)entryEnd; - } - - // check number of relocations in section header is correct... - E32IMAGEHEADER_TRACE(("E32RelocSection relocsRemaining=%d",relocsRemaining)); - if(relocsRemaining) - RETURN_FAILURE(KErrCorrupt); // incorrect number of entries - - aRelocationSection = sectionHeader; - return KErrNone; - } - - -/** -Validate an import section. - -For PE format imports, this also verifies that the Import Address Table fits within the code -part of the image. - -@param aBufferStart Start of buffer containing the data after the code part in the image file. -@param aBufferSize Size of data at aBufferStart. -@param[out] aBiggestImportCount Largest number of imports the image has from any single dependency. - -@return KErrNone if section is valid (or absent), else KErrCorrupt. -*/ -TInt E32ImageHeaderV::ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const - { - if(!iImportOffset) - { - aBiggestImportCount = 0; - return KErrNone; // no imports - } - - // get alignment requirements... - TCpu cpu = (TCpu)iCpuIdentifier; - TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6); - TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets - - // buffer pointer to read imports from... - TUint8* bufferStart = (TUint8*)aBufferStart; - TUint8* bufferEnd = bufferStart+aBufferSize; - TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart - TUint8* sectionStart = (bufferStart+iImportOffset-baseOffset); - TUint8* p = sectionStart; - - // read section header (ValidateHeader has alread checked this is OK)... - E32ImportSection* sectionHeader = (E32ImportSection*)p; - TUint size = sectionHeader->iSize; - E32IMAGEHEADER_TRACE(("E32ImportSection 0x%x",size)); - - // check section lies within buffer... - p = (TUint8*)(sectionHeader+1); // start of first import block - TUint8* sectionEnd = sectionStart+size; - if(sectionEndbufferEnd) - RETURN_FAILURE(KErrCorrupt); // overflows buffer - - // process each import block... - TUint numDeps = iDllRefTableCount; - TUint biggestImportCount = 0; - TUint totalImports = 0; - TUint importFormat = iFlags&KImageImpFmtMask; - while(numDeps--) - { - // get block header... - E32ImportBlock* block = (E32ImportBlock*)p; - p = (TUint8*)(block+1); - if(p<(TUint8*)block || p>sectionEnd) - RETURN_FAILURE(KErrCorrupt); // overflows buffer - - E32IMAGEHEADER_TRACE(("E32ImportBlock 0x%x %d",block->iOffsetOfDllName,block->iNumberOfImports)); - - // check import dll name is within section... - TUint8* name = sectionStart+block->iOffsetOfDllName; - if(name=sectionEnd) - RETURN_FAILURE(KErrCorrupt); // not within import section - while(*name++ && nameiOffsetOfDllName)); - - // process import count... - TUint numberOfImports = block->iNumberOfImports; - if(numberOfImports>=0x80000000u/sizeof(TUint32)) - RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer - if(numberOfImports>biggestImportCount) - biggestImportCount = numberOfImports; - totalImports += numberOfImports; - - // process import data... - - // PE2 doesn't have any more data... - if(importFormat==KImageImpFmt_PE2) - continue; - - // get import data range... - TUint32* imports = (TUint32*)p; - TUint32* importsEnd = imports+numberOfImports; - if(importsEnd0x80000000 - if(importsEnd>(TUint32*)sectionEnd) - RETURN_FAILURE(KErrCorrupt); // overflows buffer - - // move pointer on to next block... - p = (TUint8*)importsEnd; - - if(importFormat==KImageImpFmt_ELF) - { - // check imports are in code section... - TUint32 limit = iCodeSize-sizeof(TUint32); - while(importslimit) - RETURN_FAILURE(KErrCorrupt); - if(i&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // not word aligned - } - } - else if(importFormat==KImageImpFmt_PE) - { - // import data is not used, so don't bother checking it - } - else - { - RETURN_FAILURE(KErrCorrupt); // bad import format, Fuzzer can't trigger this because import format checked by header validation - } - - // next block... - p = (TUint8*)block->NextBlock(importFormat); - } - - // done processing imports; for PE derived files now check import address table (IAT)... - if(importFormat==KImageImpFmt_PE || importFormat==KImageImpFmt_PE2) - { - if(totalImports>=0x80000000u/sizeof(TUint32)) - RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer - TUint importAddressTable = iTextSize; // offset for IAT - if(importAddressTable&pointerAlignMask) - RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because PE imports are for X86 which doesn't have alignment restrictions - TUint importAddressTableEnd = importAddressTable+sizeof(TUint32)*totalImports; - if(importAddressTableEndTUint(iCodeSize)) - RETURN_FAILURE(KErrCorrupt); // import address table overflows code part of file - E32IMAGEHEADER_TRACE(("E32ImportSection IAT offsets 0x%x..0x%x",importAddressTable,importAddressTableEnd)); - } - - aBiggestImportCount = biggestImportCount; - return KErrNone; - } - - - - -/** -Validate a whole executable image. - -This runs all of the other validation methods in turn. - -@param aBufferStart Start of buffer containing the data after the header part of an image file. -@param aBufferSize Size of data at aBufferStart. - -@return KErrNone if image is valid, else KErrCorrupt or KErrNotSupported. -*/ -TInt E32ImageHeaderV::ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const - { - TUint32 dummyUncompressedSize; - TInt r = ValidateHeader(TotalSize()+aBufferSize,dummyUncompressedSize); - if(r!=KErrNone) - return r; - - TInt endOfCodeOffset = iCodeSize; - void* restOfFileData = ((TUint8*)aBufferStart)+endOfCodeOffset; - TInt restOfFileSize = aBufferSize-endOfCodeOffset; - - E32RelocSection* dummy; - r = ValidateRelocations(restOfFileData,restOfFileSize,iCodeRelocOffset,iCodeSize,dummy); - if(r!=KErrNone) - return r; - r = ValidateRelocations(restOfFileData,restOfFileSize,iDataRelocOffset,iDataSize,dummy); - if(r!=KErrNone) - return r; - - TUint biggestImportCount; - r = ValidateImports(restOfFileData,restOfFileSize,biggestImportCount); - if(r!=KErrNone) - return r; - - return r; - } - - -#endif // INCLUDE_E32IMAGEHEADER_IMPLEMENTATION - - -#endif // __F32IMAGE_H__