xpmgr/BuildTools/Include/corhlpr.h

703 lines
21 KiB
C++

// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// See code:EEStartup#TableOfContents for EE overview
/*****************************************************************************
** **
** Corhlpr.h - <STRIP>this file contains a set of "as is" code that may be **
** used by developers writing compilers and tools against **
** the Common Language Runtime. The code is not officially **
** supported, but is code being used by the Runtime itself. **
** </STRIP> **
** **
*****************************************************************************/
#ifndef __CORHLPR_H__
#define __CORHLPR_H__
#if defined(_MSC_VER) && defined(_X86_)
#pragma optimize("y", on) // If routines don't get inlined, don't pay the EBP frame penalty
#endif
#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(_MSC_VER) && defined(_X86_)
#pragma optimize("", on) // restore command line default optimizations
#endif
#endif // __CORHLPR_H__