CSComponentInspector.cs 34 KB

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