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