diff options
Diffstat (limited to 'src/inc/corhlpr.h')
-rw-r--r-- | src/inc/corhlpr.h | 694 |
1 files changed, 694 insertions, 0 deletions
diff --git a/src/inc/corhlpr.h b/src/inc/corhlpr.h new file mode 100644 index 0000000000..02555c9ec3 --- /dev/null +++ b/src/inc/corhlpr.h @@ -0,0 +1,694 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/***************************************************************************** + ** ** + ** Corhlpr.h - ** + ** ** + *****************************************************************************/ + + +#ifndef __CORHLPR_H__ +#define __CORHLPR_H__ + +#if defined(_MSC_VER) && defined(_X86_) && !defined(FPO_ON) +#pragma optimize("y", on) // Small critical routines, don't put in EBP frame +#define FPO_ON 1 +#define CORHLPR_TURNED_FPO_ON 1 +#endif + +#include "cor.h" +#include "corhdr.h" +#include "corerror.h" + +// This header is consumed both within the runtime and externally. In the former +// case we need to wrap memory allocations, in the latter there is no +// infrastructure to support this. Detect which way we're building and provide a +// very simple abstraction layer (handles allocating bytes only). +#ifdef _BLD_CLR +#include "new.hpp" + + +#define NEW_NOTHROW(_bytes) new (nothrow) BYTE[_bytes] +#define NEW_THROWS(_bytes) new BYTE[_bytes] +void DECLSPEC_NORETURN ThrowOutOfMemory(); +inline void DECLSPEC_NORETURN THROW_OUT_OF_MEMORY() +{ + ThrowOutOfMemory(); +} +#else +#define NEW_NOTHROW(_bytes) new BYTE[_bytes] +#define NEW_THROWS(_bytes) __CorHlprNewThrows(_bytes) +static inline void DECLSPEC_NORETURN __CorHlprThrowOOM() +{ + RaiseException(STATUS_NO_MEMORY, 0, 0, NULL); +} +static inline BYTE *__CorHlprNewThrows(size_t bytes) +{ + BYTE *pbMemory = new BYTE[bytes]; + if (pbMemory == NULL) + __CorHlprThrowOOM(); + return pbMemory; +} +inline void DECLSPEC_NORETURN THROW_OUT_OF_MEMORY() +{ + __CorHlprThrowOOM(); +} +#endif + + +//***************************************************************************** +// There are a set of macros commonly used in the helpers which you will want +// to override to get richer behavior. The following defines what is needed +// if you chose not to do the extra work. +//***************************************************************************** +#ifndef IfFailGoto +#define IfFailGoto(EXPR, LABEL) \ +do { hr = (EXPR); if(FAILED(hr)) { goto LABEL; } } while (0) +#endif + +#ifndef IfFailGo +#define IfFailGo(EXPR) IfFailGoto(EXPR, ErrExit) +#endif + +#ifndef IfFailRet +#define IfFailRet(EXPR) do { hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0) +#endif + +#ifndef IfNullRet +#define IfNullRet(EXPR) do { if ((EXPR) == NULL){ return (E_OUTOFMEMORY); } } while (0) +#endif + + +#ifndef _ASSERTE +#define _ASSERTE(expr) +#endif + +#ifndef COUNTOF +#define COUNTOF(a) (sizeof(a) / sizeof(*a)) +#endif + +#if !BIGENDIAN +#define VAL16(x) x +#define VAL32(x) x +#endif + + +//***************************************************************************** +// +//***** Macro to assist with cleaning up local static variables +// +//***************************************************************************** + +#define CHECK_LOCAL_STATIC_VAR(x) \ + x \ + +//***************************************************************************** +// +//***** Utility helpers +// +//***************************************************************************** + + +#define MAX_CLASSNAME_LENGTH 1024 + +//***************************************************************************** +// +//***** Signature helpers +// +//***************************************************************************** + +inline bool isCallConv(unsigned sigByte, CorCallingConvention conv) +{ + return ((sigByte & IMAGE_CEE_CS_CALLCONV_MASK) == (unsigned) conv); +} + +//***************************************************************************** +// +//***** File format helper classes +// +//***************************************************************************** + + + +//***************************************************************************** +typedef struct tagCOR_ILMETHOD_SECT_SMALL : IMAGE_COR_ILMETHOD_SECT_SMALL { + //Data follows + const BYTE* Data() const + { + return(((const BYTE*) this) + sizeof(struct tagCOR_ILMETHOD_SECT_SMALL)); + } + + bool IsSmall() const + { + return (Kind & CorILMethod_Sect_FatFormat) == 0; + } + + bool More() const + { + return (Kind & CorILMethod_Sect_MoreSects) != 0; + } +} COR_ILMETHOD_SECT_SMALL; + + +/************************************/ +/* NOTE this structure must be DWORD aligned!! */ +typedef struct tagCOR_ILMETHOD_SECT_FAT : IMAGE_COR_ILMETHOD_SECT_FAT { + //Data follows + const BYTE* Data() const + { + return(((const BYTE*) this) + sizeof(struct tagCOR_ILMETHOD_SECT_FAT)); + } + + //Endian-safe wrappers + unsigned GetKind() const { + /* return Kind; */ + return *(BYTE*)this; + } + void SetKind(unsigned kind) { + /* Kind = kind; */ + *(BYTE*)this = (BYTE)kind; + } + + unsigned GetDataSize() const { + /* return DataSize; */ + BYTE* p = (BYTE*)this; + return ((unsigned)*(p+1)) | + (((unsigned)*(p+2)) << 8) | + (((unsigned)*(p+3)) << 16); + } + void SetDataSize(unsigned datasize) { + /* DataSize = dataSize; */ + BYTE* p = (BYTE*)this; + *(p+1) = (BYTE)(datasize); + *(p+2) = (BYTE)(datasize >> 8); + *(p+3) = (BYTE)(datasize >> 16); + } +} COR_ILMETHOD_SECT_FAT; + +typedef struct tagCOR_ILMETHOD_SECT_EH_CLAUSE_FAT : public IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT { + //Endian-safe wrappers + CorExceptionFlag GetFlags() const { + return (CorExceptionFlag)VAL32((unsigned)Flags); + } + void SetFlags(CorExceptionFlag flags) { + Flags = (CorExceptionFlag)VAL32((unsigned)flags); + } + + DWORD GetTryOffset() const { + return VAL32(TryOffset); + } + void SetTryOffset(DWORD Offset) { + TryOffset = VAL32(Offset); + } + + DWORD GetTryLength() const { + return VAL32(TryLength); + } + void SetTryLength(DWORD Length) { + TryLength = VAL32(Length); + } + + DWORD GetHandlerOffset() const { + return VAL32(HandlerOffset); + } + void SetHandlerOffset(DWORD Offset) { + HandlerOffset = VAL32(Offset); + } + + DWORD GetHandlerLength() const { + return VAL32(HandlerLength); + } + void SetHandlerLength(DWORD Length) { + HandlerLength = VAL32(Length); + } + + DWORD GetClassToken() const { + return VAL32(ClassToken); + } + void SetClassToken(DWORD tok) { + ClassToken = VAL32(tok); + } + + DWORD GetFilterOffset() const { + return VAL32(FilterOffset); + } + void SetFilterOffset(DWORD offset) { + FilterOffset = VAL32(offset); + } + +} COR_ILMETHOD_SECT_EH_CLAUSE_FAT; + +//***************************************************************************** +struct COR_ILMETHOD_SECT_EH_FAT : public COR_ILMETHOD_SECT_FAT { + static unsigned Size(unsigned ehCount) { + return (sizeof(COR_ILMETHOD_SECT_EH_FAT) + + sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT) * (ehCount-1)); + } + + IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT Clauses[1]; // actually variable size +}; + +typedef struct tagCOR_ILMETHOD_SECT_EH_CLAUSE_SMALL : public IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL { + //Endian-safe wrappers + CorExceptionFlag GetFlags() const { + return (CorExceptionFlag)VAL16((SHORT)Flags); + } + void SetFlags(CorExceptionFlag flags) { + Flags = (CorExceptionFlag)VAL16((SHORT)flags); + } + + DWORD GetTryOffset() const { + return VAL16(TryOffset); + } + void SetTryOffset(DWORD Offset) { + _ASSERTE((Offset & ~0xffff) == 0); + TryOffset = VAL16(Offset); + } + + DWORD GetTryLength() const { + return TryLength; + } + void SetTryLength(DWORD Length) { + _ASSERTE((Length & ~0xff) == 0); + TryLength = Length; + } + + DWORD GetHandlerOffset() const { + return VAL16(HandlerOffset); + } + void SetHandlerOffset(DWORD Offset) { + _ASSERTE((Offset & ~0xffff) == 0); + HandlerOffset = VAL16(Offset); + } + + DWORD GetHandlerLength() const { + return HandlerLength; + } + void SetHandlerLength(DWORD Length) { + _ASSERTE((Length & ~0xff) == 0); + HandlerLength = Length; + } + + DWORD GetClassToken() const { + return VAL32(ClassToken); + } + void SetClassToken(DWORD tok) { + ClassToken = VAL32(tok); + } + + DWORD GetFilterOffset() const { + return VAL32(FilterOffset); + } + void SetFilterOffset(DWORD offset) { + FilterOffset = VAL32(offset); + } +} COR_ILMETHOD_SECT_EH_CLAUSE_SMALL; + +//***************************************************************************** +struct COR_ILMETHOD_SECT_EH_SMALL : public COR_ILMETHOD_SECT_SMALL { + static unsigned Size(unsigned ehCount) { + return (sizeof(COR_ILMETHOD_SECT_EH_SMALL) + + sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL) * (ehCount-1)); + } + + WORD Reserved; // alignment padding + IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL Clauses[1]; // actually variable size +}; + + +/************************************/ +/* NOTE this structure must be DWORD aligned!! */ +struct COR_ILMETHOD_SECT +{ + bool More() const + { + return((AsSmall()->Kind & CorILMethod_Sect_MoreSects) != 0); + } + + CorILMethodSect Kind() const + { + return((CorILMethodSect) (AsSmall()->Kind & CorILMethod_Sect_KindMask)); + } + + const COR_ILMETHOD_SECT* Next() const + { + if (!More()) return(0); + return ((COR_ILMETHOD_SECT*)(((BYTE *)this) + DataSize()))->Align(); + } + + const BYTE* Data() const + { + if (IsFat()) return(AsFat()->Data()); + return(AsSmall()->Data()); + } + + unsigned DataSize() const + { + if (Kind() == CorILMethod_Sect_EHTable) + { + // VB and MC++ shipped with bug where they have not accounted for size of COR_ILMETHOD_SECT_EH_XXX + // in DataSize. To avoid breaking these images, we will align the size of EH sections up. This works + // because IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_XXX is bigger than COR_ILMETHOD_SECT_EH_XXX + // (see VSWhidbey #99031 and related bugs for details). + + if (IsFat()) + return Fat.Size(Fat.GetDataSize() / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT)); + else + return Small.Size(Small.DataSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL)); + } + else + { + if (IsFat()) return(AsFat()->GetDataSize()); + return(AsSmall()->DataSize); + } + } + + friend struct COR_ILMETHOD; + friend struct tagCOR_ILMETHOD_FAT; + friend struct tagCOR_ILMETHOD_TINY; + bool IsFat() const + { + return((AsSmall()->Kind & CorILMethod_Sect_FatFormat) != 0); + } + + const COR_ILMETHOD_SECT* Align() const + { + return((COR_ILMETHOD_SECT*) ((((UINT_PTR) this) + 3) & ~3)); + } + +protected: + const COR_ILMETHOD_SECT_FAT* AsFat() const + { + return((COR_ILMETHOD_SECT_FAT*) this); + } + + const COR_ILMETHOD_SECT_SMALL* AsSmall() const + { + return((COR_ILMETHOD_SECT_SMALL*) this); + } + +public: + // The body is either a COR_ILMETHOD_SECT_SMALL or COR_ILMETHOD_SECT_FAT + // (as indicated by the CorILMethod_Sect_FatFormat bit + union { + COR_ILMETHOD_SECT_EH_SMALL Small; + COR_ILMETHOD_SECT_EH_FAT Fat; + }; +}; + + +/***********************************/ +// exported functions (implementation in Format\Format.cpp: +extern "C" { +IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* __stdcall SectEH_EHClause(void *pSectEH, unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff); + // compute the size of the section (best format) + // codeSize is the size of the method + // deprecated +unsigned __stdcall SectEH_SizeWithCode(unsigned ehCount, unsigned codeSize); + + // will return worse-case size and then Emit will return actual size +unsigned __stdcall SectEH_SizeWorst(unsigned ehCount); + + // will return exact size which will match the size returned by Emit +unsigned __stdcall SectEH_SizeExact(unsigned ehCount, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses); + + // emit the section (best format); +unsigned __stdcall SectEH_Emit(unsigned size, unsigned ehCount, + IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses, + BOOL moreSections, BYTE* outBuff, + ULONG* ehTypeOffsets = 0); +} // extern "C" + + +struct COR_ILMETHOD_SECT_EH : public COR_ILMETHOD_SECT +{ + unsigned EHCount() const + { + return (unsigned)(IsFat() ? (Fat.GetDataSize() / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT)) : + (Small.DataSize / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL))); + } + + // return one clause in its fat form. Use 'buff' if needed + const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* EHClause(unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff) const + { + return SectEH_EHClause((void *)this, idx, buff); + }; + // compute the size of the section (best format) + // codeSize is the size of the method + // deprecated + unsigned static Size(unsigned ehCount, unsigned codeSize) + { + return SectEH_SizeWithCode(ehCount, codeSize); + }; + + // will return worse-case size and then Emit will return actual size + unsigned static Size(unsigned ehCount) + { + return SectEH_SizeWorst(ehCount); + }; + + // will return exact size which will match the size returned by Emit + unsigned static Size(unsigned ehCount, const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses) + { + return SectEH_SizeExact(ehCount, (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)clauses); + }; + + // emit the section (best format); + unsigned static Emit(unsigned size, unsigned ehCount, + const IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses, + bool moreSections, BYTE* outBuff, + ULONG* ehTypeOffsets = 0) + { + return SectEH_Emit(size, ehCount, + (IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)clauses, + moreSections, outBuff, ehTypeOffsets); + }; +}; + + +/***************************************************************************/ +/* Used when the method is tiny (< 64 bytes), and there are no local vars */ +typedef struct tagCOR_ILMETHOD_TINY : IMAGE_COR_ILMETHOD_TINY +{ + bool IsTiny() const + { + return((Flags_CodeSize & (CorILMethod_FormatMask >> 1)) == CorILMethod_TinyFormat); + } + + unsigned GetCodeSize() const + { + return(((unsigned) Flags_CodeSize) >> (CorILMethod_FormatShift-1)); + } + + unsigned GetMaxStack() const + { + return(8); + } + + BYTE* GetCode() const + { + return(((BYTE*) this) + sizeof(struct tagCOR_ILMETHOD_TINY)); + } + + DWORD GetLocalVarSigTok() const + { + return(0); + } + + COR_ILMETHOD_SECT* GetSect() const + { + return(0); + } +} COR_ILMETHOD_TINY; + + +/************************************/ +// This strucuture is the 'fat' layout, where no compression is attempted. +// Note that this structure can be added on at the end, thus making it extensible +typedef struct tagCOR_ILMETHOD_FAT : IMAGE_COR_ILMETHOD_FAT +{ + //Endian-safe wrappers + unsigned GetSize() const { + /* return Size; */ + BYTE* p = (BYTE*)this; + return *(p+1) >> 4; + } + void SetSize(unsigned size) { + /* Size = size; */ + BYTE* p = (BYTE*)this; + *(p+1) = (BYTE)((*(p+1) & 0x0F) | (size << 4)); + } + + unsigned GetFlags() const { + /* return Flags; */ + BYTE* p = (BYTE*)this; + return ((unsigned)*(p+0)) | (( ((unsigned)*(p+1)) & 0x0F) << 8); + } + void SetFlags(unsigned flags) { + /* flags = Flags; */ + BYTE* p = (BYTE*)this; + *p = (BYTE)flags; + *(p+1) = (BYTE)((*(p+1) & 0xF0) | ((flags >> 8) & 0x0F)); + } + + bool IsFat() const { + /* return((IMAGE_COR_ILMETHOD_FAT::GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat); */ + return (*(BYTE*)this & CorILMethod_FormatMask) == CorILMethod_FatFormat; + } + + unsigned GetMaxStack() const { + /* return MaxStack; */ + return VAL16(*(USHORT*)((BYTE*)this+2)); + } + void SetMaxStack(unsigned maxStack) { + /* MaxStack = maxStack; */ + *(USHORT*)((BYTE*)this+2) = VAL16((USHORT)maxStack); + } + + unsigned GetCodeSize() const + { + return VAL32(CodeSize); + } + + void SetCodeSize(DWORD Size) + { + CodeSize = VAL32(Size); + } + + mdToken GetLocalVarSigTok() const + { + return VAL32(LocalVarSigTok); + } + + void SetLocalVarSigTok(mdSignature tok) + { + LocalVarSigTok = VAL32(tok); + } + + BYTE* GetCode() const { + return(((BYTE*) this) + 4*GetSize()); + } + + bool More() const { + // return (GetFlags() & CorILMethod_MoreSects) != 0; + return (*(BYTE*)this & CorILMethod_MoreSects) != 0; + } + + const COR_ILMETHOD_SECT* GetSect() const { + if (!More()) return (0); + return(((COR_ILMETHOD_SECT*) (GetCode() + GetCodeSize()))->Align()); + } +} COR_ILMETHOD_FAT; + + +extern "C" { +/************************************/ +// exported functions (impl. Format\Format.cpp) +unsigned __stdcall IlmethodSize(COR_ILMETHOD_FAT* header, BOOL MoreSections); + // emit the header (bestFormat) return amount emitted +unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* header, + BOOL moreSections, BYTE* outBuff); +} + +struct COR_ILMETHOD +{ + // a COR_ILMETHOD header should not be decoded by hand. Instead us + // COR_ILMETHOD_DECODER to decode it. + friend class COR_ILMETHOD_DECODER; + + // compute the size of the header (best format) + unsigned static Size(const COR_ILMETHOD_FAT* header, bool MoreSections) + { + return IlmethodSize((COR_ILMETHOD_FAT*)header,MoreSections); + }; + // emit the header (bestFormat) return amount emitted + unsigned static Emit(unsigned size, const COR_ILMETHOD_FAT* header, + bool moreSections, BYTE* outBuff) + { + return IlmethodEmit(size, (COR_ILMETHOD_FAT*)header, moreSections, outBuff); + }; + +//private: + union + { + COR_ILMETHOD_TINY Tiny; + COR_ILMETHOD_FAT Fat; + }; + // Code follows the Header, then immedately after the code comes + // any sections (COR_ILMETHOD_SECT). +}; + +extern "C" { +/***************************************************************************/ +/* COR_ILMETHOD_DECODER is the only way functions internal to the EE should + fetch data from a COR_ILMETHOD. This way any dependancy on the file format + (and the multiple ways of encoding the header) is centralized to the + COR_ILMETHOD_DECODER constructor) */ + void __stdcall DecoderInit(void * pThis, COR_ILMETHOD* header); + int __stdcall DecoderGetOnDiskSize(void * pThis, COR_ILMETHOD* header); +} // extern "C" + +class COR_ILMETHOD_DECODER : public COR_ILMETHOD_FAT +{ +public: + // Typically the ONLY way you should access COR_ILMETHOD is through + // this constructor so format changes are easier. + COR_ILMETHOD_DECODER(const COR_ILMETHOD* header) + { + DecoderInit(this,(COR_ILMETHOD*)header); + }; + + // The above variant of the constructor can not do a 'complete' job, because + // it can not look up the local variable signature meta-data token. + // This method should be used when you have access to the Meta data API + // If the construction fails, the 'Code' field is set to 0 + + enum DecoderStatus {SUCCESS, FORMAT_ERROR, VERIFICATION_ERROR}; + + // If we want the decoder to verify the that local signature is OK we + // will pass a non-NULL value for wbStatus + // + // When using LazyInit we want ask that the local signature be verified + // But if we fail verification we still need access to the 'Code' field + // Because we may be able to demand SkipVerification and thus it was OK + // to have had a verification error. + + COR_ILMETHOD_DECODER(COR_ILMETHOD* header, + void *pInternalImport, + DecoderStatus* wbStatus); + + unsigned EHCount() const + { + return (EH != 0) ? EH->EHCount() : 0; + } + + unsigned GetHeaderSize() const + { + return GetCodeSize() + ((EH != 0) ? EH->DataSize() : 0); + } + + // returns total size of method for use in copying + int GetOnDiskSize(const COR_ILMETHOD* header) + { + return DecoderGetOnDiskSize(this,(COR_ILMETHOD*)header); + } + + // Flags these are available because we inherit COR_ILMETHOD_FAT + // MaxStack + // CodeSize + const BYTE * Code; + PCCOR_SIGNATURE LocalVarSig; // pointer to signature blob, or 0 if none + DWORD cbLocalVarSig; // size of dignature blob, or 0 if none + const COR_ILMETHOD_SECT_EH * EH; // eh table if any 0 if none + const COR_ILMETHOD_SECT * Sect; // additional sections 0 if none +}; // class COR_ILMETHOD_DECODER + +#if defined(CORHLPR_TURNED_FPO_ON) +#pragma optimize("", on) // Go back to command line default optimizations +#undef CORHLPR_TURNED_FPO_ON +#undef FPO_ON +#endif + +#endif // __CORHLPR_H__ |