CSComponentInspectorOld.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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. #if nope
  3. using System.Collections.Immutable;
  4. //using Roslyn.Utilities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Globalization;
  9. using System.Text;
  10. using System.Reflection.Emit;
  11. using System.Reflection;
  12. using System.Reflection.Metadata;
  13. using System.Reflection.Metadata.Ecma335;
  14. namespace AtomicEditor
  15. {
  16. public class CSComponentInspector
  17. {
  18. private static readonly OpCode[] s_oneByteOpCodes;
  19. private static readonly OpCode[] s_twoByteOpCodes;
  20. public static readonly CSComponentInspector Instance = new CSComponentInspector();
  21. static CSComponentInspector()
  22. {
  23. s_oneByteOpCodes = new OpCode[0x100];
  24. s_twoByteOpCodes = new OpCode[0x100];
  25. var typeOfOpCode = typeof(OpCode);
  26. foreach (FieldInfo fi in typeof(OpCodes).GetTypeInfo().DeclaredFields)
  27. {
  28. if (fi.FieldType != typeOfOpCode)
  29. {
  30. continue;
  31. }
  32. OpCode opCode = (OpCode)fi.GetValue(null);
  33. var value = unchecked((ushort)opCode.Value);
  34. if (value < 0x100)
  35. {
  36. s_oneByteOpCodes[value] = opCode;
  37. }
  38. else if ((value & 0xff00) == 0xfe00)
  39. {
  40. s_twoByteOpCodes[value & 0xff] = opCode;
  41. }
  42. }
  43. }
  44. public enum HandlerKind
  45. {
  46. Try,
  47. Catch,
  48. Filter,
  49. Finally,
  50. Fault
  51. }
  52. public struct HandlerSpan : IComparable<HandlerSpan>
  53. {
  54. public readonly HandlerKind Kind;
  55. public readonly object ExceptionType;
  56. public readonly int StartOffset;
  57. public readonly int FilterHandlerStart;
  58. public readonly int EndOffset;
  59. public HandlerSpan(HandlerKind kind, object exceptionType, int startOffset, int endOffset, int filterHandlerStart = 0)
  60. {
  61. this.Kind = kind;
  62. this.ExceptionType = exceptionType;
  63. this.StartOffset = startOffset;
  64. this.EndOffset = endOffset;
  65. this.FilterHandlerStart = filterHandlerStart;
  66. }
  67. public int CompareTo(HandlerSpan other)
  68. {
  69. int result = this.StartOffset - other.StartOffset;
  70. if (result == 0)
  71. {
  72. // Both blocks have same start. Order larger (outer) before smaller (inner).
  73. result = other.EndOffset - this.EndOffset;
  74. }
  75. return result;
  76. }
  77. public string ToString(CSComponentInspector visualizer)
  78. {
  79. switch (this.Kind)
  80. {
  81. default:
  82. return ".try";
  83. case HandlerKind.Catch:
  84. return "catch " + visualizer.VisualizeLocalType(this.ExceptionType);
  85. case HandlerKind.Filter:
  86. return "filter";
  87. case HandlerKind.Finally:
  88. return "finally";
  89. case HandlerKind.Fault:
  90. return "fault";
  91. }
  92. }
  93. public override string ToString()
  94. {
  95. throw new NotSupportedException("Use ToString(CSComponentInspector)");
  96. }
  97. }
  98. public struct LocalInfo
  99. {
  100. public readonly string Name;
  101. public readonly bool IsPinned;
  102. public readonly bool IsByRef;
  103. public readonly object Type; // ITypeReference or ITypeSymbol
  104. public LocalInfo(string name, object type, bool isPinned, bool isByRef)
  105. {
  106. Name = name;
  107. Type = type;
  108. IsPinned = isPinned;
  109. IsByRef = isByRef;
  110. }
  111. }
  112. public const string IndentString = " ";
  113. public string VisualizeUserString(uint token)
  114. {
  115. return "";
  116. }
  117. public string VisualizeSymbol(uint token)
  118. {
  119. return "";
  120. }
  121. public string VisualizeLocalType(object type)
  122. {
  123. return "";
  124. }
  125. private static ulong ReadUInt64(ImmutableArray<byte> buffer, ref int pos)
  126. {
  127. ulong result =
  128. buffer[pos] |
  129. (ulong)buffer[pos + 1] << 8 |
  130. (ulong)buffer[pos + 2] << 16 |
  131. (ulong)buffer[pos + 3] << 24 |
  132. (ulong)buffer[pos + 4] << 32 |
  133. (ulong)buffer[pos + 5] << 40 |
  134. (ulong)buffer[pos + 6] << 48 |
  135. (ulong)buffer[pos + 7] << 56;
  136. pos += sizeof(ulong);
  137. return result;
  138. }
  139. private static uint ReadUInt32(ImmutableArray<byte> buffer, ref int pos)
  140. {
  141. uint result = buffer[pos] | (uint)buffer[pos + 1] << 8 | (uint)buffer[pos + 2] << 16 | (uint)buffer[pos + 3] << 24;
  142. pos += sizeof(uint);
  143. return result;
  144. }
  145. private static int ReadInt32(ImmutableArray<byte> buffer, ref int pos)
  146. {
  147. return unchecked((int)ReadUInt32(buffer, ref pos));
  148. }
  149. private static ushort ReadUInt16(ImmutableArray<byte> buffer, ref int pos)
  150. {
  151. ushort result = (ushort)(buffer[pos]| buffer[pos + 1] << 8);
  152. pos += sizeof(ushort);
  153. return result;
  154. }
  155. private static byte ReadByte(ImmutableArray<byte> buffer, ref int pos)
  156. {
  157. byte result = buffer[pos];
  158. pos += sizeof(byte);
  159. return result;
  160. }
  161. private static sbyte ReadSByte(ImmutableArray<byte> buffer, ref int pos)
  162. {
  163. sbyte result = unchecked((sbyte)buffer[pos]);
  164. pos += 1;
  165. return result;
  166. }
  167. private unsafe static float ReadSingle(ImmutableArray<byte> buffer, ref int pos)
  168. {
  169. uint value = ReadUInt32(buffer, ref pos);
  170. return *(float*)&value;
  171. }
  172. private unsafe static double ReadDouble(ImmutableArray<byte> buffer, ref int pos)
  173. {
  174. ulong value = ReadUInt64(buffer, ref pos);
  175. return *(double*)&value;
  176. }
  177. public void VisualizeHeader(StringBuilder sb, int codeSize, int maxStack, ImmutableArray<LocalInfo> locals)
  178. {
  179. if (codeSize >= 0 && maxStack >= 0)
  180. {
  181. if (codeSize == 0)
  182. {
  183. sb.AppendLine(" // Unrealized IL");
  184. }
  185. else
  186. {
  187. sb.AppendLine(string.Format(" // Code size {0,8} (0x{0:x})", codeSize));
  188. }
  189. sb.AppendLine(string.Format(" .maxstack {0}", maxStack));
  190. }
  191. int i = 0;
  192. foreach (var local in locals)
  193. {
  194. sb.Append(i == 0 ? " .locals init (" : new string(' ', " .locals init (".Length));
  195. if (local.IsPinned)
  196. {
  197. sb.Append("pinned ");
  198. }
  199. sb.Append(VisualizeLocalType(local.Type));
  200. if (local.IsByRef)
  201. {
  202. sb.Append("&");
  203. }
  204. sb.Append(" ");
  205. sb.Append("V_" + i);
  206. sb.Append(i == locals.Length - 1 ? ")" : ",");
  207. var name = local.Name;
  208. if (name != null)
  209. {
  210. sb.Append(" //");
  211. sb.Append(name);
  212. }
  213. sb.AppendLine();
  214. i++;
  215. }
  216. }
  217. public string DumpMethod(
  218. MetadataReader reader,
  219. TypeDefinition typeDef,
  220. int maxStack,
  221. ImmutableArray<byte> ilBytes,
  222. ImmutableArray<LocalInfo> locals,
  223. IReadOnlyList<HandlerSpan> exceptionHandlers,
  224. IReadOnlyDictionary<int, string> markers = null)
  225. {
  226. var builder = new StringBuilder();
  227. this.DumpMethod(reader, typeDef, builder, maxStack, ilBytes, locals, exceptionHandlers, markers);
  228. return builder.ToString();
  229. }
  230. public void DumpMethod(
  231. MetadataReader reader,
  232. TypeDefinition typeDef,
  233. StringBuilder sb,
  234. int maxStack,
  235. ImmutableArray<byte> ilBytes,
  236. ImmutableArray<LocalInfo> locals,
  237. IReadOnlyList<HandlerSpan> exceptionHandlers,
  238. IReadOnlyDictionary<int, string> markers = null)
  239. {
  240. sb.AppendLine("{");
  241. VisualizeHeader(sb, ilBytes.Length, maxStack, locals);
  242. DumpILBlock(reader, typeDef, ilBytes, ilBytes.Length, sb, exceptionHandlers, 0, markers);
  243. sb.AppendLine("}");
  244. }
  245. /// <summary>
  246. /// Dumps all instructions in the stream into provided string builder.
  247. /// The blockOffset specifies the relative position of the block within method body (if known).
  248. /// </summary>
  249. public void DumpILBlock(
  250. MetadataReader reader,
  251. TypeDefinition typeDef,
  252. ImmutableArray<byte> ilBytes,
  253. int length,
  254. StringBuilder sb,
  255. IReadOnlyList<HandlerSpan> spans = null,
  256. int blockOffset = 0,
  257. IReadOnlyDictionary<int, string> markers = null)
  258. {
  259. if (ilBytes == null)
  260. {
  261. return;
  262. }
  263. int spanIndex = 0;
  264. int curIndex = DumpILBlock(reader, typeDef, ilBytes, length, sb, spans, blockOffset, 0, spanIndex, IndentString, markers, out spanIndex);
  265. }
  266. private int DumpILBlock(
  267. MetadataReader reader,
  268. TypeDefinition typeDef,
  269. ImmutableArray<byte> ilBytes,
  270. int length,
  271. StringBuilder sb,
  272. IReadOnlyList<HandlerSpan> spans,
  273. int blockOffset,
  274. int curIndex,
  275. int spanIndex,
  276. string indent,
  277. IReadOnlyDictionary<int, string> markers,
  278. out int nextSpanIndex)
  279. {
  280. int lastSpanIndex = spanIndex - 1;
  281. while (curIndex < length)
  282. {
  283. if (lastSpanIndex > 0 && StartsFilterHandler(spans, lastSpanIndex, curIndex + blockOffset))
  284. {
  285. sb.Append(indent.Substring(0, indent.Length - IndentString.Length));
  286. sb.Append("} // end filter");
  287. sb.AppendLine();
  288. sb.Append(indent.Substring(0, indent.Length - IndentString.Length));
  289. sb.Append("{ // handler");
  290. sb.AppendLine();
  291. }
  292. if (StartsSpan(spans, spanIndex, curIndex + blockOffset))
  293. {
  294. sb.Append(indent);
  295. sb.Append(spans[spanIndex].ToString(this));
  296. sb.AppendLine();
  297. sb.Append(indent);
  298. sb.Append("{");
  299. sb.AppendLine();
  300. curIndex = DumpILBlock(reader, typeDef, ilBytes, length, sb, spans, blockOffset, curIndex, spanIndex + 1, indent + IndentString, markers, out spanIndex);
  301. sb.Append(indent);
  302. sb.Append("}");
  303. sb.AppendLine();
  304. }
  305. else
  306. {
  307. int ilOffset = curIndex + blockOffset;
  308. string marker;
  309. if (markers != null && markers.TryGetValue(ilOffset, out marker))
  310. {
  311. sb.Append(indent.Substring(0, indent.Length - marker.Length));
  312. sb.Append(marker);
  313. }
  314. else
  315. {
  316. sb.Append(indent);
  317. }
  318. sb.AppendFormat("IL_{0:x4}:", ilOffset);
  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. sb.AppendFormat(opCode.OperandType == OperandType.InlineNone ? "{0}" : "{0,-10}", opCode);
  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 = reader.GetFieldDefinition(fieldHandle);
  351. sb.AppendFormat("{0}", reader.GetString(fieldDef.Name));
  352. break;
  353. case OperandType.InlineMethod:
  354. case OperandType.InlineTok:
  355. case OperandType.InlineType:
  356. sb.Append(VisualizeSymbol(ReadUInt32(ilBytes, ref curIndex)));
  357. break;
  358. case OperandType.InlineSig: // signature (calli), not emitted by C#/VB
  359. sb.AppendFormat(" 387 0x{0:x}", ReadUInt32(ilBytes, ref curIndex));
  360. break;
  361. case OperandType.InlineString:
  362. //sb.Append(" 391 ");
  363. //sb.Append(VisualizeUserString());
  364. uint stringToken = ReadUInt32(ilBytes, ref curIndex);
  365. // get the kind
  366. //uint tokenKind = stringToken & TokenTypeIds.TokenTypeMask;
  367. // and the rowId
  368. //uint rowId = stringToken & TokenTypeIds.RIDMask;
  369. UserStringHandle handle = MetadataTokens.UserStringHandle((int)stringToken);
  370. sb.AppendFormat("\"{0}\"", reader.GetUserString(handle));
  371. break;
  372. case OperandType.InlineNone:
  373. // ldc.i4.1 // load 1 for instance
  374. //sb.AppendFormat(" InlineNone");
  375. break;
  376. case OperandType.ShortInlineI:
  377. sb.AppendFormat(" 399 {0}", ReadSByte(ilBytes, ref curIndex));
  378. break;
  379. case OperandType.ShortInlineVar:
  380. sb.AppendFormat(" 403 V_{0}", ReadByte(ilBytes, ref curIndex));
  381. break;
  382. case OperandType.InlineVar:
  383. sb.AppendFormat(" 407 V_{0}", ReadUInt16(ilBytes, ref curIndex));
  384. break;
  385. case OperandType.InlineI:
  386. sb.AppendFormat(" 411 0x{0:x}", ReadUInt32(ilBytes, ref curIndex));
  387. break;
  388. case OperandType.InlineI8:
  389. sb.AppendFormat(" 415 0x{0:x8}", ReadUInt64(ilBytes, ref curIndex));
  390. break;
  391. case OperandType.ShortInlineR:
  392. {
  393. var value = ReadSingle(ilBytes, ref curIndex);
  394. if (value == 0 && 1 / value < 0)
  395. {
  396. sb.Append(" 423 -0.0");
  397. }
  398. else
  399. {
  400. sb.AppendFormat("477 {0}", value.ToString(CultureInfo.InvariantCulture));
  401. }
  402. }
  403. break;
  404. case OperandType.InlineR:
  405. {
  406. var value = ReadDouble(ilBytes, ref curIndex);
  407. if (value == 0 && 1 / value < 0)
  408. {
  409. sb.Append("437 -0.0");
  410. }
  411. else
  412. {
  413. sb.AppendFormat("441 {0}", value.ToString(CultureInfo.InvariantCulture));
  414. }
  415. }
  416. break;
  417. case OperandType.ShortInlineBrTarget:
  418. sb.AppendFormat(" 447 IL_{0:x4}", ReadSByte(ilBytes, ref curIndex) + curIndex + blockOffset);
  419. break;
  420. case OperandType.InlineBrTarget:
  421. sb.AppendFormat(" 451 IL_{0:x4}", ReadInt32(ilBytes, ref curIndex) + curIndex + blockOffset);
  422. break;
  423. case OperandType.InlineSwitch:
  424. int labelCount = ReadInt32(ilBytes, ref curIndex);
  425. int instrEnd = curIndex + labelCount * 4;
  426. sb.AppendLine("(");
  427. for (int i = 0; i < labelCount; i++)
  428. {
  429. sb.AppendFormat(" IL_{0:x4}", ReadInt32(ilBytes, ref curIndex) + instrEnd + blockOffset);
  430. sb.AppendLine((i == labelCount - 1) ? ")" : ",");
  431. }
  432. break;
  433. default:
  434. throw new InvalidOperationException();
  435. //throw ExceptionUtilities.UnexpectedValue(opCode.OperandType);
  436. }
  437. sb.AppendLine();
  438. }
  439. if (EndsSpan(spans, lastSpanIndex, curIndex + blockOffset))
  440. {
  441. break;
  442. }
  443. }
  444. nextSpanIndex = spanIndex;
  445. return curIndex;
  446. }
  447. private static bool StartsSpan(IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  448. {
  449. return spans != null && spanIndex < spans.Count && spans[spanIndex].StartOffset == (uint)curIndex;
  450. }
  451. private static bool EndsSpan(IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  452. {
  453. return spans != null && spanIndex >= 0 && spans[spanIndex].EndOffset == (uint)curIndex;
  454. }
  455. private static bool StartsFilterHandler(IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  456. {
  457. return spans != null &&
  458. spanIndex < spans.Count &&
  459. spans[spanIndex].Kind == HandlerKind.Filter &&
  460. spans[spanIndex].FilterHandlerStart == (uint)curIndex;
  461. }
  462. public static IReadOnlyList<HandlerSpan> GetHandlerSpans(ImmutableArray<ExceptionRegion> entries)
  463. {
  464. if (entries.Length == 0)
  465. {
  466. return new HandlerSpan[0];
  467. }
  468. var result = new List<HandlerSpan>();
  469. foreach (ExceptionRegion entry in entries)
  470. {
  471. int tryStartOffset = entry.TryOffset;
  472. int tryEndOffset = entry.TryOffset + entry.TryLength;
  473. var span = new HandlerSpan(HandlerKind.Try, null, tryStartOffset, tryEndOffset);
  474. if (result.Count == 0 || span.CompareTo(result[result.Count - 1]) != 0)
  475. {
  476. result.Add(span);
  477. }
  478. }
  479. foreach (ExceptionRegion entry in entries)
  480. {
  481. int handlerStartOffset = entry.HandlerOffset;
  482. int handlerEndOffset = entry.HandlerOffset + entry.HandlerLength;
  483. HandlerSpan span;
  484. switch (entry.Kind)
  485. {
  486. case ExceptionRegionKind.Catch:
  487. span = new HandlerSpan(HandlerKind.Catch, MetadataTokens.GetToken(entry.CatchType), handlerStartOffset, handlerEndOffset);
  488. break;
  489. case ExceptionRegionKind.Fault:
  490. span = new HandlerSpan(HandlerKind.Fault, null, handlerStartOffset, handlerEndOffset);
  491. break;
  492. case ExceptionRegionKind.Filter:
  493. span = new HandlerSpan(HandlerKind.Filter, null, handlerStartOffset, handlerEndOffset, entry.FilterOffset);
  494. break;
  495. case ExceptionRegionKind.Finally:
  496. span = new HandlerSpan(HandlerKind.Finally, null, handlerStartOffset, handlerEndOffset);
  497. break;
  498. default:
  499. throw new InvalidOperationException();
  500. }
  501. result.Add(span);
  502. }
  503. return result;
  504. }
  505. }
  506. internal static class TokenTypeIds {
  507. internal const uint Module = 0x00000000;
  508. internal const uint TypeRef = 0x01000000;
  509. internal const uint TypeDef = 0x02000000;
  510. internal const uint FieldDef = 0x04000000;
  511. internal const uint MethodDef = 0x06000000;
  512. internal const uint ParamDef = 0x08000000;
  513. internal const uint InterfaceImpl = 0x09000000;
  514. internal const uint MemberRef = 0x0a000000;
  515. internal const uint CustomAttribute = 0x0c000000;
  516. internal const uint Permission = 0x0e000000;
  517. internal const uint Signature = 0x11000000;
  518. internal const uint Event = 0x14000000;
  519. internal const uint Property = 0x17000000;
  520. internal const uint ModuleRef = 0x1a000000;
  521. internal const uint TypeSpec = 0x1b000000;
  522. internal const uint Assembly = 0x20000000;
  523. internal const uint AssemblyRef = 0x23000000;
  524. internal const uint File = 0x26000000;
  525. internal const uint ExportedType = 0x27000000;
  526. internal const uint ManifestResource = 0x28000000;
  527. internal const uint GenericParam = 0x2a000000;
  528. internal const uint MethodSpec = 0x2b000000;
  529. internal const uint GenericParamConstraint = 0x2c000000;
  530. internal const uint String = 0x70000000;
  531. internal const uint Name = 0x71000000;
  532. internal const uint BaseType = 0x72000000; // Leave this on the high end value. This does not correspond to metadata table???
  533. internal const uint RIDMask = 0x00FFFFFF;
  534. internal const uint TokenTypeMask = 0xFF000000;
  535. }
  536. }
  537. #endif