CSComponentInspector.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System.Collections.Immutable;
  3. //using Roslyn.Utilities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.Text;
  9. using System.Reflection.Emit;
  10. using System.Reflection;
  11. using System.Reflection.Metadata;
  12. using System.Reflection.Metadata.Ecma335;
  13. using System.Reflection.PortableExecutable;
  14. //https://github.com/Microsoft/dotnetsamples/tree/master/System.Reflection.Metadata
  15. //https://github.com/dotnet/corefx/tree/master/src/System.Reflection.Metadata/tests
  16. //http://www.cnetion.com/getting-field-values-using-mono-cecil-qq-AUvBjRFgivICeoL1jxJy.php
  17. // https://github.com/Reactive-Extensions/IL2JS/blob/master/CCI2/PeReader/ILReader.cs
  18. // https://github.com/Reactive-Extensions/IL2JS
  19. // custom attr loading: https://github.com/Reactive-Extensions/IL2JS/blob/a4570f9c69b6c40d001e7539b952266d67609ca9/CST/PELoader.cs#L2352
  20. // custom attr: https://www.simple-talk.com/blogs/2011/06/03/anatomy-of-a-net-assembly-custom-attribute-encoding/
  21. // custom attr: https://github.com/jbevain/cecil/blob/67a2569688a13a6cb487f9af5c3418f7a8f43e3c/Mono.Cecil/AssemblyReader.cs
  22. // https://github.com/dotnet/roslyn/tree/master/src/Compilers/Core/Portable/MetadataReader
  23. namespace AtomicEditor
  24. {
  25. public class InspectorField
  26. {
  27. public string TypeName;
  28. // the Name of the InspectorField
  29. public string Name;
  30. // The DefaultValue if supplied
  31. public string DefaultValue;
  32. // custom attributes, positional and named
  33. public List<string> CustomAttrPositionalArgs = new List<string> ();
  34. public Dictionary<string, string> CustomAttrNamedArgs = new Dictionary<string, string> ();
  35. }
  36. public class CSComponentInspector
  37. {
  38. public Dictionary<string, InspectorField> InspectorFields = new Dictionary<string, InspectorField> ();
  39. public CSComponentInspector (TypeDefinition typeDef, PEReader peFile, MetadataReader metaReader)
  40. {
  41. this.typeDef = typeDef;
  42. this.peFile = peFile;
  43. this.metaReader = metaReader;
  44. }
  45. public void Dump ()
  46. {
  47. foreach (var entry in InspectorFields) {
  48. var field = entry.Value;
  49. Console.WriteLine ("Inspector Field: {0}", field.Name);
  50. Console.WriteLine (" Type Name: {0}", field.TypeName);
  51. Console.WriteLine (" Default Value: {0}", field.DefaultValue);
  52. Console.WriteLine (" Positional Custom Attr:");
  53. foreach (var p in field.CustomAttrPositionalArgs)
  54. if (p.Length != 0)
  55. Console.WriteLine (" {0}", p);
  56. Console.WriteLine (" Named Custom Attr:");
  57. foreach (var nentry in field.CustomAttrNamedArgs)
  58. Console.WriteLine (" {0}:{1}", nentry.Key, nentry.Value);
  59. }
  60. }
  61. public bool Inspect ()
  62. {
  63. var fields = typeDef.GetFields ();
  64. foreach (var fieldHandle in fields) {
  65. var inspectorField = new InspectorField ();
  66. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  67. var customAttr = fieldDef.GetCustomAttributes ();
  68. foreach (var caHandle in customAttr) {
  69. // Look for InspectorAttribute
  70. if (DecodeCustomAttribute (caHandle, inspectorField)) {
  71. BlobReader sigReader = metaReader.GetBlobReader (fieldDef.Signature);
  72. SignatureHeader header = sigReader.ReadSignatureHeader ();
  73. if (header.Kind != SignatureKind.Field)
  74. continue;
  75. var typeCode = sigReader.ReadSignatureTypeCode ();
  76. string typeName = typeCode.ToString ();
  77. if (typeCode == SignatureTypeCode.TypeHandle) {
  78. EntityHandle token = sigReader.ReadTypeHandle ();
  79. HandleKind tokenType = token.Kind;
  80. if (tokenType == HandleKind.TypeDefinition) {
  81. // can store local enum typedefs
  82. // enum initializers are stored as constant value in the IL
  83. var typeDef = metaReader.GetTypeDefinition ((TypeDefinitionHandle)token);
  84. var baseTypeToken = typeDef.BaseType;
  85. if (baseTypeToken.Kind != HandleKind.TypeReference)
  86. continue;
  87. var baseTypeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeToken);
  88. if (metaReader.GetString (baseTypeRef.Name) != "Enum")
  89. continue;
  90. Console.WriteLine ("Enum TypeDef {0}", metaReader.GetString (typeDef.Name));
  91. } else if (tokenType == HandleKind.TypeReference) {
  92. // TypeReference, ok
  93. var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)token);
  94. typeName = metaReader.GetString (typeRef.Name);
  95. } else {
  96. // ???
  97. continue;
  98. }
  99. }
  100. inspectorField.TypeName = typeName;
  101. inspectorField.Name = metaReader.GetString (fieldDef.Name);
  102. InspectorFields [inspectorField.Name] = inspectorField;
  103. break;
  104. }
  105. }
  106. }
  107. // There is no way to get the initializer value of a field
  108. // other than to inspect the IL code of the constructor
  109. var methods = typeDef.GetMethods ();
  110. foreach (var methodHandle in methods) {
  111. var methodDef = metaReader.GetMethodDefinition (methodHandle);
  112. if (metaReader.GetString (methodDef.Name) == ".ctor") {
  113. var body = peFile.GetMethodBody (methodDef.RelativeVirtualAddress);
  114. var ilBytes = body.GetILContent ();
  115. InspectILBlock (ilBytes, ilBytes.Length);
  116. }
  117. }
  118. Dump ();
  119. return true;
  120. }
  121. private bool DecodeCustomAttribute (CustomAttributeHandle caHandle, InspectorField inspectorField)
  122. {
  123. // GetCustomAttribute: https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1370
  124. // Custom Attribute
  125. var ca = metaReader.GetCustomAttribute (caHandle);
  126. // MethodDefinitionHandle or MemberReferenceHandle
  127. if (ca.Constructor.Kind != HandleKind.MemberReference) {
  128. Console.WriteLine ("ca.Constructor.Kind != HandleKind.MemberReference");
  129. return false;
  130. }
  131. // constructor of the custom attr which contains the signature
  132. var memberRef = metaReader.GetMemberReference ((MemberReferenceHandle)ca.Constructor);
  133. // parent of the constructor is the TypeReference
  134. var parent = memberRef.Parent;
  135. if (parent.Kind != HandleKind.TypeReference) {
  136. Console.WriteLine ("parent.Kind != HandleKind.TypeReference");
  137. return false;
  138. }
  139. var parentTypeRef = metaReader.GetTypeReference ((TypeReferenceHandle)parent);
  140. // check whether we have an InspectorAttribute
  141. if (metaReader.GetString (parentTypeRef.Name) != "InspectorAttribute") {
  142. Console.WriteLine ("parentTypeRef != InspectorAttribute");
  143. return false;
  144. }
  145. // args
  146. var argsReader = metaReader.GetBlobReader ((BlobHandle)ca.Value);
  147. uint prolog = argsReader.ReadUInt16 ();
  148. if (prolog != 1) {
  149. Console.WriteLine ("prolog != 1");
  150. return false;
  151. }
  152. // sig reader is on constructor
  153. BlobReader sigReader = metaReader.GetBlobReader (memberRef.Signature);
  154. SignatureHeader header = sigReader.ReadSignatureHeader ();
  155. // Get the type parameter count.
  156. if (header.IsGeneric && sigReader.ReadCompressedInteger () != 0) {
  157. Console.WriteLine ("header.IsGeneric && sigReader.ReadCompressedInteger() != 0");
  158. return false;
  159. }
  160. // Get the parameter count
  161. int paramCount = sigReader.ReadCompressedInteger ();
  162. // Get the type return type.
  163. var returnTypeCode = sigReader.ReadSignatureTypeCode ();
  164. if (returnTypeCode != SignatureTypeCode.Void) {
  165. Console.WriteLine ("returnTypeCode != SignatureTypeCode.Void");
  166. return false;
  167. }
  168. List<SignatureTypeCode> sigTypeCodes = new List<SignatureTypeCode> ();
  169. // position args
  170. for (int i = 0; i < paramCount; i++) {
  171. SignatureTypeCode paramTypeCode = sigReader.ReadSignatureTypeCode ();
  172. // support string custom attr for now to simplify things
  173. if (paramTypeCode != SignatureTypeCode.String)
  174. return false;
  175. string value;
  176. if (CrackStringInAttributeValue (out value, ref argsReader)) {
  177. inspectorField.CustomAttrPositionalArgs.Add (value);
  178. }
  179. sigTypeCodes.Add (paramTypeCode);
  180. }
  181. // named args
  182. short namedParamCount = argsReader.ReadInt16 ();
  183. for (short i = 0; i < namedParamCount; i++) {
  184. // Ecma-335 23.3 - A NamedArg is simply a FixedArg preceded by information to identify which field or
  185. // property it represents. [Note: Recall that the CLI allows fields and properties to have the same name; so
  186. // we require a means to disambiguate such situations. end note] FIELD is the single byte 0x53. PROPERTY is
  187. // the single byte 0x54.
  188. // https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1305
  189. var kind = (CustomAttributeNamedArgumentKind)argsReader.ReadCompressedInteger ();
  190. if (kind != CustomAttributeNamedArgumentKind.Field && kind != CustomAttributeNamedArgumentKind.Property) {
  191. return false;
  192. }
  193. var typeCode = argsReader.ReadSerializationTypeCode ();
  194. // support string custom attr for now to simplify things
  195. if (typeCode != SerializationTypeCode.String)
  196. return false;
  197. string name;
  198. if (!CrackStringInAttributeValue (out name, ref argsReader))
  199. return false;
  200. string value;
  201. if (!CrackStringInAttributeValue (out value, ref argsReader))
  202. return false;
  203. inspectorField.CustomAttrNamedArgs [name] = value;
  204. }
  205. return true;
  206. }
  207. internal static bool CrackStringInAttributeValue (out string value, ref BlobReader sig)
  208. {
  209. try {
  210. int strLen;
  211. if (sig.TryReadCompressedInteger (out strLen) && sig.RemainingBytes >= strLen) {
  212. value = sig.ReadUTF8 (strLen);
  213. // Trim null characters at the end to mimic native compiler behavior.
  214. // There are libraries that have them and leaving them in breaks tests.
  215. value = value.TrimEnd ('\0');
  216. return true;
  217. }
  218. value = null;
  219. // Strings are stored as UTF8, but 0xFF means NULL string.
  220. return sig.RemainingBytes >= 1 && sig.ReadByte () == 0xFF;
  221. } catch (BadImageFormatException) {
  222. value = null;
  223. return false;
  224. }
  225. }
  226. public void InspectILBlock (
  227. ImmutableArray<byte> ilBytes,
  228. int length,
  229. IReadOnlyList<HandlerSpan> spans = null,
  230. int blockOffset = 0,
  231. IReadOnlyDictionary<int, string> markers = null)
  232. {
  233. if (ilBytes == null) {
  234. return;
  235. }
  236. int spanIndex = 0;
  237. int curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, 0, spanIndex, markers, out spanIndex);
  238. }
  239. private int InspectILBlock (
  240. ImmutableArray<byte> ilBytes,
  241. int length,
  242. IReadOnlyList<HandlerSpan> spans,
  243. int blockOffset,
  244. int curIndex,
  245. int spanIndex,
  246. IReadOnlyDictionary<int, string> markers,
  247. out int nextSpanIndex)
  248. {
  249. int lastSpanIndex = spanIndex - 1;
  250. List<string> loadedValues = new List<string> ();
  251. while (curIndex < length) {
  252. if (lastSpanIndex > 0 && StartsFilterHandler (spans, lastSpanIndex, curIndex + blockOffset)) {
  253. }
  254. if (StartsSpan (spans, spanIndex, curIndex + blockOffset)) {
  255. curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, curIndex, spanIndex + 1, markers, out spanIndex);
  256. } else {
  257. int ilOffset = curIndex + blockOffset;
  258. string marker;
  259. if (markers != null && markers.TryGetValue (ilOffset, out marker)) {
  260. } else {
  261. }
  262. OpCode opCode;
  263. int expectedSize;
  264. byte op1 = ilBytes [curIndex++];
  265. if (op1 == 0xfe && curIndex < length) {
  266. byte op2 = ilBytes [curIndex++];
  267. opCode = s_twoByteOpCodes [op2];
  268. expectedSize = 2;
  269. } else {
  270. opCode = s_oneByteOpCodes [op1];
  271. expectedSize = 1;
  272. }
  273. if (opCode.Size != expectedSize) {
  274. //sb.AppendLine(string.Format(" <unknown 0x{0}{1:X2}>", expectedSize == 2 ? "fe" : "", op1));
  275. continue;
  276. }
  277. //sb.Append(" ");
  278. // Console.WriteLine (opCode.OperandType == OperandType.InlineNone ? "{0} {1}" : "{0,-10} {1}", opCode, opCode.OperandType);
  279. switch (opCode.OperandType) {
  280. case OperandType.InlineField:
  281. // read token
  282. uint fieldToken = ReadUInt32 (ilBytes, ref curIndex);
  283. // get the kind
  284. uint tokenKind = fieldToken & TokenTypeIds.TokenTypeMask;
  285. // and the rowId
  286. uint rowId = fieldToken & TokenTypeIds.RIDMask;
  287. var fieldHandle = MetadataTokens.FieldDefinitionHandle ((int)rowId);
  288. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  289. var fieldName = metaReader.GetString (fieldDef.Name);
  290. if (opCode.ToString () == "stfld") {
  291. InspectorField inspectorField;
  292. if (InspectorFields.TryGetValue (fieldName, out inspectorField)) {
  293. inspectorField.DefaultValue = String.Join (" ", loadedValues.ToArray ());
  294. }
  295. }
  296. loadedValues.Clear ();
  297. break;
  298. case OperandType.InlineMethod:
  299. // new Vector3, etc
  300. if (opCode.ToString () == "newobj") {
  301. } else
  302. loadedValues.Clear ();
  303. break;
  304. case OperandType.InlineTok:
  305. case OperandType.InlineType:
  306. ReadUInt32 (ilBytes, ref curIndex);
  307. loadedValues.Clear ();
  308. break;
  309. case OperandType.InlineSig: // signature (calli), not emitted by C#/VB
  310. ReadUInt32 (ilBytes, ref curIndex);
  311. loadedValues.Clear ();
  312. break;
  313. case OperandType.InlineString:
  314. //sb.Append(" 391 ");
  315. //sb.Append(VisualizeUserString());
  316. uint stringToken = ReadUInt32 (ilBytes, ref curIndex);
  317. // get the kind
  318. //uint tokenKind = stringToken & TokenTypeIds.TokenTypeMask;
  319. // and the rowId
  320. //uint rowId = stringToken & TokenTypeIds.RIDMask;
  321. UserStringHandle handle = MetadataTokens.UserStringHandle ((int)stringToken);
  322. loadedValues.Add (metaReader.GetUserString (handle));
  323. break;
  324. case OperandType.InlineNone:
  325. if (opCode == OpCodes.Ldc_I4_0)
  326. loadedValues.Add ("0");
  327. else if (opCode == OpCodes.Ldc_I4_1)
  328. loadedValues.Add ("1");
  329. else if (opCode == OpCodes.Ldc_I4_2)
  330. loadedValues.Add ("2");
  331. else if (opCode == OpCodes.Ldc_I4_3)
  332. loadedValues.Add ("3");
  333. else if (opCode == OpCodes.Ldc_I4_4)
  334. loadedValues.Add ("4");
  335. else if (opCode == OpCodes.Ldc_I4_5)
  336. loadedValues.Add ("5");
  337. else if (opCode == OpCodes.Ldc_I4_6)
  338. loadedValues.Add ("6");
  339. else if (opCode == OpCodes.Ldc_I4_7)
  340. loadedValues.Add ("7");
  341. else if (opCode == OpCodes.Ldc_I4_8)
  342. loadedValues.Add ("8");
  343. else if (opCode == OpCodes.Ldc_I4_M1)
  344. loadedValues.Add ("-1");
  345. break;
  346. case OperandType.ShortInlineI:
  347. loadedValues.Add (ReadSByte (ilBytes, ref curIndex).ToString ());
  348. break;
  349. case OperandType.ShortInlineVar:
  350. loadedValues.Add (ReadByte (ilBytes, ref curIndex).ToString ());
  351. break;
  352. case OperandType.InlineVar:
  353. loadedValues.Add (ReadUInt16 (ilBytes, ref curIndex).ToString ());
  354. break;
  355. case OperandType.InlineI:
  356. loadedValues.Add (ReadUInt32 (ilBytes, ref curIndex).ToString ());
  357. break;
  358. case OperandType.InlineI8:
  359. loadedValues.Add (ReadUInt64 (ilBytes, ref curIndex).ToString ());
  360. break;
  361. case OperandType.ShortInlineR:
  362. {
  363. loadedValues.Add (ReadSingle (ilBytes, ref curIndex).ToString ());
  364. }
  365. break;
  366. case OperandType.InlineR:
  367. {
  368. loadedValues.Add (ReadDouble (ilBytes, ref curIndex).ToString ());
  369. }
  370. break;
  371. case OperandType.ShortInlineBrTarget:
  372. loadedValues.Clear ();
  373. var sbyteValue = ReadSByte (ilBytes, ref curIndex) + curIndex + blockOffset;
  374. break;
  375. case OperandType.InlineBrTarget:
  376. loadedValues.Clear ();
  377. var int32value = ReadInt32 (ilBytes, ref curIndex) + curIndex + blockOffset;
  378. break;
  379. case OperandType.InlineSwitch:
  380. loadedValues.Clear ();
  381. int labelCount = ReadInt32 (ilBytes, ref curIndex);
  382. int instrEnd = curIndex + labelCount * 4;
  383. for (int i = 0; i < labelCount; i++) {
  384. var int32LabelValue = ReadInt32 (ilBytes, ref curIndex) + instrEnd + blockOffset;
  385. //sb.AppendLine((i == labelCount - 1) ? ")" : ",");
  386. }
  387. break;
  388. default:
  389. throw new InvalidOperationException ();
  390. //throw ExceptionUtilities.UnexpectedValue(opCode.OperandType);
  391. }
  392. //sb.AppendLine();
  393. }
  394. if (EndsSpan (spans, lastSpanIndex, curIndex + blockOffset)) {
  395. break;
  396. }
  397. }
  398. nextSpanIndex = spanIndex;
  399. return curIndex;
  400. }
  401. TypeDefinition typeDef;
  402. PEReader peFile;
  403. MetadataReader metaReader;
  404. private static readonly OpCode[] s_oneByteOpCodes;
  405. private static readonly OpCode[] s_twoByteOpCodes;
  406. static CSComponentInspector ()
  407. {
  408. s_oneByteOpCodes = new OpCode[0x100];
  409. s_twoByteOpCodes = new OpCode[0x100];
  410. var typeOfOpCode = typeof(OpCode);
  411. foreach (FieldInfo fi in typeof(OpCodes).GetTypeInfo().DeclaredFields) {
  412. if (fi.FieldType != typeOfOpCode) {
  413. continue;
  414. }
  415. OpCode opCode = (OpCode)fi.GetValue (null);
  416. var value = unchecked((ushort)opCode.Value);
  417. if (value < 0x100) {
  418. s_oneByteOpCodes [value] = opCode;
  419. } else if ((value & 0xff00) == 0xfe00) {
  420. s_twoByteOpCodes [value & 0xff] = opCode;
  421. }
  422. }
  423. }
  424. private static ulong ReadUInt64 (ImmutableArray<byte> buffer, ref int pos)
  425. {
  426. ulong result =
  427. buffer [pos] |
  428. (ulong)buffer [pos + 1] << 8 |
  429. (ulong)buffer [pos + 2] << 16 |
  430. (ulong)buffer [pos + 3] << 24 |
  431. (ulong)buffer [pos + 4] << 32 |
  432. (ulong)buffer [pos + 5] << 40 |
  433. (ulong)buffer [pos + 6] << 48 |
  434. (ulong)buffer [pos + 7] << 56;
  435. pos += sizeof(ulong);
  436. return result;
  437. }
  438. private static uint ReadUInt32 (ImmutableArray<byte> buffer, ref int pos)
  439. {
  440. uint result = buffer [pos] | (uint)buffer [pos + 1] << 8 | (uint)buffer [pos + 2] << 16 | (uint)buffer [pos + 3] << 24;
  441. pos += sizeof(uint);
  442. return result;
  443. }
  444. private static int ReadInt32 (ImmutableArray<byte> buffer, ref int pos)
  445. {
  446. return unchecked((int)ReadUInt32 (buffer, ref pos));
  447. }
  448. private static ushort ReadUInt16 (ImmutableArray<byte> buffer, ref int pos)
  449. {
  450. ushort result = (ushort)(buffer [pos] | buffer [pos + 1] << 8);
  451. pos += sizeof(ushort);
  452. return result;
  453. }
  454. private static byte ReadByte (ImmutableArray<byte> buffer, ref int pos)
  455. {
  456. byte result = buffer [pos];
  457. pos += sizeof(byte);
  458. return result;
  459. }
  460. private static sbyte ReadSByte (ImmutableArray<byte> buffer, ref int pos)
  461. {
  462. sbyte result = unchecked((sbyte)buffer [pos]);
  463. pos += 1;
  464. return result;
  465. }
  466. private unsafe static float ReadSingle (ImmutableArray<byte> buffer, ref int pos)
  467. {
  468. uint value = ReadUInt32 (buffer, ref pos);
  469. return *(float*)&value;
  470. }
  471. private unsafe static double ReadDouble (ImmutableArray<byte> buffer, ref int pos)
  472. {
  473. ulong value = ReadUInt64 (buffer, ref pos);
  474. return *(double*)&value;
  475. }
  476. public enum HandlerKind
  477. {
  478. Try,
  479. Catch,
  480. Filter,
  481. Finally,
  482. Fault
  483. }
  484. public struct HandlerSpan : IComparable<HandlerSpan>
  485. {
  486. public readonly HandlerKind Kind;
  487. public readonly object ExceptionType;
  488. public readonly int StartOffset;
  489. public readonly int FilterHandlerStart;
  490. public readonly int EndOffset;
  491. public HandlerSpan (HandlerKind kind, object exceptionType, int startOffset, int endOffset, int filterHandlerStart = 0)
  492. {
  493. this.Kind = kind;
  494. this.ExceptionType = exceptionType;
  495. this.StartOffset = startOffset;
  496. this.EndOffset = endOffset;
  497. this.FilterHandlerStart = filterHandlerStart;
  498. }
  499. public int CompareTo (HandlerSpan other)
  500. {
  501. int result = this.StartOffset - other.StartOffset;
  502. if (result == 0) {
  503. // Both blocks have same start. Order larger (outer) before smaller (inner).
  504. result = other.EndOffset - this.EndOffset;
  505. }
  506. return result;
  507. }
  508. public string ToString (CSComponentInspector visualizer)
  509. {
  510. switch (this.Kind) {
  511. default:
  512. return ".try";
  513. case HandlerKind.Catch:
  514. return "catch **exceptiontype**";// + visualizer.VisualizeLocalType(this.ExceptionType);
  515. case HandlerKind.Filter:
  516. return "filter";
  517. case HandlerKind.Finally:
  518. return "finally";
  519. case HandlerKind.Fault:
  520. return "fault";
  521. }
  522. }
  523. public override string ToString ()
  524. {
  525. throw new NotSupportedException ("Use ToString(CSComponentInspector)");
  526. }
  527. }
  528. private static bool StartsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  529. {
  530. return spans != null && spanIndex < spans.Count && spans [spanIndex].StartOffset == (uint)curIndex;
  531. }
  532. private static bool EndsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  533. {
  534. return spans != null && spanIndex >= 0 && spans [spanIndex].EndOffset == (uint)curIndex;
  535. }
  536. private static bool StartsFilterHandler (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  537. {
  538. return spans != null &&
  539. spanIndex < spans.Count &&
  540. spans [spanIndex].Kind == HandlerKind.Filter &&
  541. spans [spanIndex].FilterHandlerStart == (uint)curIndex;
  542. }
  543. public static IReadOnlyList<HandlerSpan> GetHandlerSpans (ImmutableArray<ExceptionRegion> entries)
  544. {
  545. if (entries.Length == 0) {
  546. return new HandlerSpan[0];
  547. }
  548. var result = new List<HandlerSpan> ();
  549. foreach (ExceptionRegion entry in entries) {
  550. int tryStartOffset = entry.TryOffset;
  551. int tryEndOffset = entry.TryOffset + entry.TryLength;
  552. var span = new HandlerSpan (HandlerKind.Try, null, tryStartOffset, tryEndOffset);
  553. if (result.Count == 0 || span.CompareTo (result [result.Count - 1]) != 0) {
  554. result.Add (span);
  555. }
  556. }
  557. foreach (ExceptionRegion entry in entries) {
  558. int handlerStartOffset = entry.HandlerOffset;
  559. int handlerEndOffset = entry.HandlerOffset + entry.HandlerLength;
  560. HandlerSpan span;
  561. switch (entry.Kind) {
  562. case ExceptionRegionKind.Catch:
  563. span = new HandlerSpan (HandlerKind.Catch, MetadataTokens.GetToken (entry.CatchType), handlerStartOffset, handlerEndOffset);
  564. break;
  565. case ExceptionRegionKind.Fault:
  566. span = new HandlerSpan (HandlerKind.Fault, null, handlerStartOffset, handlerEndOffset);
  567. break;
  568. case ExceptionRegionKind.Filter:
  569. span = new HandlerSpan (HandlerKind.Filter, null, handlerStartOffset, handlerEndOffset, entry.FilterOffset);
  570. break;
  571. case ExceptionRegionKind.Finally:
  572. span = new HandlerSpan (HandlerKind.Finally, null, handlerStartOffset, handlerEndOffset);
  573. break;
  574. default:
  575. throw new InvalidOperationException ();
  576. }
  577. result.Add (span);
  578. }
  579. return result;
  580. }
  581. }
  582. internal static class TokenTypeIds
  583. {
  584. internal const uint Module = 0x00000000;
  585. internal const uint TypeRef = 0x01000000;
  586. internal const uint TypeDef = 0x02000000;
  587. internal const uint FieldDef = 0x04000000;
  588. internal const uint MethodDef = 0x06000000;
  589. internal const uint ParamDef = 0x08000000;
  590. internal const uint InterfaceImpl = 0x09000000;
  591. internal const uint MemberRef = 0x0a000000;
  592. internal const uint CustomAttribute = 0x0c000000;
  593. internal const uint Permission = 0x0e000000;
  594. internal const uint Signature = 0x11000000;
  595. internal const uint Event = 0x14000000;
  596. internal const uint Property = 0x17000000;
  597. internal const uint ModuleRef = 0x1a000000;
  598. internal const uint TypeSpec = 0x1b000000;
  599. internal const uint Assembly = 0x20000000;
  600. internal const uint AssemblyRef = 0x23000000;
  601. internal const uint File = 0x26000000;
  602. internal const uint ExportedType = 0x27000000;
  603. internal const uint ManifestResource = 0x28000000;
  604. internal const uint GenericParam = 0x2a000000;
  605. internal const uint MethodSpec = 0x2b000000;
  606. internal const uint GenericParamConstraint = 0x2c000000;
  607. internal const uint String = 0x70000000;
  608. internal const uint Name = 0x71000000;
  609. internal const uint BaseType = 0x72000000;
  610. // Leave this on the high end value. This does not correspond to metadata table???
  611. internal const uint RIDMask = 0x00FFFFFF;
  612. internal const uint TokenTypeMask = 0xFF000000;
  613. }
  614. }