diff options
Diffstat (limited to 'src/inc/corhlpr.cpp')
-rw-r--r-- | src/inc/corhlpr.cpp | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/src/inc/corhlpr.cpp b/src/inc/corhlpr.cpp new file mode 100644 index 0000000000..ba803a5616 --- /dev/null +++ b/src/inc/corhlpr.cpp @@ -0,0 +1,307 @@ +// 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 - signature helpers. ** + ** ** + ****************************************************************************/ +#ifndef SOS_INCLUDE + +#ifdef _BLD_CLR +#include "utilcode.h" +#endif +#include "corhlpr.h" +#include <stdlib.h> + +#endif // !SOS_INCLUDE + + +//***************************************************************************** +// +//***** File format helper classes +// +//***************************************************************************** + +extern "C" { + +/***************************************************************************/ +/* Note that this construtor does not set the LocalSig, but has the + advantage that it does not have any dependancy on EE structures. + inside the EE use the FunctionDesc constructor */ + +void __stdcall DecoderInit(void *pThis, COR_ILMETHOD *header) +{ + COR_ILMETHOD_DECODER *decoder = (COR_ILMETHOD_DECODER *)pThis; + + memset(decoder, 0, sizeof(COR_ILMETHOD_DECODER)); + if (header->Tiny.IsTiny()) + { + decoder->SetMaxStack(header->Tiny.GetMaxStack()); + decoder->Code = header->Tiny.GetCode(); + decoder->SetCodeSize(header->Tiny.GetCodeSize()); + decoder->SetFlags(CorILMethod_TinyFormat); + return; + } + if (header->Fat.IsFat()) + { +#ifdef _WIN64 + if((((size_t) header) & 3) == 0) // header is aligned +#else + _ASSERTE((((size_t) header) & 3) == 0); // header is aligned +#endif + { + *((COR_ILMETHOD_FAT *)decoder) = header->Fat; + decoder->Code = header->Fat.GetCode(); + if (header->Fat.GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4)) // Size if valid + { + decoder->Sect = header->Fat.GetSect(); + if ((decoder->Sect != NULL) && (decoder->Sect->Kind() == CorILMethod_Sect_EHTable)) + { + decoder->EH = (COR_ILMETHOD_SECT_EH *)decoder->Sect; + decoder->Sect = decoder->Sect->Next(); + } + } + } + return; + } +} // DecoderInit + +// Calculate the total method size. First get address of end of code. If there are no sections, then +// the end of code addr marks end of COR_ILMETHOD. Otherwise find addr of end of last section and use it +// to mark end of COR_ILMETHOD. Assumes that the code is directly followed +// by each section in the on-disk format +int __stdcall DecoderGetOnDiskSize(void * pThis, COR_ILMETHOD* header) +{ + COR_ILMETHOD_DECODER* decoder = (COR_ILMETHOD_DECODER*)pThis; + + if (decoder->Code == NULL) + return 0; + + BYTE *lastAddr = (BYTE*)decoder->Code + decoder->GetCodeSize(); // addr of end of code + const COR_ILMETHOD_SECT *sect = decoder->EH; + if (sect != 0 && sect->Next() == 0) + { + lastAddr = (BYTE *)sect + sect->DataSize(); + } + else + { + const COR_ILMETHOD_SECT *nextSect; + for (sect = decoder->Sect; sect; sect = nextSect) + { + nextSect = sect->Next(); + if (nextSect == 0) + { + // sect points to the last section, so set lastAddr + lastAddr = (BYTE *)sect + sect->DataSize(); + break; + } + } + } + return (int)(lastAddr - (BYTE*)header); +} + +/*********************************************************************/ +/* APIs for emitting sections etc */ + +unsigned __stdcall IlmethodSize(COR_ILMETHOD_FAT* header, BOOL moreSections) +{ + if (header->GetMaxStack() <= 8 && (header->GetFlags() & ~CorILMethod_FormatMask) == 0 + && header->GetLocalVarSigTok() == 0 && header->GetCodeSize() < 64 && !moreSections) + return(sizeof(COR_ILMETHOD_TINY)); + + return(sizeof(COR_ILMETHOD_FAT)); +} + +/*********************************************************************/ + // emit the header (bestFormat) return amount emitted +unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* header, + BOOL moreSections, BYTE* outBuff) +{ +#ifndef SOS_INCLUDE +#ifdef _DEBUG + BYTE* origBuff = outBuff; +#endif +#endif // !SOS_INCLUDE + if (size == 1) { + // Tiny format + *outBuff++ = (BYTE) (CorILMethod_TinyFormat | (header->GetCodeSize() << 2)); + } + else { + // Fat format + _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned + COR_ILMETHOD_FAT* fatHeader = (COR_ILMETHOD_FAT*) outBuff; + outBuff += sizeof(COR_ILMETHOD_FAT); + *fatHeader = *header; + fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_FatFormat); + _ASSERTE((fatHeader->GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat); + if (moreSections) + fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_MoreSects); + fatHeader->SetSize(sizeof(COR_ILMETHOD_FAT) / 4); + } +#ifndef SOS_INCLUDE + _ASSERTE(&origBuff[size] == outBuff); +#endif // !SOS_INCLUDE + return(size); +} + +/*********************************************************************/ +/* static */ +IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* __stdcall SectEH_EHClause(void *pSectEH, unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff) +{ + if (((COR_ILMETHOD_SECT_EH *)pSectEH)->IsFat()) + return(&(((COR_ILMETHOD_SECT_EH *)pSectEH)->Fat.Clauses[idx])); + + COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)buff; + COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&((COR_ILMETHOD_SECT_EH *)pSectEH)->Small.Clauses[idx]; + + // mask to remove sign extension - cast just wouldn't work + fatClause->SetFlags((CorExceptionFlag)(smallClause->GetFlags()&0x0000ffff)); + fatClause->SetClassToken(smallClause->GetClassToken()); + fatClause->SetTryOffset(smallClause->GetTryOffset()); + fatClause->SetTryLength(smallClause->GetTryLength()); + fatClause->SetHandlerLength(smallClause->GetHandlerLength()); + fatClause->SetHandlerOffset(smallClause->GetHandlerOffset()); + return(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) +{ + return((ehCount)? SectEH_SizeWorst(ehCount) : 0); +} + + // will return worse-case size and then Emit will return actual size +unsigned __stdcall SectEH_SizeWorst(unsigned ehCount) +{ + return((ehCount)? (COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)) : 0); +} + + // 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) +{ + if (ehCount == 0) + return(0); + + unsigned smallSize = COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount); + if (smallSize > COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) + return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)); + for (unsigned i = 0; i < ehCount; i++) { + COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i]; + if (fatClause->GetTryOffset() > 0xFFFF || + fatClause->GetTryLength() > 0xFF || + fatClause->GetHandlerOffset() > 0xFFFF || + fatClause->GetHandlerLength() > 0xFF) { + return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)); + } + } + return smallSize; +} + +/*********************************************************************/ + + // 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) +{ + if (size == 0) + return(0); + + _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned + BYTE* origBuff = outBuff; + if (ehCount <= 0) + return 0; + + // Initialize the ehTypeOffsets array. + if (ehTypeOffsets) + { + for (unsigned int i = 0; i < ehCount; i++) + ehTypeOffsets[i] = (ULONG) -1; + } + + if (COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount) < COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) { + COR_ILMETHOD_SECT_EH_SMALL* EHSect = (COR_ILMETHOD_SECT_EH_SMALL*) outBuff; + unsigned i; + for (i = 0; i < ehCount; i++) { + COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i]; + if (fatClause->GetTryOffset() > 0xFFFF || + fatClause->GetTryLength() > 0xFF || + fatClause->GetHandlerOffset() > 0xFFFF || + fatClause->GetHandlerLength() > 0xFF) { + break; // fall through and generate as FAT + } + _ASSERTE((fatClause->GetFlags() & ~0xFFFF) == 0); + _ASSERTE((fatClause->GetTryOffset() & ~0xFFFF) == 0); + _ASSERTE((fatClause->GetTryLength() & ~0xFF) == 0); + _ASSERTE((fatClause->GetHandlerOffset() & ~0xFFFF) == 0); + _ASSERTE((fatClause->GetHandlerLength() & ~0xFF) == 0); + + COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i]; + smallClause->SetFlags((CorExceptionFlag) fatClause->GetFlags()); + smallClause->SetTryOffset(fatClause->GetTryOffset()); + smallClause->SetTryLength(fatClause->GetTryLength()); + smallClause->SetHandlerOffset(fatClause->GetHandlerOffset()); + smallClause->SetHandlerLength(fatClause->GetHandlerLength()); + smallClause->SetClassToken(fatClause->GetClassToken()); + } + if (i >= ehCount) { + // if actually got through all the clauses and they are small enough + EHSect->Kind = CorILMethod_Sect_EHTable; + if (moreSections) + EHSect->Kind |= CorILMethod_Sect_MoreSects; +#ifndef SOS_INCLUDE + EHSect->DataSize = EHSect->Size(ehCount); +#else + EHSect->DataSize = (BYTE) EHSect->Size(ehCount); +#endif // !SOS_INCLUDE + EHSect->Reserved = 0; + _ASSERTE(EHSect->DataSize == EHSect->Size(ehCount)); // make sure didn't overflow + outBuff = (BYTE*) &EHSect->Clauses[ehCount]; + // Set the offsets for the exception type tokens. + if (ehTypeOffsets) + { + for (i = 0; i < ehCount; i++) { + COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i]; + if (smallClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE) + { + _ASSERTE(! IsNilToken(smallClause->GetClassToken())); + ehTypeOffsets[i] = (ULONG)((BYTE *)&smallClause->ClassToken - origBuff); + } + } + } + return(size); + } + } + // either total size too big or one of constituent elements too big (eg. offset or length) + COR_ILMETHOD_SECT_EH_FAT* EHSect = (COR_ILMETHOD_SECT_EH_FAT*) outBuff; + EHSect->SetKind(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat); + if (moreSections) + EHSect->SetKind(EHSect->GetKind() | CorILMethod_Sect_MoreSects); + + EHSect->SetDataSize(EHSect->Size(ehCount)); + memcpy(EHSect->Clauses, clauses, ehCount * sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT)); + outBuff = (BYTE*) &EHSect->Clauses[ehCount]; + _ASSERTE(&origBuff[size] == outBuff); + // Set the offsets for the exception type tokens. + if (ehTypeOffsets) + { + for (unsigned int i = 0; i < ehCount; i++) { + COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&EHSect->Clauses[i]; + if (fatClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE) + { + _ASSERTE(! IsNilToken(fatClause->GetClassToken())); + ehTypeOffsets[i] = (ULONG)((BYTE *)&fatClause->ClassToken - origBuff); + } + } + } + return(size); +} + +} // extern "C" + + |