1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/****************************************************************************
6 ** **
7 ** Corhlpr.h - signature helpers. **
8 ** **
9 ****************************************************************************/
10#ifndef SOS_INCLUDE
11
12#ifdef _BLD_CLR
13#include "utilcode.h"
14#endif
15#include "corhlpr.h"
16#include <stdlib.h>
17
18#endif // !SOS_INCLUDE
19
20
21//*****************************************************************************
22//
23//***** File format helper classes
24//
25//*****************************************************************************
26
27extern "C" {
28
29/***************************************************************************/
30/* Note that this construtor does not set the LocalSig, but has the
31 advantage that it does not have any dependancy on EE structures.
32 inside the EE use the FunctionDesc constructor */
33
34void __stdcall DecoderInit(void *pThis, COR_ILMETHOD *header)
35{
36 COR_ILMETHOD_DECODER *decoder = (COR_ILMETHOD_DECODER *)pThis;
37
38 memset(decoder, 0, sizeof(COR_ILMETHOD_DECODER));
39 if (header->Tiny.IsTiny())
40 {
41 decoder->SetMaxStack(header->Tiny.GetMaxStack());
42 decoder->Code = header->Tiny.GetCode();
43 decoder->SetCodeSize(header->Tiny.GetCodeSize());
44 decoder->SetFlags(CorILMethod_TinyFormat);
45 return;
46 }
47 if (header->Fat.IsFat())
48 {
49#ifdef _WIN64
50 if((((size_t) header) & 3) == 0) // header is aligned
51#else
52 _ASSERTE((((size_t) header) & 3) == 0); // header is aligned
53#endif
54 {
55 *((COR_ILMETHOD_FAT *)decoder) = header->Fat;
56 decoder->Code = header->Fat.GetCode();
57 if (header->Fat.GetSize() >= (sizeof(COR_ILMETHOD_FAT) / 4)) // Size if valid
58 {
59 decoder->Sect = header->Fat.GetSect();
60 if ((decoder->Sect != NULL) && (decoder->Sect->Kind() == CorILMethod_Sect_EHTable))
61 {
62 decoder->EH = (COR_ILMETHOD_SECT_EH *)decoder->Sect;
63 decoder->Sect = decoder->Sect->Next();
64 }
65 }
66 }
67 return;
68 }
69} // DecoderInit
70
71// Calculate the total method size. First get address of end of code. If there are no sections, then
72// the end of code addr marks end of COR_ILMETHOD. Otherwise find addr of end of last section and use it
73// to mark end of COR_ILMETHOD. Assumes that the code is directly followed
74// by each section in the on-disk format
75int __stdcall DecoderGetOnDiskSize(void * pThis, COR_ILMETHOD* header)
76{
77 COR_ILMETHOD_DECODER* decoder = (COR_ILMETHOD_DECODER*)pThis;
78
79 if (decoder->Code == NULL)
80 return 0;
81
82 BYTE *lastAddr = (BYTE*)decoder->Code + decoder->GetCodeSize(); // addr of end of code
83 const COR_ILMETHOD_SECT *sect = decoder->EH;
84 if (sect != 0 && sect->Next() == 0)
85 {
86 lastAddr = (BYTE *)sect + sect->DataSize();
87 }
88 else
89 {
90 const COR_ILMETHOD_SECT *nextSect;
91 for (sect = decoder->Sect; sect; sect = nextSect)
92 {
93 nextSect = sect->Next();
94 if (nextSect == 0)
95 {
96 // sect points to the last section, so set lastAddr
97 lastAddr = (BYTE *)sect + sect->DataSize();
98 break;
99 }
100 }
101 }
102 return (int)(lastAddr - (BYTE*)header);
103}
104
105/*********************************************************************/
106/* APIs for emitting sections etc */
107
108unsigned __stdcall IlmethodSize(COR_ILMETHOD_FAT* header, BOOL moreSections)
109{
110 if (header->GetMaxStack() <= 8 && (header->GetFlags() & ~CorILMethod_FormatMask) == 0
111 && header->GetLocalVarSigTok() == 0 && header->GetCodeSize() < 64 && !moreSections)
112 return(sizeof(COR_ILMETHOD_TINY));
113
114 return(sizeof(COR_ILMETHOD_FAT));
115}
116
117/*********************************************************************/
118 // emit the header (bestFormat) return amount emitted
119unsigned __stdcall IlmethodEmit(unsigned size, COR_ILMETHOD_FAT* header,
120 BOOL moreSections, BYTE* outBuff)
121{
122#ifndef SOS_INCLUDE
123#ifdef _DEBUG
124 BYTE* origBuff = outBuff;
125#endif
126#endif // !SOS_INCLUDE
127 if (size == 1) {
128 // Tiny format
129 *outBuff++ = (BYTE) (CorILMethod_TinyFormat | (header->GetCodeSize() << 2));
130 }
131 else {
132 // Fat format
133 _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned
134 COR_ILMETHOD_FAT* fatHeader = (COR_ILMETHOD_FAT*) outBuff;
135 outBuff += sizeof(COR_ILMETHOD_FAT);
136 *fatHeader = *header;
137 fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_FatFormat);
138 _ASSERTE((fatHeader->GetFlags() & CorILMethod_FormatMask) == CorILMethod_FatFormat);
139 if (moreSections)
140 fatHeader->SetFlags(fatHeader->GetFlags() | CorILMethod_MoreSects);
141 fatHeader->SetSize(sizeof(COR_ILMETHOD_FAT) / 4);
142 }
143#ifndef SOS_INCLUDE
144 _ASSERTE(&origBuff[size] == outBuff);
145#endif // !SOS_INCLUDE
146 return(size);
147}
148
149/*********************************************************************/
150/* static */
151IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* __stdcall SectEH_EHClause(void *pSectEH, unsigned idx, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* buff)
152{
153 if (((COR_ILMETHOD_SECT_EH *)pSectEH)->IsFat())
154 return(&(((COR_ILMETHOD_SECT_EH *)pSectEH)->Fat.Clauses[idx]));
155
156 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)buff;
157 COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&((COR_ILMETHOD_SECT_EH *)pSectEH)->Small.Clauses[idx];
158
159 // mask to remove sign extension - cast just wouldn't work
160 fatClause->SetFlags((CorExceptionFlag)(smallClause->GetFlags()&0x0000ffff));
161 fatClause->SetClassToken(smallClause->GetClassToken());
162 fatClause->SetTryOffset(smallClause->GetTryOffset());
163 fatClause->SetTryLength(smallClause->GetTryLength());
164 fatClause->SetHandlerLength(smallClause->GetHandlerLength());
165 fatClause->SetHandlerOffset(smallClause->GetHandlerOffset());
166 return(buff);
167}
168/*********************************************************************/
169 // compute the size of the section (best format)
170 // codeSize is the size of the method
171 // deprecated
172unsigned __stdcall SectEH_SizeWithCode(unsigned ehCount, unsigned codeSize)
173{
174 return((ehCount)? SectEH_SizeWorst(ehCount) : 0);
175}
176
177 // will return worse-case size and then Emit will return actual size
178unsigned __stdcall SectEH_SizeWorst(unsigned ehCount)
179{
180 return((ehCount)? (COR_ILMETHOD_SECT_EH_FAT::Size(ehCount)) : 0);
181}
182
183 // will return exact size which will match the size returned by Emit
184unsigned __stdcall SectEH_SizeExact(unsigned ehCount, IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses)
185{
186 if (ehCount == 0)
187 return(0);
188
189 unsigned smallSize = COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount);
190 if (smallSize > COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE)
191 return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount));
192 for (unsigned i = 0; i < ehCount; i++) {
193 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i];
194 if (fatClause->GetTryOffset() > 0xFFFF ||
195 fatClause->GetTryLength() > 0xFF ||
196 fatClause->GetHandlerOffset() > 0xFFFF ||
197 fatClause->GetHandlerLength() > 0xFF) {
198 return(COR_ILMETHOD_SECT_EH_FAT::Size(ehCount));
199 }
200 }
201 return smallSize;
202}
203
204/*********************************************************************/
205
206 // emit the section (best format);
207unsigned __stdcall SectEH_Emit(unsigned size, unsigned ehCount,
208 IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clauses,
209 BOOL moreSections, BYTE* outBuff,
210 ULONG* ehTypeOffsets)
211{
212 if (size == 0)
213 return(0);
214
215 _ASSERTE((((size_t) outBuff) & 3) == 0); // header is dword aligned
216 BYTE* origBuff = outBuff;
217 if (ehCount <= 0)
218 return 0;
219
220 // Initialize the ehTypeOffsets array.
221 if (ehTypeOffsets)
222 {
223 for (unsigned int i = 0; i < ehCount; i++)
224 ehTypeOffsets[i] = (ULONG) -1;
225 }
226
227 if (COR_ILMETHOD_SECT_EH_SMALL::Size(ehCount) < COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE) {
228 COR_ILMETHOD_SECT_EH_SMALL* EHSect = (COR_ILMETHOD_SECT_EH_SMALL*) outBuff;
229 unsigned i;
230 for (i = 0; i < ehCount; i++) {
231 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&clauses[i];
232 if (fatClause->GetTryOffset() > 0xFFFF ||
233 fatClause->GetTryLength() > 0xFF ||
234 fatClause->GetHandlerOffset() > 0xFFFF ||
235 fatClause->GetHandlerLength() > 0xFF) {
236 break; // fall through and generate as FAT
237 }
238 _ASSERTE((fatClause->GetFlags() & ~0xFFFF) == 0);
239 _ASSERTE((fatClause->GetTryOffset() & ~0xFFFF) == 0);
240 _ASSERTE((fatClause->GetTryLength() & ~0xFF) == 0);
241 _ASSERTE((fatClause->GetHandlerOffset() & ~0xFFFF) == 0);
242 _ASSERTE((fatClause->GetHandlerLength() & ~0xFF) == 0);
243
244 COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i];
245 smallClause->SetFlags((CorExceptionFlag) fatClause->GetFlags());
246 smallClause->SetTryOffset(fatClause->GetTryOffset());
247 smallClause->SetTryLength(fatClause->GetTryLength());
248 smallClause->SetHandlerOffset(fatClause->GetHandlerOffset());
249 smallClause->SetHandlerLength(fatClause->GetHandlerLength());
250 smallClause->SetClassToken(fatClause->GetClassToken());
251 }
252 if (i >= ehCount) {
253 // if actually got through all the clauses and they are small enough
254 EHSect->Kind = CorILMethod_Sect_EHTable;
255 if (moreSections)
256 EHSect->Kind |= CorILMethod_Sect_MoreSects;
257#ifndef SOS_INCLUDE
258 EHSect->DataSize = EHSect->Size(ehCount);
259#else
260 EHSect->DataSize = (BYTE) EHSect->Size(ehCount);
261#endif // !SOS_INCLUDE
262 EHSect->Reserved = 0;
263 _ASSERTE(EHSect->DataSize == EHSect->Size(ehCount)); // make sure didn't overflow
264 outBuff = (BYTE*) &EHSect->Clauses[ehCount];
265 // Set the offsets for the exception type tokens.
266 if (ehTypeOffsets)
267 {
268 for (i = 0; i < ehCount; i++) {
269 COR_ILMETHOD_SECT_EH_CLAUSE_SMALL* smallClause = (COR_ILMETHOD_SECT_EH_CLAUSE_SMALL*)&EHSect->Clauses[i];
270 if (smallClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE)
271 {
272 _ASSERTE(! IsNilToken(smallClause->GetClassToken()));
273 ehTypeOffsets[i] = (ULONG)((BYTE *)&smallClause->ClassToken - origBuff);
274 }
275 }
276 }
277 return(size);
278 }
279 }
280 // either total size too big or one of constituent elements too big (eg. offset or length)
281 COR_ILMETHOD_SECT_EH_FAT* EHSect = (COR_ILMETHOD_SECT_EH_FAT*) outBuff;
282 EHSect->SetKind(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
283 if (moreSections)
284 EHSect->SetKind(EHSect->GetKind() | CorILMethod_Sect_MoreSects);
285
286 EHSect->SetDataSize(EHSect->Size(ehCount));
287 memcpy(EHSect->Clauses, clauses, ehCount * sizeof(COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
288 outBuff = (BYTE*) &EHSect->Clauses[ehCount];
289 _ASSERTE(&origBuff[size] == outBuff);
290 // Set the offsets for the exception type tokens.
291 if (ehTypeOffsets)
292 {
293 for (unsigned int i = 0; i < ehCount; i++) {
294 COR_ILMETHOD_SECT_EH_CLAUSE_FAT* fatClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)&EHSect->Clauses[i];
295 if (fatClause->GetFlags() == COR_ILEXCEPTION_CLAUSE_NONE)
296 {
297 _ASSERTE(! IsNilToken(fatClause->GetClassToken()));
298 ehTypeOffsets[i] = (ULONG)((BYTE *)&fatClause->ClassToken - origBuff);
299 }
300 }
301 }
302 return(size);
303}
304
305} // extern "C"
306
307
308