CSComponentInspector.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. namespace AtomicEditor
  15. {
  16. public class CSComponentInspector
  17. {
  18. private List<string> inspectorFieldNames = new List<string> ();
  19. public CSComponentInspector (TypeDefinition typeDef, PEReader peFile, MetadataReader metaReader)
  20. {
  21. this.typeDef = typeDef;
  22. this.peFile = peFile;
  23. this.metaReader = metaReader;
  24. }
  25. public bool Inspect ()
  26. {
  27. var fields = typeDef.GetFields ();
  28. foreach (var fieldHandle in fields) {
  29. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  30. var customAttr = fieldDef.GetCustomAttributes ();
  31. foreach (var caHandle in customAttr) {
  32. var ca = metaReader.GetCustomAttribute (caHandle);
  33. // MethodDefinitionHandle or MemberReferenceHandle
  34. if (ca.Constructor.Kind == HandleKind.MemberReference) {
  35. var memberRef = metaReader.GetMemberReference ((MemberReferenceHandle)ca.Constructor);
  36. var parent = memberRef.Parent;
  37. if (parent.Kind == HandleKind.TypeReference) {
  38. var parentTypeRef = metaReader.GetTypeReference ((TypeReferenceHandle)parent);
  39. var attrName = metaReader.GetString (parentTypeRef.Name);
  40. if (attrName == "InspectorAttribute") {
  41. var fieldName = metaReader.GetString (fieldDef.Name);
  42. inspectorFieldNames.Add (fieldName);
  43. Console.WriteLine ("Found inspector field: {0}", fieldName);
  44. var blobReader = metaReader.GetBlobReader( (BlobHandle) ca.Value);
  45. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  46. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  47. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  48. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  49. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  50. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  51. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  52. Console.WriteLine("Blob: {0}", blobReader.ReadByte());
  53. //Console.WriteLine("Blob: {0}", blobReader.ReadSerializedString());
  54. //Console.WriteLine("Blob: {0}", blobReader.ReadUInt16());
  55. //Console.WriteLine("Blob: {0}", blobReader.ReadSerializedString());
  56. }
  57. //Console.WriteLine("CustomAttr MemberReference {0} {1}", , metaReader.GetString(memberRef.Name));
  58. }
  59. }
  60. }
  61. }
  62. var methods = typeDef.GetMethods ();
  63. foreach (var methodHandle in methods) {
  64. var methodDef = metaReader.GetMethodDefinition (methodHandle);
  65. if (metaReader.GetString (methodDef.Name) == ".ctor") {
  66. var body = peFile.GetMethodBody (methodDef.RelativeVirtualAddress);
  67. }
  68. }
  69. return true;
  70. }
  71. public void InspectILBlock (
  72. ImmutableArray<byte> ilBytes,
  73. int length,
  74. IReadOnlyList<HandlerSpan> spans = null,
  75. int blockOffset = 0,
  76. IReadOnlyDictionary<int, string> markers = null)
  77. {
  78. if (ilBytes == null) {
  79. return;
  80. }
  81. int spanIndex = 0;
  82. int curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, 0, spanIndex, markers, out spanIndex);
  83. }
  84. private int InspectILBlock (
  85. ImmutableArray<byte> ilBytes,
  86. int length,
  87. IReadOnlyList<HandlerSpan> spans,
  88. int blockOffset,
  89. int curIndex,
  90. int spanIndex,
  91. IReadOnlyDictionary<int, string> markers,
  92. out int nextSpanIndex)
  93. {
  94. int lastSpanIndex = spanIndex - 1;
  95. while (curIndex < length) {
  96. if (lastSpanIndex > 0 && StartsFilterHandler (spans, lastSpanIndex, curIndex + blockOffset)) {
  97. }
  98. if (StartsSpan (spans, spanIndex, curIndex + blockOffset)) {
  99. curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, curIndex, spanIndex + 1, markers, out spanIndex);
  100. } else {
  101. int ilOffset = curIndex + blockOffset;
  102. string marker;
  103. if (markers != null && markers.TryGetValue (ilOffset, out marker)) {
  104. } else {
  105. }
  106. OpCode opCode;
  107. int expectedSize;
  108. byte op1 = ilBytes [curIndex++];
  109. if (op1 == 0xfe && curIndex < length) {
  110. byte op2 = ilBytes [curIndex++];
  111. opCode = s_twoByteOpCodes [op2];
  112. expectedSize = 2;
  113. } else {
  114. opCode = s_oneByteOpCodes [op1];
  115. expectedSize = 1;
  116. }
  117. if (opCode.Size != expectedSize) {
  118. //sb.AppendLine(string.Format(" <unknown 0x{0}{1:X2}>", expectedSize == 2 ? "fe" : "", op1));
  119. continue;
  120. }
  121. //sb.Append(" ");
  122. //sb.AppendFormat(opCode.OperandType == OperandType.InlineNone ? "{0}" : "{0,-10}", opCode);
  123. switch (opCode.OperandType) {
  124. case OperandType.InlineField:
  125. // read token
  126. uint fieldToken = ReadUInt32 (ilBytes, ref curIndex);
  127. // get the kind
  128. uint tokenKind = fieldToken & TokenTypeIds.TokenTypeMask;
  129. // and the rowId
  130. uint rowId = fieldToken & TokenTypeIds.RIDMask;
  131. var fieldHandle = MetadataTokens.FieldDefinitionHandle ((int)rowId);
  132. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  133. break;
  134. case OperandType.InlineMethod:
  135. case OperandType.InlineTok:
  136. case OperandType.InlineType:
  137. ReadUInt32 (ilBytes, ref curIndex);
  138. break;
  139. case OperandType.InlineSig: // signature (calli), not emitted by C#/VB
  140. ReadUInt32 (ilBytes, ref curIndex);
  141. break;
  142. case OperandType.InlineString:
  143. //sb.Append(" 391 ");
  144. //sb.Append(VisualizeUserString());
  145. uint stringToken = ReadUInt32 (ilBytes, ref curIndex);
  146. // get the kind
  147. //uint tokenKind = stringToken & TokenTypeIds.TokenTypeMask;
  148. // and the rowId
  149. //uint rowId = stringToken & TokenTypeIds.RIDMask;
  150. UserStringHandle handle = MetadataTokens.UserStringHandle ((int)stringToken);
  151. string stringValue = metaReader.GetUserString (handle);
  152. //sb.AppendFormat("\"{0}\"", );
  153. break;
  154. case OperandType.InlineNone:
  155. // ldc.i4.1 // load 1 for instance
  156. //sb.AppendFormat(" InlineNone");
  157. break;
  158. case OperandType.ShortInlineI:
  159. ReadSByte (ilBytes, ref curIndex);
  160. break;
  161. case OperandType.ShortInlineVar:
  162. ReadByte (ilBytes, ref curIndex);
  163. break;
  164. case OperandType.InlineVar:
  165. ReadUInt16 (ilBytes, ref curIndex);
  166. break;
  167. case OperandType.InlineI:
  168. ReadUInt32 (ilBytes, ref curIndex);
  169. break;
  170. case OperandType.InlineI8:
  171. ReadUInt64 (ilBytes, ref curIndex);
  172. break;
  173. case OperandType.ShortInlineR:
  174. {
  175. var value = ReadSingle (ilBytes, ref curIndex);
  176. if (value == 0 && 1 / value < 0) {
  177. //sb.Append(" 423 -0.0");
  178. } else {
  179. //sb.AppendFormat("477 {0}", value.ToString(CultureInfo.InvariantCulture));
  180. }
  181. }
  182. break;
  183. case OperandType.InlineR:
  184. {
  185. var value = ReadDouble (ilBytes, ref curIndex);
  186. if (value == 0 && 1 / value < 0) {
  187. //sb.Append("437 -0.0");
  188. } else {
  189. //sb.AppendFormat("441 {0}", value.ToString(CultureInfo.InvariantCulture));
  190. }
  191. }
  192. break;
  193. case OperandType.ShortInlineBrTarget:
  194. var sbyteValue = ReadSByte (ilBytes, ref curIndex) + curIndex + blockOffset;
  195. break;
  196. case OperandType.InlineBrTarget:
  197. var int32value = ReadInt32 (ilBytes, ref curIndex) + curIndex + blockOffset;
  198. break;
  199. case OperandType.InlineSwitch:
  200. int labelCount = ReadInt32 (ilBytes, ref curIndex);
  201. int instrEnd = curIndex + labelCount * 4;
  202. for (int i = 0; i < labelCount; i++) {
  203. var int32LabelValue = ReadInt32 (ilBytes, ref curIndex) + instrEnd + blockOffset;
  204. //sb.AppendLine((i == labelCount - 1) ? ")" : ",");
  205. }
  206. break;
  207. default:
  208. throw new InvalidOperationException ();
  209. //throw ExceptionUtilities.UnexpectedValue(opCode.OperandType);
  210. }
  211. //sb.AppendLine();
  212. }
  213. if (EndsSpan (spans, lastSpanIndex, curIndex + blockOffset)) {
  214. break;
  215. }
  216. }
  217. nextSpanIndex = spanIndex;
  218. return curIndex;
  219. }
  220. TypeDefinition typeDef;
  221. PEReader peFile;
  222. MetadataReader metaReader;
  223. private static readonly OpCode[] s_oneByteOpCodes;
  224. private static readonly OpCode[] s_twoByteOpCodes;
  225. static CSComponentInspector ()
  226. {
  227. s_oneByteOpCodes = new OpCode[0x100];
  228. s_twoByteOpCodes = new OpCode[0x100];
  229. var typeOfOpCode = typeof(OpCode);
  230. foreach (FieldInfo fi in typeof(OpCodes).GetTypeInfo().DeclaredFields) {
  231. if (fi.FieldType != typeOfOpCode) {
  232. continue;
  233. }
  234. OpCode opCode = (OpCode)fi.GetValue (null);
  235. var value = unchecked((ushort)opCode.Value);
  236. if (value < 0x100) {
  237. s_oneByteOpCodes [value] = opCode;
  238. } else if ((value & 0xff00) == 0xfe00) {
  239. s_twoByteOpCodes [value & 0xff] = opCode;
  240. }
  241. }
  242. }
  243. private static ulong ReadUInt64 (ImmutableArray<byte> buffer, ref int pos)
  244. {
  245. ulong result =
  246. buffer [pos] |
  247. (ulong)buffer [pos + 1] << 8 |
  248. (ulong)buffer [pos + 2] << 16 |
  249. (ulong)buffer [pos + 3] << 24 |
  250. (ulong)buffer [pos + 4] << 32 |
  251. (ulong)buffer [pos + 5] << 40 |
  252. (ulong)buffer [pos + 6] << 48 |
  253. (ulong)buffer [pos + 7] << 56;
  254. pos += sizeof(ulong);
  255. return result;
  256. }
  257. private static uint ReadUInt32 (ImmutableArray<byte> buffer, ref int pos)
  258. {
  259. uint result = buffer [pos] | (uint)buffer [pos + 1] << 8 | (uint)buffer [pos + 2] << 16 | (uint)buffer [pos + 3] << 24;
  260. pos += sizeof(uint);
  261. return result;
  262. }
  263. private static int ReadInt32 (ImmutableArray<byte> buffer, ref int pos)
  264. {
  265. return unchecked((int)ReadUInt32 (buffer, ref pos));
  266. }
  267. private static ushort ReadUInt16 (ImmutableArray<byte> buffer, ref int pos)
  268. {
  269. ushort result = (ushort)(buffer [pos] | buffer [pos + 1] << 8);
  270. pos += sizeof(ushort);
  271. return result;
  272. }
  273. private static byte ReadByte (ImmutableArray<byte> buffer, ref int pos)
  274. {
  275. byte result = buffer [pos];
  276. pos += sizeof(byte);
  277. return result;
  278. }
  279. private static sbyte ReadSByte (ImmutableArray<byte> buffer, ref int pos)
  280. {
  281. sbyte result = unchecked((sbyte)buffer [pos]);
  282. pos += 1;
  283. return result;
  284. }
  285. private unsafe static float ReadSingle (ImmutableArray<byte> buffer, ref int pos)
  286. {
  287. uint value = ReadUInt32 (buffer, ref pos);
  288. return *(float*)&value;
  289. }
  290. private unsafe static double ReadDouble (ImmutableArray<byte> buffer, ref int pos)
  291. {
  292. ulong value = ReadUInt64 (buffer, ref pos);
  293. return *(double*)&value;
  294. }
  295. public enum HandlerKind
  296. {
  297. Try,
  298. Catch,
  299. Filter,
  300. Finally,
  301. Fault
  302. }
  303. public struct HandlerSpan : IComparable<HandlerSpan>
  304. {
  305. public readonly HandlerKind Kind;
  306. public readonly object ExceptionType;
  307. public readonly int StartOffset;
  308. public readonly int FilterHandlerStart;
  309. public readonly int EndOffset;
  310. public HandlerSpan (HandlerKind kind, object exceptionType, int startOffset, int endOffset, int filterHandlerStart = 0)
  311. {
  312. this.Kind = kind;
  313. this.ExceptionType = exceptionType;
  314. this.StartOffset = startOffset;
  315. this.EndOffset = endOffset;
  316. this.FilterHandlerStart = filterHandlerStart;
  317. }
  318. public int CompareTo (HandlerSpan other)
  319. {
  320. int result = this.StartOffset - other.StartOffset;
  321. if (result == 0) {
  322. // Both blocks have same start. Order larger (outer) before smaller (inner).
  323. result = other.EndOffset - this.EndOffset;
  324. }
  325. return result;
  326. }
  327. public string ToString (CSComponentInspector visualizer)
  328. {
  329. switch (this.Kind) {
  330. default:
  331. return ".try";
  332. case HandlerKind.Catch:
  333. return "catch **exceptiontype**";// + visualizer.VisualizeLocalType(this.ExceptionType);
  334. case HandlerKind.Filter:
  335. return "filter";
  336. case HandlerKind.Finally:
  337. return "finally";
  338. case HandlerKind.Fault:
  339. return "fault";
  340. }
  341. }
  342. public override string ToString ()
  343. {
  344. throw new NotSupportedException ("Use ToString(CSComponentInspector)");
  345. }
  346. }
  347. private static bool StartsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  348. {
  349. return spans != null && spanIndex < spans.Count && spans [spanIndex].StartOffset == (uint)curIndex;
  350. }
  351. private static bool EndsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  352. {
  353. return spans != null && spanIndex >= 0 && spans [spanIndex].EndOffset == (uint)curIndex;
  354. }
  355. private static bool StartsFilterHandler (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
  356. {
  357. return spans != null &&
  358. spanIndex < spans.Count &&
  359. spans [spanIndex].Kind == HandlerKind.Filter &&
  360. spans [spanIndex].FilterHandlerStart == (uint)curIndex;
  361. }
  362. public static IReadOnlyList<HandlerSpan> GetHandlerSpans (ImmutableArray<ExceptionRegion> entries)
  363. {
  364. if (entries.Length == 0) {
  365. return new HandlerSpan[0];
  366. }
  367. var result = new List<HandlerSpan> ();
  368. foreach (ExceptionRegion entry in entries) {
  369. int tryStartOffset = entry.TryOffset;
  370. int tryEndOffset = entry.TryOffset + entry.TryLength;
  371. var span = new HandlerSpan (HandlerKind.Try, null, tryStartOffset, tryEndOffset);
  372. if (result.Count == 0 || span.CompareTo (result [result.Count - 1]) != 0) {
  373. result.Add (span);
  374. }
  375. }
  376. foreach (ExceptionRegion entry in entries) {
  377. int handlerStartOffset = entry.HandlerOffset;
  378. int handlerEndOffset = entry.HandlerOffset + entry.HandlerLength;
  379. HandlerSpan span;
  380. switch (entry.Kind) {
  381. case ExceptionRegionKind.Catch:
  382. span = new HandlerSpan (HandlerKind.Catch, MetadataTokens.GetToken (entry.CatchType), handlerStartOffset, handlerEndOffset);
  383. break;
  384. case ExceptionRegionKind.Fault:
  385. span = new HandlerSpan (HandlerKind.Fault, null, handlerStartOffset, handlerEndOffset);
  386. break;
  387. case ExceptionRegionKind.Filter:
  388. span = new HandlerSpan (HandlerKind.Filter, null, handlerStartOffset, handlerEndOffset, entry.FilterOffset);
  389. break;
  390. case ExceptionRegionKind.Finally:
  391. span = new HandlerSpan (HandlerKind.Finally, null, handlerStartOffset, handlerEndOffset);
  392. break;
  393. default:
  394. throw new InvalidOperationException ();
  395. }
  396. result.Add (span);
  397. }
  398. return result;
  399. }
  400. }
  401. internal static class TokenTypeIds
  402. {
  403. internal const uint Module = 0x00000000;
  404. internal const uint TypeRef = 0x01000000;
  405. internal const uint TypeDef = 0x02000000;
  406. internal const uint FieldDef = 0x04000000;
  407. internal const uint MethodDef = 0x06000000;
  408. internal const uint ParamDef = 0x08000000;
  409. internal const uint InterfaceImpl = 0x09000000;
  410. internal const uint MemberRef = 0x0a000000;
  411. internal const uint CustomAttribute = 0x0c000000;
  412. internal const uint Permission = 0x0e000000;
  413. internal const uint Signature = 0x11000000;
  414. internal const uint Event = 0x14000000;
  415. internal const uint Property = 0x17000000;
  416. internal const uint ModuleRef = 0x1a000000;
  417. internal const uint TypeSpec = 0x1b000000;
  418. internal const uint Assembly = 0x20000000;
  419. internal const uint AssemblyRef = 0x23000000;
  420. internal const uint File = 0x26000000;
  421. internal const uint ExportedType = 0x27000000;
  422. internal const uint ManifestResource = 0x28000000;
  423. internal const uint GenericParam = 0x2a000000;
  424. internal const uint MethodSpec = 0x2b000000;
  425. internal const uint GenericParamConstraint = 0x2c000000;
  426. internal const uint String = 0x70000000;
  427. internal const uint Name = 0x71000000;
  428. internal const uint BaseType = 0x72000000;
  429. // Leave this on the high end value. This does not correspond to metadata table???
  430. internal const uint RIDMask = 0x00FFFFFF;
  431. internal const uint TokenTypeMask = 0xFF000000;
  432. }
  433. }