1 /*
2   Copyright (C) 2008-2013 Jeroen Frijters
3 
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7 
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11 
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19 
20   Jeroen Frijters
21   jeroen@frijters.net
22 
23 */
24 using System;
25 using System.IO;
26 using System.Collections.Generic;
27 using System.Diagnostics;
28 using System.Text;
29 using IKVM.Reflection.Writer;
30 
31 namespace IKVM.Reflection.Emit
32 {
33 	public sealed class CustomAttributeBuilder
34 	{
35 		internal static readonly ConstructorInfo LegacyPermissionSet = new ConstructorBuilder(null);
36 		private readonly ConstructorInfo con;
37 		private readonly byte[] blob;
38 		private readonly object[] constructorArgs;
39 		private readonly PropertyInfo[] namedProperties;
40 		private readonly object[] propertyValues;
41 		private readonly FieldInfo[] namedFields;
42 		private readonly object[] fieldValues;
43 
CustomAttributeBuilder(ConstructorInfo con, byte[] blob)44 		internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
45 		{
46 			this.con = con;
47 			this.blob = blob;
48 		}
49 
CustomAttributeBuilder(ConstructorInfo con, int securityAction, byte[] blob)50 		private CustomAttributeBuilder(ConstructorInfo con, int securityAction, byte[] blob)
51 		{
52 			this.con = con;
53 			this.blob = blob;
54 			this.constructorArgs = new object[] { securityAction };
55 		}
56 
CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)57 		public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
58 			: this(con, constructorArgs, null, null, null,null)
59 		{
60 		}
61 
CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)62 		public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
63 			: this(con, constructorArgs, null, null, namedFields, fieldValues)
64 		{
65 		}
66 
CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues)67 		public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues)
68 			: this(con, constructorArgs, namedProperties, propertyValues, null, null)
69 		{
70 		}
71 
CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)72 		public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
73 		{
74 			this.con = con;
75 			this.constructorArgs = constructorArgs;
76 			this.namedProperties = namedProperties;
77 			this.propertyValues = propertyValues;
78 			this.namedFields = namedFields;
79 			this.fieldValues = fieldValues;
80 		}
81 
__FromBlob(ConstructorInfo con, byte[] blob)82 		public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, byte[] blob)
83 		{
84 			return new CustomAttributeBuilder(con, blob);
85 		}
86 
__FromBlob(ConstructorInfo con, int securityAction, byte[] blob)87 		public static CustomAttributeBuilder __FromBlob(ConstructorInfo con, int securityAction, byte[] blob)
88 		{
89 			return new CustomAttributeBuilder(con, securityAction, blob);
90 		}
91 
__MakeTypedArgument(Type type, object value)92 		public static CustomAttributeTypedArgument __MakeTypedArgument(Type type, object value)
93 		{
94 			return new CustomAttributeTypedArgument(type, value);
95 		}
96 
97 		private sealed class BlobWriter
98 		{
99 			private readonly Assembly assembly;
100 			private readonly CustomAttributeBuilder cab;
101 			private readonly ByteBuffer bb;
102 
BlobWriter(Assembly assembly, CustomAttributeBuilder cab, ByteBuffer bb)103 			internal BlobWriter(Assembly assembly, CustomAttributeBuilder cab, ByteBuffer bb)
104 			{
105 				this.assembly = assembly;
106 				this.cab = cab;
107 				this.bb = bb;
108 			}
109 
WriteCustomAttributeBlob()110 			internal void WriteCustomAttributeBlob()
111 			{
112 				// prolog
113 				WriteUInt16(1);
114 				ParameterInfo[] pi = cab.con.GetParameters();
115 				for (int i = 0; i < pi.Length; i++)
116 				{
117 					WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
118 				}
119 				WriteNamedArguments(false);
120 			}
121 
WriteNamedArguments(bool forDeclSecurity)122 			internal void WriteNamedArguments(bool forDeclSecurity)
123 			{
124 				// NumNamed
125 				int named = 0;
126 				if (cab.namedFields != null)
127 				{
128 					named += cab.namedFields.Length;
129 				}
130 				if (cab.namedProperties != null)
131 				{
132 					named += cab.namedProperties.Length;
133 				}
134 				if (forDeclSecurity)
135 				{
136 					WritePackedLen(named);
137 				}
138 				else
139 				{
140 					WriteUInt16((ushort)named);
141 				}
142 				if (cab.namedFields != null)
143 				{
144 					for (int i = 0; i < cab.namedFields.Length; i++)
145 					{
146 						WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
147 					}
148 				}
149 				if (cab.namedProperties != null)
150 				{
151 					for (int i = 0; i < cab.namedProperties.Length; i++)
152 					{
153 						WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
154 					}
155 				}
156 			}
157 
WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)158 			private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
159 			{
160 				WriteByte(fieldOrProperty);
161 				WriteFieldOrPropType(type);
162 				WriteString(name);
163 				WriteFixedArg(type, value);
164 			}
165 
WriteByte(byte value)166 			private void WriteByte(byte value)
167 			{
168 				bb.Write(value);
169 			}
170 
WriteUInt16(ushort value)171 			private void WriteUInt16(ushort value)
172 			{
173 				bb.Write(value);
174 			}
175 
WriteInt32(int value)176 			private void WriteInt32(int value)
177 			{
178 				bb.Write(value);
179 			}
180 
WriteFixedArg(Type type, object value)181 			private void WriteFixedArg(Type type, object value)
182 			{
183 				Universe u = assembly.universe;
184 				if (type == u.System_String)
185 				{
186 					WriteString((string)value);
187 				}
188 				else if (type == u.System_Boolean)
189 				{
190 					WriteByte((bool)value ? (byte)1 : (byte)0);
191 				}
192 				else if (type == u.System_Char)
193 				{
194 					WriteUInt16((char)value);
195 				}
196 				else if (type == u.System_SByte)
197 				{
198 					WriteByte((byte)(sbyte)value);
199 				}
200 				else if (type == u.System_Byte)
201 				{
202 					WriteByte((byte)value);
203 				}
204 				else if (type == u.System_Int16)
205 				{
206 					WriteUInt16((ushort)(short)value);
207 				}
208 				else if (type == u.System_UInt16)
209 				{
210 					WriteUInt16((ushort)value);
211 				}
212 				else if (type == u.System_Int32)
213 				{
214 					WriteInt32((int)value);
215 				}
216 				else if (type == u.System_UInt32)
217 				{
218 					WriteInt32((int)(uint)value);
219 				}
220 				else if (type == u.System_Int64)
221 				{
222 					WriteInt64((long)value);
223 				}
224 				else if (type == u.System_UInt64)
225 				{
226 					WriteInt64((long)(ulong)value);
227 				}
228 				else if (type == u.System_Single)
229 				{
230 					WriteSingle((float)value);
231 				}
232 				else if (type == u.System_Double)
233 				{
234 					WriteDouble((double)value);
235 				}
236 				else if (type == u.System_Type)
237 				{
238 					WriteTypeName((Type)value);
239 				}
240 				else if (type == u.System_Object)
241 				{
242 					if (value == null)
243 					{
244 						type = u.System_String;
245 					}
246 					else if (value is Type)
247 					{
248 						// value.GetType() would return a subclass of Type, but we don't want to deal with that
249 						type = u.System_Type;
250 					}
251 					else if (value is CustomAttributeTypedArgument)
252 					{
253 						CustomAttributeTypedArgument cta = (CustomAttributeTypedArgument)value;
254 						value = cta.Value;
255 						type = cta.ArgumentType;
256 					}
257 					else
258 					{
259 						type = u.Import(value.GetType());
260 					}
261 					WriteFieldOrPropType(type);
262 					WriteFixedArg(type, value);
263 				}
264 				else if (type.IsArray)
265 				{
266 					if (value == null)
267 					{
268 						WriteInt32(-1);
269 					}
270 					else
271 					{
272 						Array array = (Array)value;
273 						Type elemType = type.GetElementType();
274 						WriteInt32(array.Length);
275 						foreach (object val in array)
276 						{
277 							WriteFixedArg(elemType, val);
278 						}
279 					}
280 				}
281 				else if (type.IsEnum)
282 				{
283 					WriteFixedArg(type.GetEnumUnderlyingTypeImpl(), value);
284 				}
285 				else
286 				{
287 					throw new ArgumentException();
288 				}
289 			}
290 
WriteInt64(long value)291 			private void WriteInt64(long value)
292 			{
293 				bb.Write(value);
294 			}
295 
WriteSingle(float value)296 			private void WriteSingle(float value)
297 			{
298 				bb.Write(value);
299 			}
300 
WriteDouble(double value)301 			private void WriteDouble(double value)
302 			{
303 				bb.Write(value);
304 			}
305 
WriteTypeName(Type type)306 			private void WriteTypeName(Type type)
307 			{
308 				string name = null;
309 				if (type != null)
310 				{
311 					StringBuilder sb = new StringBuilder();
312 					GetTypeName(sb, type, false);
313 					name = sb.ToString();
314 				}
315 				WriteString(name);
316 			}
317 
GetTypeName(StringBuilder sb, Type type, bool isTypeParam)318 			private void GetTypeName(StringBuilder sb, Type type, bool isTypeParam)
319 			{
320 				bool v1 = !assembly.ManifestModule.__IsMissing && assembly.ManifestModule.MDStreamVersion < 0x20000;
321 				bool includeAssemblyName = type.Assembly != assembly && (!v1 || type.Assembly != type.Module.universe.Mscorlib);
322 				if (isTypeParam && includeAssemblyName)
323 				{
324 					sb.Append('[');
325 				}
326 				GetTypeNameImpl(sb, type);
327 				if (includeAssemblyName)
328 				{
329 					if (v1)
330 					{
331 						sb.Append(',');
332 					}
333 					else
334 					{
335 						sb.Append(", ");
336 					}
337 					if (isTypeParam)
338 					{
339 						sb.Append(type.Assembly.FullName.Replace("]", "\\]")).Append(']');
340 					}
341 					else
342 					{
343 						sb.Append(type.Assembly.FullName);
344 					}
345 				}
346 			}
347 
GetTypeNameImpl(StringBuilder sb, Type type)348 			private void GetTypeNameImpl(StringBuilder sb, Type type)
349 			{
350 				if (type.HasElementType)
351 				{
352 					GetTypeNameImpl(sb, type.GetElementType());
353 					sb.Append(((ElementHolderType)type).GetSuffix());
354 				}
355 				else if (type.IsConstructedGenericType)
356 				{
357 					sb.Append(type.GetGenericTypeDefinition().FullName);
358 					sb.Append('[');
359 					string sep = "";
360 					foreach (Type typeParam in type.GetGenericArguments())
361 					{
362 						sb.Append(sep);
363 						GetTypeName(sb, typeParam, true);
364 						sep = ",";
365 					}
366 					sb.Append(']');
367 				}
368 				else
369 				{
370 					sb.Append(type.FullName);
371 				}
372 			}
373 
WriteString(string val)374 			private void WriteString(string val)
375 			{
376 				bb.Write(val);
377 			}
378 
WritePackedLen(int len)379 			private void WritePackedLen(int len)
380 			{
381 				bb.WriteCompressedUInt(len);
382 			}
383 
WriteFieldOrPropType(Type type)384 			private void WriteFieldOrPropType(Type type)
385 			{
386 				Universe u = type.Module.universe;
387 				if (type == u.System_Type)
388 				{
389 					WriteByte(0x50);
390 				}
391 				else if (type == u.System_Object)
392 				{
393 					WriteByte(0x51);
394 				}
395 				else if (type == u.System_Boolean)
396 				{
397 					WriteByte(0x02);
398 				}
399 				else if (type == u.System_Char)
400 				{
401 					WriteByte(0x03);
402 				}
403 				else if (type == u.System_SByte)
404 				{
405 					WriteByte(0x04);
406 				}
407 				else if (type == u.System_Byte)
408 				{
409 					WriteByte(0x05);
410 				}
411 				else if (type == u.System_Int16)
412 				{
413 					WriteByte(0x06);
414 				}
415 				else if (type == u.System_UInt16)
416 				{
417 					WriteByte(0x07);
418 				}
419 				else if (type == u.System_Int32)
420 				{
421 					WriteByte(0x08);
422 				}
423 				else if (type == u.System_UInt32)
424 				{
425 					WriteByte(0x09);
426 				}
427 				else if (type == u.System_Int64)
428 				{
429 					WriteByte(0x0A);
430 				}
431 				else if (type == u.System_UInt64)
432 				{
433 					WriteByte(0x0B);
434 				}
435 				else if (type == u.System_Single)
436 				{
437 					WriteByte(0x0C);
438 				}
439 				else if (type == u.System_Double)
440 				{
441 					WriteByte(0x0D);
442 				}
443 				else if (type == u.System_String)
444 				{
445 					WriteByte(0x0E);
446 				}
447 				else if (type.IsArray)
448 				{
449 					WriteByte(0x1D);
450 					WriteFieldOrPropType(type.GetElementType());
451 				}
452 				else if (type.IsEnum)
453 				{
454 					WriteByte(0x55);
455 					WriteTypeName(type);
456 				}
457 				else
458 				{
459 					throw new ArgumentException();
460 				}
461 			}
462 		}
463 
464 		internal ConstructorInfo Constructor
465 		{
466 			get { return con; }
467 		}
468 
WriteBlob(ModuleBuilder moduleBuilder)469 		internal int WriteBlob(ModuleBuilder moduleBuilder)
470 		{
471 			ByteBuffer bb;
472 			if (blob != null)
473 			{
474 				bb = ByteBuffer.Wrap(blob);
475 			}
476 			else
477 			{
478 				bb = new ByteBuffer(100);
479 				BlobWriter bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
480 				bw.WriteCustomAttributeBlob();
481 			}
482 			return moduleBuilder.Blobs.Add(bb);
483 		}
484 
GetConstructorArgument(int pos)485 		internal object GetConstructorArgument(int pos)
486 		{
487 			return constructorArgs[pos];
488 		}
489 
490 		internal int ConstructorArgumentCount
491 		{
492 			get { return constructorArgs == null ? 0 : constructorArgs.Length; }
493 		}
494 
495 		internal T? GetFieldValue<T>(string name) where T : struct
496 		{
497 			object val = GetFieldValue(name);
498 			if (val is T)
499 			{
500 				return (T)val;
501 			}
502 			else if (val != null)
503 			{
504 				if (typeof(T).IsEnum)
505 				{
506 					Debug.Assert(Enum.GetUnderlyingType(typeof(T)) == val.GetType());
507 					return (T)Enum.ToObject(typeof(T), val);
508 				}
509 				else
510 				{
511 					Debug.Assert(Enum.GetUnderlyingType(val.GetType()) == typeof(T));
512 					return (T)Convert.ChangeType(val, typeof(T));
513 				}
514 			}
515 			else
516 			{
517 				return null;
518 			}
519 		}
520 
GetFieldValue(string name)521 		internal object GetFieldValue(string name)
522 		{
523 			if (namedFields != null)
524 			{
525 				for (int i = 0; i < namedFields.Length; i++)
526 				{
527 					if (namedFields[i].Name == name)
528 					{
529 						return fieldValues[i];
530 					}
531 				}
532 			}
533 			return null;
534 		}
535 
536 		internal bool IsLegacyDeclSecurity
537 		{
538 			get
539 			{
540 				return ReferenceEquals(con, LegacyPermissionSet)
541 					|| (con.DeclaringType == con.Module.universe.System_Security_Permissions_PermissionSetAttribute
542 						&& blob == null
543 						&& (namedFields == null || namedFields.Length == 0)
544 						&& namedProperties != null
545 						&& namedProperties.Length == 1
546 						&& namedProperties[0].Name == "XML"
547 						&& propertyValues[0] is string);
548 			}
549 		}
550 
WriteLegacyDeclSecurityBlob(ModuleBuilder moduleBuilder)551 		internal int WriteLegacyDeclSecurityBlob(ModuleBuilder moduleBuilder)
552 		{
553 			if (blob != null)
554 			{
555 				return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(blob));
556 			}
557 			else
558 			{
559 				return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(Encoding.Unicode.GetBytes((string)propertyValues[0])));
560 			}
561 		}
562 
WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb)563 		internal void WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb)
564 		{
565 			if (blob != null)
566 			{
567 				bb.Write(blob);
568 			}
569 			else
570 			{
571 				BlobWriter bw = new BlobWriter(moduleBuilder.Assembly, this, bb);
572 				bw.WriteNamedArguments(true);
573 			}
574 		}
575 
ToData(Assembly asm)576 		internal CustomAttributeData ToData(Assembly asm)
577 		{
578 			if (blob != null)
579 			{
580 				if (constructorArgs != null)
581 				{
582 					return new CustomAttributeData(asm, con, (int)constructorArgs[0], blob, -1);
583 				}
584 				return new CustomAttributeData(asm, con, new IKVM.Reflection.Reader.ByteReader(blob, 0, blob.Length));
585 			}
586 			else
587 			{
588 				List<CustomAttributeNamedArgument> namedArgs = new List<CustomAttributeNamedArgument>();
589 				if (namedProperties != null)
590 				{
591 					for (int i = 0; i < namedProperties.Length; i++)
592 					{
593 						namedArgs.Add(new CustomAttributeNamedArgument(namedProperties[i], RewrapValue(namedProperties[i].PropertyType, propertyValues[i])));
594 					}
595 				}
596 				if (namedFields != null)
597 				{
598 					for (int i = 0; i < namedFields.Length; i++)
599 					{
600 						namedArgs.Add(new CustomAttributeNamedArgument(namedFields[i], RewrapValue(namedFields[i].FieldType, fieldValues[i])));
601 					}
602 				}
603 				List<CustomAttributeTypedArgument> args = new List<CustomAttributeTypedArgument>(constructorArgs.Length);
604 				ParameterInfo[] parameters = this.Constructor.GetParameters();
605 				for (int i = 0; i < constructorArgs.Length; i++)
606 				{
607 					args.Add(RewrapValue(parameters[i].ParameterType, constructorArgs[i]));
608 				}
609 				return new CustomAttributeData(asm.ManifestModule, con, args, namedArgs);
610 			}
611 		}
612 
RewrapValue(Type type, object value)613 		private static CustomAttributeTypedArgument RewrapValue(Type type, object value)
614 		{
615 			if (value is Array)
616 			{
617 				Array array = (Array)value;
618 				Type arrayType = type.Module.universe.Import(array.GetType());
619 				return RewrapArray(arrayType, array);
620 			}
621 			else if (value is CustomAttributeTypedArgument)
622 			{
623 				CustomAttributeTypedArgument arg = (CustomAttributeTypedArgument)value;
624 				if (arg.Value is Array)
625 				{
626 					return RewrapArray(arg.ArgumentType, (Array)arg.Value);
627 				}
628 				return arg;
629 			}
630 			else
631 			{
632 				return new CustomAttributeTypedArgument(type, value);
633 			}
634 		}
635 
RewrapArray(Type arrayType, Array array)636 		private static CustomAttributeTypedArgument RewrapArray(Type arrayType, Array array)
637 		{
638 			Type elementType = arrayType.GetElementType();
639 			CustomAttributeTypedArgument[] newArray = new CustomAttributeTypedArgument[array.Length];
640 			for (int i = 0; i < newArray.Length; i++)
641 			{
642 				newArray[i] = RewrapValue(elementType, array.GetValue(i));
643 			}
644 			return new CustomAttributeTypedArgument(arrayType, newArray);
645 		}
646 
647 		internal bool HasBlob
648 		{
649 			get { return blob != null; }
650 		}
651 
DecodeBlob(Assembly asm)652 		internal CustomAttributeBuilder DecodeBlob(Assembly asm)
653 		{
654 			if (blob == null)
655 			{
656 				return this;
657 			}
658 			else
659 			{
660 				return ToData(asm).__ToBuilder();
661 			}
662 		}
663 
GetBlob(Assembly asm)664 		internal byte[] GetBlob(Assembly asm)
665 		{
666 			ByteBuffer bb = new ByteBuffer(100);
667 			BlobWriter bw = new BlobWriter(asm, this, bb);
668 			bw.WriteCustomAttributeBlob();
669 			return bb.ToArray();
670 		}
671 
672 		internal KnownCA KnownCA
673 		{
674 			get
675 			{
676 				TypeName typeName = con.DeclaringType.TypeName;
677 				switch (typeName.Namespace)
678 				{
679 					case "System":
680 						switch (typeName.Name)
681 						{
682 							case "SerializableAttribute":
683 								return KnownCA.SerializableAttribute;
684 							case "NonSerializedAttribute":
685 								return KnownCA.NonSerializedAttribute;
686 						}
687 						break;
688 					case "System.Runtime.CompilerServices":
689 						switch (typeName.Name)
690 						{
691 							case "MethodImplAttribute":
692 								return KnownCA.MethodImplAttribute;
693 							case "SpecialNameAttribute":
694 								return KnownCA.SpecialNameAttribute;
695 						}
696 						break;
697 					case "System.Runtime.InteropServices":
698 						switch (typeName.Name)
699 						{
700 							case "DllImportAttribute":
701 								return KnownCA.DllImportAttribute;
702 							case "ComImportAttribute":
703 								return KnownCA.ComImportAttribute;
704 							case "MarshalAsAttribute":
705 								return KnownCA.MarshalAsAttribute;
706 							case "PreserveSigAttribute":
707 								return KnownCA.PreserveSigAttribute;
708 							case "InAttribute":
709 								return KnownCA.InAttribute;
710 							case "OutAttribute":
711 								return KnownCA.OutAttribute;
712 							case "OptionalAttribute":
713 								return KnownCA.OptionalAttribute;
714 							case "StructLayoutAttribute":
715 								return KnownCA.StructLayoutAttribute;
716 							case "FieldOffsetAttribute":
717 								return KnownCA.FieldOffsetAttribute;
718 						}
719 						break;
720 				}
721 				if (typeName.Matches("System.Security.SuppressUnmanagedCodeSecurityAttribute"))
722 				{
723 					return KnownCA.SuppressUnmanagedCodeSecurityAttribute;
724 				}
725 				return KnownCA.Unknown;
726 			}
727 		}
728 	}
729 
730 	// These are the pseudo-custom attributes that are recognized by name by the runtime (i.e. the type identity is not considered).
731 	// The corresponding list in the runtime is at https://github.com/dotnet/coreclr/blob/1afe5ce4f45045d724a4e129df4b816655d486fb/src/md/compiler/custattr_emit.cpp#L38
732 	// Note that we only need to handle a subset of the types, since we don't need the ones that are only used for validation by the runtime.
733 	enum KnownCA
734 	{
735 		Unknown,
736 		DllImportAttribute,
737 		ComImportAttribute,
738 		SerializableAttribute,
739 		NonSerializedAttribute,
740 		MethodImplAttribute,
741 		MarshalAsAttribute,
742 		PreserveSigAttribute,
743 		InAttribute,
744 		OutAttribute,
745 		OptionalAttribute,
746 		StructLayoutAttribute,
747 		FieldOffsetAttribute,
748 		SpecialNameAttribute,
749 		// the following is not part of the runtime known custom attributes, but we handle it here for efficiency and convenience
750 		SuppressUnmanagedCodeSecurityAttribute,
751 	}
752 }
753