1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/epoc32/include/f32image.h Tue Mar 16 16:12:26 2010 +0000
1.3 @@ -0,0 +1,1239 @@
1.4 +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// 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
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\inc\f32image.h
1.18 +//
1.19 +//
1.20 +
1.21 +
1.22 +
1.23 +/**
1.24 + @file f32\inc\f32image.h
1.25 + @internalTechnology
1.26 +*/
1.27 +
1.28 +#ifndef __F32IMAGE_H__
1.29 +#define __F32IMAGE_H__
1.30 +#include <e32cmn.h>
1.31 +
1.32 +/**
1.33 +Value used for E32ImageHeader::iCpuIdentifier.
1.34 +*/
1.35 +enum TCpu
1.36 + {
1.37 + ECpuUnknown=0, ECpuX86=0x1000, ECpuArmV4=0x2000, ECpuArmV5=0x2001, ECpuArmV6=0x2002, ECpuMCore=0x4000
1.38 + };
1.39 +
1.40 +/**
1.41 +Ordinal value of the first entry in an executables export directory.
1.42 +@see E32ImageHeader::iExportDirOffset.
1.43 +*/
1.44 +const TInt KOrdinalBase=1;
1.45 +
1.46 +/**
1.47 +Value used to initialise E32ImageHeader::iHeaderCrc prior to CRC generation.
1.48 +*/
1.49 +const TUint32 KImageCrcInitialiser = 0xc90fdaa2u;
1.50 +
1.51 +
1.52 +/**
1.53 +Byte offset from an executable's entrypoint to the code segment ID storage location.
1.54 +*/
1.55 +const TUint KCodeSegIdOffset = 12;
1.56 +
1.57 +//
1.58 +// Flags fields for E32ImageHeader::iFlags
1.59 +//
1.60 +
1.61 +const TUint KImageDll = 0x00000001u; ///< Flag set if executable is a DLL, clear if an EXE.
1.62 +
1.63 +const TUint KImageNoCallEntryPoint = 0x00000002u; ///< Obsolete flag ignored since Symbian OS version 8.1b.
1.64 +
1.65 +const TUint KImageFixedAddressExe = 0x00000004u; ///< Executable's data should not move when running on the moving memory model.
1.66 +
1.67 +const TUint KImageABIMask = 0x00000018u; ///< Bitmask for ABI value.
1.68 +const TInt KImageABIShift = 3; ///< Bit shift count for ABI value.
1.69 +const TUint KImageABI_GCC98r2 = 0x00000000u; ///< Obsolete ABI for ARM targets.
1.70 +const TUint KImageABI_EABI = 0x00000008u; ///< ARM EABI
1.71 +
1.72 +const TUint KImageEptMask = 0x000000e0u; ///< Bitmask for Entrypoint value.
1.73 +const TInt KImageEptShift = 5; ///< Bit shift count for Entrypoint value
1.74 +const TUint KImageEpt_Eka1 = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
1.75 +const TUint KImageEpt_Eka2 = 0x00000020u; ///< Standard entrypoint for ARM executable.
1.76 +
1.77 +const TUint KImageUnpaged = 0x00000100u; ///< Executable image should not be demand paged. Exclusive with KImagePaged,
1.78 +const TUint KImagePaged = 0x00000200u; ///< Executable image should be demand paged. Exclusive with KImageUnpaged,
1.79 +
1.80 +const TUint KImageNmdExpData = 0x00000400u; ///< Flag to indicate when named symbol export data present in image
1.81 +
1.82 +const TUint KImageDebuggable = 0x00000800u; ///< Flag to indicate image is debuggable
1.83 +
1.84 +const TUint KImageHWFloatMask = 0x00f00000u; ///< Bitmask for Floating Point type.
1.85 +const TInt KImageHWFloatShift = 20; ///< Bit shift count for Floating Point type.
1.86 +const TUint KImageHWFloat_None = EFpTypeNone << KImageHWFloatShift; ///< No hardware floating point used.
1.87 +const TUint KImageHWFloat_VFPv2 = EFpTypeVFPv2 << KImageHWFloatShift; ///< ARM VFPv2 floating point used.
1.88 +
1.89 +const TUint KImageHdrFmtMask = 0x0f000000u; ///< Bitmask for header format type.
1.90 +const TInt KImageHdrFmtShift = 24; ///< Bit shift count for header format type.
1.91 +const TUint KImageHdrFmt_Original = 0x00000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
1.92 +const TUint KImageHdrFmt_J = 0x01000000u; ///< @removed Obsolete format not used since Symbian OS version 8.1b.
1.93 +const TUint KImageHdrFmt_V = 0x02000000u; ///< Header has format given by class E32ImageHeaderV.
1.94 +
1.95 +const TUint KImageImpFmtMask = 0xf0000000u; ///< Bitmask for import section format type.
1.96 +const TInt KImageImpFmtShift = 28; ///< Bit shift count for import section format type.
1.97 +const TUint KImageImpFmt_PE = 0x00000000u; ///< PE-derived imports.
1.98 +const TUint KImageImpFmt_ELF = 0x10000000u; ///< ELF-derived imports.
1.99 +const TUint KImageImpFmt_PE2 = 0x20000000u; ///< PE-derived imports without redundant copy of import ordinals.
1.100 +
1.101 +
1.102 +
1.103 +
1.104 +// forward references...
1.105 +class RFile;
1.106 +class E32RelocSection;
1.107 +
1.108 +
1.109 +/**
1.110 +Structure for an executable image's header.
1.111 +This is extended by E32ImageHeaderComp and E32ImageHeaderV.
1.112 +All executables since Symbian OS version 8.1b have an header given by class E32ImageHeaderV.
1.113 +
1.114 +Summary of an executable image structure...
1.115 +
1.116 +- Header, 0..iCodeOffset-1
1.117 +- Code part, iCodeOffset..iCodeOffset+iCodeSize-1
1.118 + - .text section, 0 + iTextSize
1.119 + - Import Address Table (IAT), iText + ?
1.120 + - Export Directory, iExportDirOffset + iExportDirCount*4 (in .text Section)
1.121 +- Rest of data, iCodeOffset+iCodeSize..EOF
1.122 + - .data section, iDataOffset + iDataSize
1.123 + - Import section, iImportOffset + sizeof(E32ImportSection)+?
1.124 + - Code relocation section, iCodeRelocOffset + sizeof(E32RelocSection)+?
1.125 + - Data relocation section, iDataRelocOffset + sizeof(E32RelocSection)+?
1.126 +*/
1.127 +class E32ImageHeader
1.128 + {
1.129 +public:
1.130 + static TInt New(E32ImageHeader*& aHdr, RFile& aFile);
1.131 + static TInt New(E32ImageHeader*& aHdr, TUint8* aFileData, TUint32 aFileSize);
1.132 + TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const;
1.133 +
1.134 + inline static TUint ABIFromFlags(TUint aFlags);
1.135 + inline static TUint EptFromFlags(TUint aFlags);
1.136 + inline static TUint HdrFmtFromFlags(TUint aFlags);
1.137 + inline static TUint ImpFmtFromFlags(TUint aFlags);
1.138 +
1.139 + inline TUint ABI() const;
1.140 + inline TUint EntryPointFormat() const;
1.141 + inline TUint HeaderFormat() const;
1.142 + inline TUint ImportFormat() const;
1.143 +
1.144 + inline TUint32 CompressionType() const;
1.145 + inline TUint32 ModuleVersion() const;
1.146 + inline TInt TotalSize() const;
1.147 + inline TInt UncompressedFileSize() const;
1.148 + inline void GetSecurityInfo(SSecurityInfo& aInfo) const;
1.149 + inline TCpu CpuIdentifier() const;
1.150 + inline TProcessPriority ProcessPriority() const;
1.151 + inline TUint32 ExceptionDescriptor() const;
1.152 +public:
1.153 + TUint32 iUid1; ///< KDynamicLibraryUidValue or KExecutableImageUidValue
1.154 + TUint32 iUid2; ///< Second UID for executable.
1.155 + TUint32 iUid3; ///< Third UID for executable.
1.156 + TUint32 iUidChecksum; ///< Checksum for iUid1, iUid2 and iUid3.
1.157 + TUint iSignature; ///< Contains 'EPOC'.
1.158 + TUint32 iHeaderCrc; ///< CRC-32 of entire header. @see #KImageCrcInitialiser.
1.159 + TUint32 iModuleVersion; ///< Version number for this executable (used in link resolution).
1.160 + TUint32 iCompressionType; ///< Type of compression used for file contents located after the header. (UID or 0 for none).
1.161 + TVersion iToolsVersion; ///< Version number of tools which generated this file.
1.162 + TUint32 iTimeLo; ///< Least significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000.
1.163 + TUint32 iTimeHi; ///< Most significant 32 bits of the time of image creation, in milliseconds since since midnight Jan 1st, 2000.
1.164 + TUint iFlags; ///< Contains various bit-fields of attributes for the image.
1.165 + TInt iCodeSize; ///< Size of executables code. Includes import address table, constant data and export directory.
1.166 + TInt iDataSize; ///< Size of executables initialised data.
1.167 + TInt iHeapSizeMin; ///< Minimum size for an EXEs runtime heap memory.
1.168 + TInt iHeapSizeMax; ///< Maximum size for an EXEs runtime heap memory.
1.169 + TInt iStackSize; ///< Size for stack required by an EXEs initial thread.
1.170 + TInt iBssSize; ///< Size of executables uninitialised data.
1.171 + TUint iEntryPoint; ///< Offset into code of the entry point.
1.172 + TUint iCodeBase; ///< Virtual address that the executables code is linked for.
1.173 + TUint iDataBase; ///< Virtual address that the executables data is linked for.
1.174 + TInt iDllRefTableCount; ///< Number of executable against which this executable is linked. The number of files mention in the import section at iImportOffset.
1.175 + TUint iExportDirOffset; ///< Byte offset into file of the export directory.
1.176 + TInt iExportDirCount; ///< Number of entries in the export directory.
1.177 + TInt iTextSize; ///< Size of just the text section, also doubles as the offset for the Import Address Table w.r.t. the code section.
1.178 + TUint iCodeOffset; ///< Offset into file of the code section. Also doubles the as header size.
1.179 + TUint iDataOffset; ///< Offset into file of the data section.
1.180 + TUint iImportOffset; ///< Offset into file of the import section (E32ImportSection).
1.181 + TUint iCodeRelocOffset; ///< Offset into file of the code relocation section (E32RelocSection).
1.182 + TUint iDataRelocOffset; ///< Offset into file of the data relocation section (E32RelocSection).
1.183 + TUint16 iProcessPriority; ///< Initial runtime process priorty for an EXE. (Value from enum TProcessPriority.)
1.184 + TUint16 iCpuIdentifier; ///< Value from enum TCpu which indicates the CPU architecture for which the image was created
1.185 + };
1.186 +
1.187 +
1.188 +/**
1.189 +Extends E32ImageHeader.
1.190 +*/
1.191 +class E32ImageHeaderComp : public E32ImageHeader
1.192 + {
1.193 +public:
1.194 + TUint32 iUncompressedSize; ///< Uncompressed size of file data after the header, or zero if file not compressed.
1.195 + };
1.196 +
1.197 +
1.198 +/**
1.199 +Extends E32ImageHeaderComp.
1.200 +All Symbian OS executable files have a header in this format since OS version 8.1b.
1.201 +*/
1.202 +class E32ImageHeaderV : public E32ImageHeaderComp
1.203 + {
1.204 +public:
1.205 + SSecurityInfo iS; ///< Platform Security information of executable.
1.206 + TUint32 iExceptionDescriptor; ///< Offset in bytes from start of code section to Exception Descriptor, bit 0 set if valid.
1.207 + TUint32 iSpare2; ///< Reserved for future use. Set to zero.
1.208 + TUint16 iExportDescSize; ///< Size of export description stored in iExportDesc.
1.209 + TUint8 iExportDescType; ///< Type of description of holes in export table
1.210 + TUint8 iExportDesc[1]; ///< Description of holes in export table, size given by iExportDescSize..
1.211 +public:
1.212 + TInt ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const;
1.213 + TInt ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const;
1.214 + TInt ValidateExportDescription() const;
1.215 + TInt ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const;
1.216 + TInt ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const;
1.217 + TInt ValidateAndAdjust(TUint32 aFileSize);
1.218 + };
1.219 +
1.220 +// export description type E32ImageHeaderV::iExportDescType
1.221 +const TUint KImageHdr_ExpD_NoHoles =0x00; ///< No holes, all exports present.
1.222 +const TUint KImageHdr_ExpD_FullBitmap =0x01; ///< Full bitmap present at E32ImageHeaderV::iExportDesc
1.223 +const TUint KImageHdr_ExpD_SparseBitmap8 =0x02; ///< Sparse bitmap present at E32ImageHeaderV::iExportDesc, granularity 8
1.224 +const TUint KImageHdr_ExpD_Xip =0xff; ///< XIP file
1.225 +
1.226 +
1.227 +//
1.228 +// inline getters for E32ImageHeader
1.229 +//
1.230 +
1.231 +/**
1.232 +Extract ABI type from aFlags.
1.233 +*/
1.234 +inline TUint E32ImageHeader::ABIFromFlags(TUint aFlags)
1.235 + {
1.236 + return aFlags & KImageABIMask;
1.237 + }
1.238 +
1.239 +/**
1.240 +Extract ABI type from #iFlags.
1.241 +*/
1.242 +inline TUint E32ImageHeader::ABI() const
1.243 + {
1.244 + return ABIFromFlags(iFlags);
1.245 + }
1.246 +
1.247 +/**
1.248 +Extract entrypoint format from aFlags.
1.249 +*/
1.250 +inline TUint E32ImageHeader::EptFromFlags(TUint aFlags)
1.251 + {
1.252 + return aFlags & KImageEptMask;
1.253 + }
1.254 +
1.255 +/**
1.256 +Extract entrypoint format from #iFlags.
1.257 +*/
1.258 +inline TUint E32ImageHeader::EntryPointFormat() const
1.259 + {
1.260 + return EptFromFlags(iFlags);
1.261 + }
1.262 +
1.263 +/**
1.264 +Extract header format from aFlags.
1.265 +*/
1.266 +inline TUint E32ImageHeader::HdrFmtFromFlags(TUint aFlags)
1.267 + {
1.268 + return aFlags & KImageHdrFmtMask;
1.269 + }
1.270 +
1.271 +/**
1.272 +Extract header format from #iFlags.
1.273 +*/
1.274 +inline TUint E32ImageHeader::HeaderFormat() const
1.275 + {
1.276 + return HdrFmtFromFlags(iFlags);
1.277 + }
1.278 +
1.279 +/**
1.280 +Extract import format from aFlags.
1.281 +*/
1.282 +inline TUint E32ImageHeader::ImpFmtFromFlags(TUint aFlags)
1.283 + {
1.284 + return aFlags & KImageImpFmtMask;
1.285 + }
1.286 +
1.287 +/**
1.288 +Extract import format from #iFlags.
1.289 +*/
1.290 +inline TUint E32ImageHeader::ImportFormat() const
1.291 + {
1.292 + return ImpFmtFromFlags(iFlags);
1.293 + }
1.294 +
1.295 +/**
1.296 +Return #iCompressionType.
1.297 +*/
1.298 +inline TUint32 E32ImageHeader::CompressionType() const
1.299 + {
1.300 + return iCompressionType;
1.301 + }
1.302 +
1.303 +/**
1.304 +Return #iModuleVersion.
1.305 +*/
1.306 +inline TUint32 E32ImageHeader::ModuleVersion() const
1.307 + {
1.308 + return iModuleVersion;
1.309 + }
1.310 +
1.311 +/**
1.312 +Return size of this header.
1.313 +*/
1.314 +inline TInt E32ImageHeader::TotalSize() const
1.315 + {
1.316 + return iCodeOffset;
1.317 + }
1.318 +
1.319 +/**
1.320 +Return total size of file after decompression, or -1 if file not compressed.
1.321 +*/
1.322 +inline TInt E32ImageHeader::UncompressedFileSize() const
1.323 + {
1.324 + if(iCompressionType==0)
1.325 + return -1; // not compressed
1.326 + else
1.327 + return ((E32ImageHeaderComp*)this)->iUncompressedSize + TotalSize();
1.328 + }
1.329 +
1.330 +/**
1.331 +Return copy of security info, #E32ImageHeaderV::iS.
1.332 +*/
1.333 +inline void E32ImageHeader::GetSecurityInfo(SSecurityInfo& aInfo) const
1.334 + {
1.335 + aInfo = ((E32ImageHeaderV*)this)->iS;
1.336 + }
1.337 +
1.338 +/**
1.339 +Return #iCpuIdentifier.
1.340 +*/
1.341 +inline TCpu E32ImageHeader::CpuIdentifier() const
1.342 + {
1.343 + return (TCpu)iCpuIdentifier;
1.344 + }
1.345 +
1.346 +/**
1.347 +Return #iProcessPriority.
1.348 +*/
1.349 +inline TProcessPriority E32ImageHeader::ProcessPriority() const
1.350 + {
1.351 + return (TProcessPriority)iProcessPriority;
1.352 + }
1.353 +
1.354 +/**
1.355 +Return fffset in bytes from start of code section for the Exception Descriptor.
1.356 +Or zero if not present.
1.357 +*/
1.358 +inline TUint32 E32ImageHeader::ExceptionDescriptor() const
1.359 + {
1.360 + TUint32 xd = ((E32ImageHeaderV*)this)->iExceptionDescriptor;
1.361 +
1.362 + if((xd & 1) && (xd != 0xffffffffu))
1.363 + return (xd & ~1);
1.364 +
1.365 + return 0;
1.366 + }
1.367 +
1.368 +
1.369 +/**
1.370 +A block of imports from a single executable.
1.371 +These structures are conatined in a images Import Section (E32ImportSection).
1.372 +*/
1.373 +class E32ImportBlock
1.374 + {
1.375 +public:
1.376 + inline const E32ImportBlock* NextBlock(TUint aImpFmt) const;
1.377 + inline TInt Size(TUint aImpFmt) const;
1.378 + inline const TUint* Imports() const; // import list if present
1.379 +public:
1.380 + TUint32 iOffsetOfDllName; ///< Offset from start of import section for a NUL terminated executable (DLL or EXE) name.
1.381 + TInt iNumberOfImports; ///< Number of imports from this executable.
1.382 +// TUint iImport[iNumberOfImports]; ///< For ELF-derived executes: list of code section offsets. For PE, list of imported ordinals. Omitted in PE2 import format
1.383 + };
1.384 +
1.385 +/**
1.386 +Return size of this import block.
1.387 +@param aImpFmt Import format as obtained from image header.
1.388 +*/
1.389 +inline TInt E32ImportBlock::Size(TUint aImpFmt) const
1.390 + {
1.391 + TInt r = sizeof(E32ImportBlock);
1.392 + if(aImpFmt!=KImageImpFmt_PE2)
1.393 + r += iNumberOfImports * sizeof(TUint);
1.394 + return r;
1.395 + }
1.396 +
1.397 +/**
1.398 +Return pointer to import block which immediately follows this one.
1.399 +@param aImpFmt Import format as obtained from image header.
1.400 +*/
1.401 +inline const E32ImportBlock* E32ImportBlock::NextBlock(TUint aImpFmt) const
1.402 + {
1.403 + const E32ImportBlock* next = this + 1;
1.404 + if(aImpFmt!=KImageImpFmt_PE2)
1.405 + next = (const E32ImportBlock*)( (TUint8*)next + iNumberOfImports * sizeof(TUint) );
1.406 + return next;
1.407 + }
1.408 +
1.409 +/**
1.410 +Return address of first import in this block.
1.411 +For import format KImageImpFmt_ELF, imports are list of code section offsets.
1.412 +For import format KImageImpFmt_PE, imports are a list of imported ordinals.
1.413 +For import format KImageImpFmt_PE2, the import list is not present and should not be accessed.
1.414 +*/
1.415 +inline const TUint* E32ImportBlock::Imports() const
1.416 + {
1.417 + return (const TUint*)(this + 1);
1.418 + }
1.419 +
1.420 +
1.421 +/**
1.422 +Header for the Import Section in an image, as referenced by E32ImageHeader::iImportOffset.
1.423 +Immediately following this structure are an array of E32ImportBlock structures.
1.424 +The number of these is given by E32ImageHeader::iDllRefTableCount.
1.425 +*/
1.426 +class E32ImportSection
1.427 + {
1.428 +public:
1.429 + TInt iSize; ///< Size of this section excluding 'this' structure
1.430 +// E32ImportBlock iImportBlock[iDllRefTableCount];
1.431 + };
1.432 +
1.433 +
1.434 +/**
1.435 +A block of relocations for a single page (4kB) of code/data.
1.436 +
1.437 +Immediately following this structure are an array of TUint16 values
1.438 +each representing a single value in the page which is to be relocated.
1.439 +The lower 12 bits of each entry is the offset, in bytes, from start of this page.
1.440 +The Upper 4 bits are the relocation type to be applied to the 32-bit value located
1.441 +at that offset.
1.442 + - 1 means relocate relative to code section.
1.443 + - 2 means relocate relative to data section.
1.444 + - 3 means relocate relative to code or data section; calculate which.
1.445 +
1.446 +A value of all zeros (0x0000) is ignored. (Used for padding structure to 4 byte alignment).
1.447 +*/
1.448 +class E32RelocBlock
1.449 + {
1.450 +public:
1.451 + TUint32 iPageOffset; ///< Offset, in bytes, for the page being relocated; relative to the section start. Always a multiple of the page size: 4096 bytes.
1.452 + TUint32 iBlockSize; ///< Size, in bytes, for this block structure. Always a multiple of 4.
1.453 +// TUint16 iEntry[]
1.454 + };
1.455 +
1.456 +
1.457 +/**
1.458 +Header for a Relocation Section in an image, as referenced by E32ImageHeader::iCodeRelocOffset
1.459 +or E32ImageHeader::iDataRelocOffset.
1.460 +
1.461 +Immediately following this structure are an array of E32RelocBlock structures.
1.462 +*/
1.463 +class E32RelocSection
1.464 + {
1.465 +public:
1.466 + TInt iSize; ///< Size of this relocation section including 'this' structure. Always a multiple of 4.
1.467 + TInt iNumberOfRelocs; ///< Number of relocations in this section.
1.468 +// E32RelocBlock iRelockBlock[];
1.469 + };
1.470 +
1.471 +
1.472 +/**
1.473 +Structure contained in the export directory in text section of the stdexe/stddll.
1.474 +It contains information on the names of symbols exported by this stdexe/stddll and
1.475 +pointers to a E32EpocExpSymInfoHdr structure of any stddlls that are dependencies of
1.476 +this stdexe/stddll.
1.477 +
1.478 +This is not used for emulator images see E32EmulExpSymInfoHdr below.
1.479 +@see E32EmulExpSymInfoHdr
1.480 +*/
1.481 +class E32EpocExpSymInfoHdr
1.482 + {
1.483 +public:
1.484 + TInt iSize; // size of this Table
1.485 + TInt16 iFlags;
1.486 + TInt16 iSymCount; // number of symbols
1.487 + TInt iSymbolTblOffset; // start of the symbol table - offset from byte 0 of this header
1.488 + TInt iStringTableSz; // size of the string table
1.489 + TInt iStringTableOffset; // start of the string table having names of the symbols - offset from byte 0 of this header
1.490 + TInt iDllCount; // Number of dependent DLLs
1.491 + TInt iDepDllZeroOrdTableOffset; // offset of the DLL dependency table - offset from byte 0 of this header.
1.492 + };
1.493 +
1.494 +
1.495 +/**
1.496 +Header of the structure contained in the 'KWin32SectionName_NmdExpData'
1.497 +segment of emulator stdexe & stddll images.
1.498 +The segment contains addresses of symbols and NULL
1.499 +terminated ASCII strings of the names of static dependencies.
1.500 +For a stdexe, this segment contains the following:
1.501 + a) symbol count (iSymCount) and static dependency count (iDllCount)
1.502 + b) iSymCount * symbol addresses
1.503 + c) iSymCount * symbol names
1.504 + d) iDllCount * dependency names
1.505 +
1.506 +For a stddll, this segment contains the following:
1.507 + a) symbol count (iSymCout) is always 0
1.508 + b) static dependency count (iDllCount)
1.509 + c) iDllCount * dependency names
1.510 +The symbol addresses and names are not required for a stddll as the Windows API,
1.511 +GetProcAddress may be used to get the addresses for symbol names.
1.512 +Since this API works only on DLL handles, we explicitly list them for stdexes.
1.513 +This is used for emulator images only.
1.514 +*/
1.515 +class E32EmulExpSymInfoHdr
1.516 + {
1.517 +public:
1.518 + TInt32 iSymCount; // Number of symbols
1.519 + TInt32 iDllCount; // Number of static dependency DLLs
1.520 + };
1.521 +
1.522 +
1.523 +
1.524 +#ifdef INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
1.525 +
1.526 +// include code which implements validation functions...
1.527 +
1.528 +#ifndef RETURN_FAILURE
1.529 +#define RETURN_FAILURE(_r) return (_r)
1.530 +#endif
1.531 +
1.532 +#ifndef E32IMAGEHEADER_TRACE
1.533 +#define E32IMAGEHEADER_TRACE(_t) ((void)0)
1.534 +#endif
1.535 +
1.536 +
1.537 +#include <e32uid.h>
1.538 +
1.539 +
1.540 +/**
1.541 +Validate this image header.
1.542 +
1.543 +After successful validation the following are true:
1.544 + - File size is big enough to contain the entire header.
1.545 + - Values #iUidChecksum, #iSignature and #iHeaderCrc are correct.
1.546 + - CPU type (#iCpuIdentifier), ABI type (#iFlags&#KImageABIMask) and
1.547 + entrypoint type (#iFlags&#KImageEptMask) are valid for this system.
1.548 + - Code part of file as specified by #iCodeOffset and #iCodeSize is fully within the file.
1.549 + - Text section size (#iTextSize) is within code part.
1.550 + - Entrypoint value (#iEntryPoint) lies within the code part and is aligned correctly.
1.551 + - Export directory as specified by #iExportDirCount and #iExportDirOffset is fully
1.552 + within code part and is aligned correctly.
1.553 + - Exception description (E32ImageHeaderV::iExceptionDescriptor), if present,
1.554 + lies within the code part.
1.555 + - Data part of file as specified by #iDataOffset and #iDataSize is fully within the file.
1.556 + Or data is not present (#iDataOffset==#iDataSize==0).
1.557 + - Import section (class E32ImportSection at #iImportOffset) is within 'rest of data'
1.558 + and aligned correctly. Data following the E32ImportSection header is NOT validated or
1.559 + checked if it is fully contained within the file.
1.560 + - Code relocations (class E32RelocSection at #iCodeRelocOffset) is within 'rest of data'
1.561 + and aligned correctly. Data following the E32RelocSection header is NOT validated or
1.562 + checked if it is fully contained within the file.
1.563 + - Data relocations (class E32RelocSection at #iDataRelocOffset) is within 'rest of data'
1.564 + and aligned correctly. Data following the E32RelocSection header is NOT validated or
1.565 + checked if it is fully contained within the file.
1.566 + - Export description is validated by E32ImageHeaderV::ValidateExportDescription().
1.567 + - #iUid1 is consistant with #iFlags&#KImageDll. I.e. if flaged as a DLL, #iUid1 is
1.568 + KDynamicLibraryUidValue, otherwise it is KExecutableImageUidValue.
1.569 + - Version number (#iModuleVersion) is valid. (Major and minor versions are <32768).
1.570 + - File compression type (#iCompressionType) is supported.
1.571 + - #iHeapSizeMax>=#iHeapSizeMin
1.572 + - All signed values in header are not negative.
1.573 +
1.574 +@param aFileSize Total size of the file from which this header was created.
1.575 +@param[out] aUncompressedSize Returns the total size that the file data would be once decompressed.
1.576 +
1.577 +@return KErrNone if no errors detected;
1.578 + KErrCorrupt if errors found;
1.579 + KErrNotSupported if image format not supported on this platform.
1.580 +*/
1.581 +TInt E32ImageHeader::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const
1.582 + {
1.583 + // check file is big enough for any header...
1.584 + if(TUint(aFileSize)<sizeof(*this))
1.585 + return KErrCorrupt;
1.586 +
1.587 + TUint hdrfmt = HeaderFormat();
1.588 + if(hdrfmt==KImageHdrFmt_V)
1.589 + return ((E32ImageHeaderV*)this)->ValidateHeader(aFileSize,aUncompressedSize);
1.590 +
1.591 + return KErrNotSupported; // header format unrecognised
1.592 + }
1.593 +
1.594 +/**
1.595 +Validate this image header.
1.596 +
1.597 +@param aFileSize Total size of the file from which this header was created.
1.598 +@param[out] aUncompressedSize Returns the total size that the file data would be once decompressed.
1.599 +
1.600 +@return KErrNone if no errors detected;
1.601 + KErrCorrupt if errors found;
1.602 + KErrNotSupported if image format not supported on this platform.
1.603 +*/
1.604 +TInt E32ImageHeaderV::ValidateHeader(TInt aFileSize, TUint32& aUncompressedSize) const
1.605 + {
1.606 + const TUint KMaxDesSize = 0x0fffffffu; // maximum size of descriptor
1.607 + if(aFileSize==-1)
1.608 + {
1.609 + // file size unknown, set to maximum valid so rest of validation works...
1.610 + aFileSize = KMaxDesSize;
1.611 + }
1.612 + if(TUint(aFileSize)>KMaxDesSize)
1.613 + RETURN_FAILURE(KErrCorrupt); // file size negative or too big
1.614 +
1.615 + aUncompressedSize = 0;
1.616 +
1.617 + // check file is big enough to contain this header...
1.618 + if(aFileSize<(TInt)sizeof(*this))
1.619 + RETURN_FAILURE(KErrCorrupt);
1.620 +
1.621 + // check header format version...
1.622 + if((iFlags&KImageHdrFmtMask)!=KImageHdrFmt_V)
1.623 + RETURN_FAILURE(KErrNotSupported);
1.624 +
1.625 + // check header size...
1.626 + TUint headerSize = iCodeOffset;
1.627 + if(headerSize>TUint(aFileSize))
1.628 + RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because Loader will fail earlier when reading header from file
1.629 +
1.630 + // check iCpuIdentifier...
1.631 + TCpu cpu = (TCpu)iCpuIdentifier;
1.632 + TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
1.633 +#if defined(__CPU_ARM)
1.634 + if(!isARM)
1.635 + RETURN_FAILURE(KErrNotSupported);
1.636 +#elif defined(__CPU_X86)
1.637 + if(cpu!=ECpuX86)
1.638 + RETURN_FAILURE(KErrNotSupported);
1.639 +#endif
1.640 + TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
1.641 +
1.642 + // check iUid1,iUid2,iUid3,iUidChecksum...
1.643 + TUidType uids = *(const TUidType*)&iUid1;
1.644 + TCheckedUid chkuid(uids);
1.645 + const TUint32* pChkUid = (const TUint32*)&chkuid; // need hackery to verify the UID checksum since everything is private
1.646 + if(pChkUid[3]!=iUidChecksum)
1.647 + RETURN_FAILURE(KErrCorrupt);
1.648 +
1.649 + // check iSignature...
1.650 + if(iSignature!=0x434f5045) // 'EPOC'
1.651 + RETURN_FAILURE(KErrCorrupt);
1.652 +
1.653 + // check iHeaderCrc...
1.654 + TUint32 supplied_crc = iHeaderCrc;
1.655 + ((E32ImageHeaderV*)this)->iHeaderCrc = KImageCrcInitialiser;
1.656 + TUint32 crc = 0;
1.657 + Mem::Crc32(crc, this, headerSize);
1.658 + ((E32ImageHeaderV*)this)->iHeaderCrc = supplied_crc;
1.659 + if(crc!=supplied_crc)
1.660 + RETURN_FAILURE(KErrCorrupt);
1.661 +
1.662 + // check iModuleVersion...
1.663 + TUint32 mv = iModuleVersion;
1.664 + if(mv>=0x80000000u || (mv&0x0000ffffu)>0x8000u)
1.665 + RETURN_FAILURE(KErrNotSupported);
1.666 +
1.667 + // check iCompressionType and get uncompressed size...
1.668 + TUint compression = iCompressionType;
1.669 + TUint uncompressedSize = aFileSize;
1.670 + if(compression!=KFormatNotCompressed)
1.671 + {
1.672 + if(compression!=KUidCompressionDeflate && compression!=KUidCompressionBytePair)
1.673 + RETURN_FAILURE(KErrNotSupported); // unknown compression method
1.674 + uncompressedSize = headerSize+iUncompressedSize;
1.675 + if(uncompressedSize<headerSize)
1.676 + RETURN_FAILURE(KErrCorrupt); // size overflowed 32 bits
1.677 + }
1.678 +
1.679 + // check sizes won't overflow the limit for a descriptor (many Loader uses won't like that).
1.680 + if(uncompressedSize>KMaxDesSize)
1.681 + RETURN_FAILURE(KErrCorrupt);
1.682 +
1.683 + // check KImageDll in iFlags...
1.684 + if(iFlags&KImageDll)
1.685 + {
1.686 + if(iUid1!=TUint32(KDynamicLibraryUidValue))
1.687 + RETURN_FAILURE(KErrNotSupported);
1.688 + }
1.689 + else if(iUid1!=TUint32(KExecutableImageUidValue))
1.690 + RETURN_FAILURE(KErrNotSupported);
1.691 +
1.692 + // check iFlags for ABI and entry point types...
1.693 + if(isARM)
1.694 + {
1.695 + if((iFlags&KImageEptMask)!=KImageEpt_Eka2)
1.696 + RETURN_FAILURE(KErrNotSupported);
1.697 + #if defined(__EABI__)
1.698 + if((iFlags&KImageABIMask)!=KImageABI_EABI)
1.699 + RETURN_FAILURE(KErrNotSupported);
1.700 + #elif defined(__GCC32__)
1.701 + if((iFlags&KImageABIMask)!=KImageABI_GCC98r2)
1.702 + RETURN_FAILURE(KErrNotSupported);
1.703 + #endif
1.704 + }
1.705 + else
1.706 + {
1.707 + if(iFlags&KImageEptMask)
1.708 + RETURN_FAILURE(KErrNotSupported); // no special entry point type allowed on non-ARM targets
1.709 + if(iFlags&KImageABIMask)
1.710 + RETURN_FAILURE(KErrNotSupported);
1.711 + }
1.712 +
1.713 + // check iFlags for import format...
1.714 + if((iFlags&KImageImpFmtMask)>KImageImpFmt_PE2)
1.715 + RETURN_FAILURE(KErrNotSupported);
1.716 +
1.717 + // check iHeapSizeMin...
1.718 + if(iHeapSizeMin<0)
1.719 + RETURN_FAILURE(KErrCorrupt);
1.720 +
1.721 + // check iHeapSizeMax...
1.722 + if(iHeapSizeMax<iHeapSizeMin)
1.723 + RETURN_FAILURE(KErrCorrupt);
1.724 +
1.725 + // check iStackSize...
1.726 + if(iStackSize<0)
1.727 + RETURN_FAILURE(KErrCorrupt);
1.728 +
1.729 + // check iBssSize...
1.730 + if(iBssSize<0)
1.731 + RETURN_FAILURE(KErrCorrupt);
1.732 +
1.733 + // check iEntryPoint...
1.734 + if(iEntryPoint>=TUint(iCodeSize))
1.735 + RETURN_FAILURE(KErrCorrupt);
1.736 + if(iEntryPoint+KCodeSegIdOffset+sizeof(TUint32)>TUint(iCodeSize))
1.737 + RETURN_FAILURE(KErrCorrupt);
1.738 + if(iEntryPoint&pointerAlignMask)
1.739 + RETURN_FAILURE(KErrCorrupt); // not aligned
1.740 +
1.741 + // check iCodeBase...
1.742 + if(iCodeBase&3)
1.743 + RETURN_FAILURE(KErrCorrupt); // not aligned
1.744 +
1.745 + // check iDataBase...
1.746 + if(iDataBase&3)
1.747 + RETURN_FAILURE(KErrCorrupt); // not aligned
1.748 +
1.749 + // check iDllRefTableCount...
1.750 + if(iDllRefTableCount<0)
1.751 + RETURN_FAILURE(KErrCorrupt);
1.752 + if(iDllRefTableCount)
1.753 + {
1.754 + if(!iImportOffset)
1.755 + RETURN_FAILURE(KErrCorrupt); // we link to DLLs but have no import data
1.756 + }
1.757 +
1.758 + // check iCodeOffset and iCodeSize specify region in file...
1.759 + TUint codeStart = iCodeOffset;
1.760 + TUint codeEnd = codeStart+iCodeSize;
1.761 + if(codeEnd<codeStart)
1.762 + RETURN_FAILURE(KErrCorrupt);
1.763 +// if(codeStart<headerSize)
1.764 +// RETURN_FAILURE(KErrCorrupt); // can't happen because headerSize is defined as iCodeOffset (codeStart)
1.765 + if(codeEnd>uncompressedSize)
1.766 + RETURN_FAILURE(KErrCorrupt);
1.767 +
1.768 + // check iDataOffset and iDataSize specify region in file...
1.769 + TUint dataStart = iDataOffset;
1.770 + TUint dataEnd = dataStart+iDataSize;
1.771 + if(dataEnd<dataStart)
1.772 + RETURN_FAILURE(KErrCorrupt);
1.773 + if(!dataStart)
1.774 + {
1.775 + // no data...
1.776 + if(dataEnd)
1.777 + RETURN_FAILURE(KErrCorrupt);
1.778 + }
1.779 + else
1.780 + {
1.781 + if(dataStart<codeEnd)
1.782 + RETURN_FAILURE(KErrCorrupt);
1.783 + if(dataEnd>uncompressedSize)
1.784 + RETURN_FAILURE(KErrCorrupt);
1.785 + if((dataStart-codeStart)&pointerAlignMask)
1.786 + RETURN_FAILURE(KErrCorrupt); // data not aligned with respect to code
1.787 + }
1.788 +
1.789 +
1.790 + // check total data size isn't too bit...
1.791 + TUint totalDataSize = iDataSize+iBssSize;
1.792 + if(totalDataSize>0x7fff0000)
1.793 + RETURN_FAILURE(KErrNoMemory);
1.794 +
1.795 + // check iExportDirOffset and iExportDirCount specify region in code part...
1.796 + if(TUint(iExportDirCount)>65535)
1.797 + RETURN_FAILURE(KErrCorrupt); // too many exports
1.798 + if(iExportDirCount)
1.799 + {
1.800 + TUint exportsStart = iExportDirOffset;
1.801 + TUint exportsEnd = exportsStart+iExportDirCount*sizeof(TUint32);
1.802 + if(iFlags&KImageNmdExpData)
1.803 + exportsStart -= sizeof(TUint32); // allow for 0th ordinal
1.804 + if(exportsEnd<exportsStart)
1.805 + RETURN_FAILURE(KErrCorrupt);
1.806 + if(exportsStart<codeStart)
1.807 + RETURN_FAILURE(KErrCorrupt);
1.808 + if(exportsEnd>codeEnd)
1.809 + RETURN_FAILURE(KErrCorrupt);
1.810 + if((exportsStart-codeStart)&pointerAlignMask)
1.811 + RETURN_FAILURE(KErrCorrupt); // not aligned within code section
1.812 + }
1.813 +
1.814 + // check iTextSize...
1.815 + if(TUint(iTextSize)>TUint(iCodeSize))
1.816 + RETURN_FAILURE(KErrCorrupt);
1.817 +
1.818 + // check iImportOffset...
1.819 + TUint start = iImportOffset;
1.820 + if(start)
1.821 + {
1.822 + TUint end = start+sizeof(E32ImportSection); // minimum valid size
1.823 + if(end<start)
1.824 + RETURN_FAILURE(KErrCorrupt);
1.825 + if(start<codeEnd)
1.826 + RETURN_FAILURE(KErrCorrupt);
1.827 + if(end>uncompressedSize)
1.828 + RETURN_FAILURE(KErrCorrupt);
1.829 + if((start-codeEnd)&pointerAlignMask)
1.830 + RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
1.831 + }
1.832 +
1.833 + // check iCodeRelocOffset...
1.834 + start = iCodeRelocOffset;
1.835 + if(start)
1.836 + {
1.837 + TUint end = start+sizeof(E32RelocSection); // minimum valid size
1.838 + if(end<start)
1.839 + RETURN_FAILURE(KErrCorrupt);
1.840 + if(start<codeEnd)
1.841 + RETURN_FAILURE(KErrCorrupt);
1.842 + if(end>uncompressedSize)
1.843 + RETURN_FAILURE(KErrCorrupt);
1.844 + if((start-codeEnd)&pointerAlignMask)
1.845 + RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
1.846 + }
1.847 +
1.848 + // check iDataRelocOffset...
1.849 + start = iDataRelocOffset;
1.850 + if(start)
1.851 + {
1.852 + TUint end = start+sizeof(E32RelocSection); // minimum valid size
1.853 + if(end<start)
1.854 + RETURN_FAILURE(KErrCorrupt);
1.855 + if(start<codeEnd)
1.856 + RETURN_FAILURE(KErrCorrupt);
1.857 + if(end>uncompressedSize)
1.858 + RETURN_FAILURE(KErrCorrupt);
1.859 + if((start-codeEnd)&pointerAlignMask)
1.860 + RETURN_FAILURE(KErrCorrupt); // not aligned within 'rest of data'
1.861 + }
1.862 +
1.863 + // check exception descriptor...
1.864 + if(iExceptionDescriptor&1) // if valid...
1.865 + if(iExceptionDescriptor>=TUint(iCodeSize))
1.866 + RETURN_FAILURE(KErrCorrupt);
1.867 +
1.868 + TInt r = ValidateExportDescription();
1.869 + if(r!=KErrNone)
1.870 + RETURN_FAILURE(r);
1.871 +
1.872 + // done...
1.873 + aUncompressedSize = uncompressedSize;
1.874 + return KErrNone;
1.875 + }
1.876 +
1.877 +
1.878 +/**
1.879 +Valdate that the export description is valid.
1.880 +*/
1.881 +TInt E32ImageHeaderV::ValidateExportDescription() const
1.882 + {
1.883 + TUint headerSize = iCodeOffset;
1.884 +
1.885 + // check export description...
1.886 + TUint edSize = iExportDescSize + sizeof(iExportDescSize) + sizeof(iExportDescType);
1.887 + edSize = (edSize+3)&~3;
1.888 + TUint edEnd = _FOFF(E32ImageHeaderV,iExportDescSize)+edSize;
1.889 + if(edEnd!=headerSize)
1.890 + RETURN_FAILURE(KErrCorrupt);
1.891 +
1.892 + // size of bitmap of exports...
1.893 + TUint bitmapSize = (iExportDirCount+7) >> 3;
1.894 +
1.895 + // check export description bitmap...
1.896 + switch(iExportDescType)
1.897 + {
1.898 + case KImageHdr_ExpD_NoHoles:
1.899 + // no bitmap to check...
1.900 + E32IMAGEHEADER_TRACE(("ValidateExportDescription NoHoles"));
1.901 + return KErrNone;
1.902 +
1.903 + case KImageHdr_ExpD_FullBitmap:
1.904 + // full bitmap present...
1.905 + E32IMAGEHEADER_TRACE(("ValidateExportDescription FullBitmap"));
1.906 + if(bitmapSize!=iExportDescSize)
1.907 + RETURN_FAILURE(KErrCorrupt);
1.908 + return KErrNone;
1.909 +
1.910 + case KImageHdr_ExpD_SparseBitmap8:
1.911 + {
1.912 + // sparse bitmap present...
1.913 + E32IMAGEHEADER_TRACE(("ValidateExportDescription SparseBitmap8"));
1.914 +
1.915 + // get size of meta-bitmap...
1.916 + TUint metaBitmapSize = (bitmapSize+7) >> 3;
1.917 + if(metaBitmapSize>iExportDescSize)
1.918 + RETURN_FAILURE(KErrCorrupt); // doesn't fit
1.919 +
1.920 + TUint totalSize = metaBitmapSize;
1.921 +
1.922 + // scan meta-bitmap counting extra bytes which should be present...
1.923 + const TUint8* metaBitmap = iExportDesc;
1.924 + const TUint8* metaBitmapEnd = metaBitmap + metaBitmapSize;
1.925 + while(metaBitmap<metaBitmapEnd)
1.926 + {
1.927 + TUint bits = *metaBitmap++;
1.928 + do
1.929 + {
1.930 + if(bits&1)
1.931 + ++totalSize; // another byte is present in bitmap
1.932 + }
1.933 + while(bits>>=1);
1.934 + }
1.935 +
1.936 + if(totalSize!=iExportDescSize)
1.937 + RETURN_FAILURE(KErrCorrupt);
1.938 + }
1.939 + return KErrNone;
1.940 +
1.941 + default:
1.942 + E32IMAGEHEADER_TRACE(("ValidateExportDescription ?"));
1.943 + RETURN_FAILURE(KErrNotSupported);
1.944 + }
1.945 + }
1.946 +
1.947 +
1.948 +/**
1.949 +Validate a relocation section.
1.950 +
1.951 +@param aBufferStart Start of buffer containing the data after the code part in the image file.
1.952 +@param aBufferSize Size of data at aBufferStart.
1.953 +@param aRelocationInfoOffset File offset for relocation section. (#iCodeRelocOffset or #iDataRelocOffset.)
1.954 +@param aRelocatedSectionSize Size of section being relocated. (#iCodeSize or #iDataSize.)
1.955 +@param[out] aRelocationSection Set to the start of the relocation section in the given buffer.
1.956 +
1.957 +@return KErrNone if relocation section is valid, else KErrCorrupt.
1.958 +*/
1.959 +TInt E32ImageHeaderV::ValidateRelocations(TAny* aBufferStart, TUint aBufferSize, TUint aRelocationInfoOffset, TUint aRelocatedSectionSize, E32RelocSection*& aRelocationSection) const
1.960 + {
1.961 + aRelocationSection = 0;
1.962 + if(!aRelocationInfoOffset)
1.963 + return KErrNone; // no relocations
1.964 +
1.965 + // get alignment requirements...
1.966 + TCpu cpu = (TCpu)iCpuIdentifier;
1.967 + TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
1.968 + TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
1.969 +
1.970 + // buffer pointer to read relocation from...
1.971 + TUint8* bufferStart = (TUint8*)aBufferStart;
1.972 + TUint8* bufferEnd = bufferStart+aBufferSize;
1.973 + TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart
1.974 + TUint8* sectionStart = (bufferStart+aRelocationInfoOffset-baseOffset);
1.975 + TUint8* p = sectionStart;
1.976 +
1.977 + // read section header (ValidateHeader has alread checked this is OK)...
1.978 + E32RelocSection* sectionHeader = (E32RelocSection*)p;
1.979 + TUint size = sectionHeader->iSize;
1.980 + TUint relocsRemaining = sectionHeader->iNumberOfRelocs;
1.981 + E32IMAGEHEADER_TRACE(("E32RelocSection 0x%x %d",size,relocsRemaining));
1.982 + if(size&3)
1.983 + RETURN_FAILURE(KErrCorrupt); // not multiple of word size
1.984 +
1.985 + // calculate buffer range for block data...
1.986 + p = (TUint8*)(sectionHeader+1); // start of first block
1.987 + TUint8* sectionEnd = p+size;
1.988 + if(sectionEnd<p)
1.989 + RETURN_FAILURE(KErrCorrupt); // math overflow
1.990 + if(sectionEnd>bufferEnd)
1.991 + RETURN_FAILURE(KErrCorrupt); // overflows buffer
1.992 +
1.993 + // process each block...
1.994 + while(p!=sectionEnd)
1.995 + {
1.996 + E32RelocBlock* block = (E32RelocBlock*)p;
1.997 +
1.998 + // get address of first entry in this block...
1.999 + TUint16* entryPtr = (TUint16*)(block+1);
1.1000 + if((TUint8*)entryPtr<(TUint8*)block || (TUint8*)entryPtr>sectionEnd)
1.1001 + RETURN_FAILURE(KErrCorrupt); // overflows relocation section
1.1002 +
1.1003 + // read block header...
1.1004 + TUint pageOffset = block->iPageOffset;
1.1005 + TUint blockSize = block->iBlockSize;
1.1006 + E32IMAGEHEADER_TRACE(("E32RelocSection block 0x%x 0x%x",pageOffset,blockSize));
1.1007 + if(pageOffset&0xfff)
1.1008 + RETURN_FAILURE(KErrCorrupt); // not page aligned
1.1009 + if(blockSize<sizeof(E32RelocBlock))
1.1010 + RETURN_FAILURE(KErrCorrupt); // blockSize must be at least that of the header just read
1.1011 + if(blockSize&3)
1.1012 + RETURN_FAILURE(KErrCorrupt); // not word aligned
1.1013 +
1.1014 + // caculate end of entries in this block...
1.1015 + TUint16* entryEnd = (TUint16*)(p+blockSize);
1.1016 + if(entryEnd<entryPtr)
1.1017 + RETURN_FAILURE(KErrCorrupt); // math overflow
1.1018 + if(entryEnd>(TUint16*)sectionEnd)
1.1019 + RETURN_FAILURE(KErrCorrupt); // overflows relocation section
1.1020 +
1.1021 + // process each entry in this block...
1.1022 + while(entryPtr<entryEnd)
1.1023 + {
1.1024 + TUint entry = *entryPtr++;
1.1025 + E32IMAGEHEADER_TRACE(("E32RelocSection entry 0x%04x",entry));
1.1026 + if(!entry)
1.1027 + continue;
1.1028 +
1.1029 + // check relocation type...
1.1030 + TUint entryType = entry&0xf000;
1.1031 + if(entryType!=KTextRelocType && entryType!=KDataRelocType && entryType!=KInferredRelocType)
1.1032 + RETURN_FAILURE(KErrCorrupt);
1.1033 +
1.1034 + // check relocation is within section being relocated...
1.1035 + TUint offset = pageOffset+(entry&0x0fff);
1.1036 + if(offset>=aRelocatedSectionSize || offset+4>aRelocatedSectionSize)
1.1037 + RETURN_FAILURE(KErrCorrupt); // not within section
1.1038 + if(offset&pointerAlignMask)
1.1039 + RETURN_FAILURE(KErrCorrupt); // not aligned correctly
1.1040 +
1.1041 + // count each relocation processed...
1.1042 + --relocsRemaining;
1.1043 + }
1.1044 +
1.1045 + // next sub block...
1.1046 + p = (TUint8*)entryEnd;
1.1047 + }
1.1048 +
1.1049 + // check number of relocations in section header is correct...
1.1050 + E32IMAGEHEADER_TRACE(("E32RelocSection relocsRemaining=%d",relocsRemaining));
1.1051 + if(relocsRemaining)
1.1052 + RETURN_FAILURE(KErrCorrupt); // incorrect number of entries
1.1053 +
1.1054 + aRelocationSection = sectionHeader;
1.1055 + return KErrNone;
1.1056 + }
1.1057 +
1.1058 +
1.1059 +/**
1.1060 +Validate an import section.
1.1061 +
1.1062 +For PE format imports, this also verifies that the Import Address Table fits within the code
1.1063 +part of the image.
1.1064 +
1.1065 +@param aBufferStart Start of buffer containing the data after the code part in the image file.
1.1066 +@param aBufferSize Size of data at aBufferStart.
1.1067 +@param[out] aBiggestImportCount Largest number of imports the image has from any single dependency.
1.1068 +
1.1069 +@return KErrNone if section is valid (or absent), else KErrCorrupt.
1.1070 +*/
1.1071 +TInt E32ImageHeaderV::ValidateImports(TAny* aBufferStart, TUint aBufferSize, TUint& aBiggestImportCount) const
1.1072 + {
1.1073 + if(!iImportOffset)
1.1074 + {
1.1075 + aBiggestImportCount = 0;
1.1076 + return KErrNone; // no imports
1.1077 + }
1.1078 +
1.1079 + // get alignment requirements...
1.1080 + TCpu cpu = (TCpu)iCpuIdentifier;
1.1081 + TBool isARM = (cpu==ECpuArmV4 || cpu==ECpuArmV5 || cpu==ECpuArmV6);
1.1082 + TUint32 pointerAlignMask = isARM ? 3 : 0; // mask of bits which must be zero for aligned pointers/offsets
1.1083 +
1.1084 + // buffer pointer to read imports from...
1.1085 + TUint8* bufferStart = (TUint8*)aBufferStart;
1.1086 + TUint8* bufferEnd = bufferStart+aBufferSize;
1.1087 + TUint baseOffset = iCodeOffset+iCodeSize; // file offset for aBufferStart
1.1088 + TUint8* sectionStart = (bufferStart+iImportOffset-baseOffset);
1.1089 + TUint8* p = sectionStart;
1.1090 +
1.1091 + // read section header (ValidateHeader has alread checked this is OK)...
1.1092 + E32ImportSection* sectionHeader = (E32ImportSection*)p;
1.1093 + TUint size = sectionHeader->iSize;
1.1094 + E32IMAGEHEADER_TRACE(("E32ImportSection 0x%x",size));
1.1095 +
1.1096 + // check section lies within buffer...
1.1097 + p = (TUint8*)(sectionHeader+1); // start of first import block
1.1098 + TUint8* sectionEnd = sectionStart+size;
1.1099 + if(sectionEnd<p)
1.1100 + RETURN_FAILURE(KErrCorrupt); // math overflow or not big enough to contain header
1.1101 + if(sectionEnd>bufferEnd)
1.1102 + RETURN_FAILURE(KErrCorrupt); // overflows buffer
1.1103 +
1.1104 + // process each import block...
1.1105 + TUint numDeps = iDllRefTableCount;
1.1106 + TUint biggestImportCount = 0;
1.1107 + TUint totalImports = 0;
1.1108 + TUint importFormat = iFlags&KImageImpFmtMask;
1.1109 + while(numDeps--)
1.1110 + {
1.1111 + // get block header...
1.1112 + E32ImportBlock* block = (E32ImportBlock*)p;
1.1113 + p = (TUint8*)(block+1);
1.1114 + if(p<(TUint8*)block || p>sectionEnd)
1.1115 + RETURN_FAILURE(KErrCorrupt); // overflows buffer
1.1116 +
1.1117 + E32IMAGEHEADER_TRACE(("E32ImportBlock 0x%x %d",block->iOffsetOfDllName,block->iNumberOfImports));
1.1118 +
1.1119 + // check import dll name is within section...
1.1120 + TUint8* name = sectionStart+block->iOffsetOfDllName;
1.1121 + if(name<sectionStart || name>=sectionEnd)
1.1122 + RETURN_FAILURE(KErrCorrupt); // not within import section
1.1123 + while(*name++ && name<sectionEnd)
1.1124 + {}
1.1125 + if(name[-1])
1.1126 + RETURN_FAILURE(KErrCorrupt); // name overflows section
1.1127 + E32IMAGEHEADER_TRACE(("E32ImportBlock %s",sectionStart+block->iOffsetOfDllName));
1.1128 +
1.1129 + // process import count...
1.1130 + TUint numberOfImports = block->iNumberOfImports;
1.1131 + if(numberOfImports>=0x80000000u/sizeof(TUint32))
1.1132 + RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer
1.1133 + if(numberOfImports>biggestImportCount)
1.1134 + biggestImportCount = numberOfImports;
1.1135 + totalImports += numberOfImports;
1.1136 +
1.1137 + // process import data...
1.1138 +
1.1139 + // PE2 doesn't have any more data...
1.1140 + if(importFormat==KImageImpFmt_PE2)
1.1141 + continue;
1.1142 +
1.1143 + // get import data range...
1.1144 + TUint32* imports = (TUint32*)p;
1.1145 + TUint32* importsEnd = imports+numberOfImports;
1.1146 + if(importsEnd<imports)
1.1147 + RETURN_FAILURE(KErrCorrupt); // math overflow. Fuzzer can't trigger this because needs aBufferStart to be in to be >0x80000000
1.1148 + if(importsEnd>(TUint32*)sectionEnd)
1.1149 + RETURN_FAILURE(KErrCorrupt); // overflows buffer
1.1150 +
1.1151 + // move pointer on to next block...
1.1152 + p = (TUint8*)importsEnd;
1.1153 +
1.1154 + if(importFormat==KImageImpFmt_ELF)
1.1155 + {
1.1156 + // check imports are in code section...
1.1157 + TUint32 limit = iCodeSize-sizeof(TUint32);
1.1158 + while(imports<importsEnd)
1.1159 + {
1.1160 + TUint32 i = *imports++;
1.1161 + if(i>limit)
1.1162 + RETURN_FAILURE(KErrCorrupt);
1.1163 + if(i&pointerAlignMask)
1.1164 + RETURN_FAILURE(KErrCorrupt); // not word aligned
1.1165 + }
1.1166 + }
1.1167 + else if(importFormat==KImageImpFmt_PE)
1.1168 + {
1.1169 + // import data is not used, so don't bother checking it
1.1170 + }
1.1171 + else
1.1172 + {
1.1173 + RETURN_FAILURE(KErrCorrupt); // bad import format, Fuzzer can't trigger this because import format checked by header validation
1.1174 + }
1.1175 +
1.1176 + // next block...
1.1177 + p = (TUint8*)block->NextBlock(importFormat);
1.1178 + }
1.1179 +
1.1180 + // done processing imports; for PE derived files now check import address table (IAT)...
1.1181 + if(importFormat==KImageImpFmt_PE || importFormat==KImageImpFmt_PE2)
1.1182 + {
1.1183 + if(totalImports>=0x80000000u/sizeof(TUint32))
1.1184 + RETURN_FAILURE(KErrCorrupt); // size doesn't fit into a signed integer
1.1185 + TUint importAddressTable = iTextSize; // offset for IAT
1.1186 + if(importAddressTable&pointerAlignMask)
1.1187 + RETURN_FAILURE(KErrCorrupt); // Fuzzer can't trigger this because PE imports are for X86 which doesn't have alignment restrictions
1.1188 + TUint importAddressTableEnd = importAddressTable+sizeof(TUint32)*totalImports;
1.1189 + if(importAddressTableEnd<importAddressTable || importAddressTableEnd>TUint(iCodeSize))
1.1190 + RETURN_FAILURE(KErrCorrupt); // import address table overflows code part of file
1.1191 + E32IMAGEHEADER_TRACE(("E32ImportSection IAT offsets 0x%x..0x%x",importAddressTable,importAddressTableEnd));
1.1192 + }
1.1193 +
1.1194 + aBiggestImportCount = biggestImportCount;
1.1195 + return KErrNone;
1.1196 + }
1.1197 +
1.1198 +
1.1199 +
1.1200 +
1.1201 +/**
1.1202 +Validate a whole executable image.
1.1203 +
1.1204 +This runs all of the other validation methods in turn.
1.1205 +
1.1206 +@param aBufferStart Start of buffer containing the data after the header part of an image file.
1.1207 +@param aBufferSize Size of data at aBufferStart.
1.1208 +
1.1209 +@return KErrNone if image is valid, else KErrCorrupt or KErrNotSupported.
1.1210 +*/
1.1211 +TInt E32ImageHeaderV::ValidateWholeImage(TAny* aBufferStart, TUint aBufferSize) const
1.1212 + {
1.1213 + TUint32 dummyUncompressedSize;
1.1214 + TInt r = ValidateHeader(TotalSize()+aBufferSize,dummyUncompressedSize);
1.1215 + if(r!=KErrNone)
1.1216 + return r;
1.1217 +
1.1218 + TInt endOfCodeOffset = iCodeSize;
1.1219 + void* restOfFileData = ((TUint8*)aBufferStart)+endOfCodeOffset;
1.1220 + TInt restOfFileSize = aBufferSize-endOfCodeOffset;
1.1221 +
1.1222 + E32RelocSection* dummy;
1.1223 + r = ValidateRelocations(restOfFileData,restOfFileSize,iCodeRelocOffset,iCodeSize,dummy);
1.1224 + if(r!=KErrNone)
1.1225 + return r;
1.1226 + r = ValidateRelocations(restOfFileData,restOfFileSize,iDataRelocOffset,iDataSize,dummy);
1.1227 + if(r!=KErrNone)
1.1228 + return r;
1.1229 +
1.1230 + TUint biggestImportCount;
1.1231 + r = ValidateImports(restOfFileData,restOfFileSize,biggestImportCount);
1.1232 + if(r!=KErrNone)
1.1233 + return r;
1.1234 +
1.1235 + return r;
1.1236 + }
1.1237 +
1.1238 +
1.1239 +#endif // INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
1.1240 +
1.1241 +
1.1242 +#endif // __F32IMAGE_H__