PageRenderTime 66ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/tools/cil-strip/Mono.Cecil.Cil/CodeReader.cs

https://github.com/iainlane/mono
C# | 357 lines | 290 code | 37 blank | 30 comment | 45 complexity | 9eacb64305cb6040f84e4e7022f522dc MD5 | raw file
  1. //
  2. // CodeReader.cs
  3. //
  4. // Author:
  5. // Jb Evain (jbevain@gmail.com)
  6. //
  7. // (C) 2005 - 2007 Jb Evain
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. namespace Mono.Cecil.Cil {
  29. using System;
  30. using System.Collections;
  31. using System.IO;
  32. using Mono.Cecil;
  33. using Mono.Cecil.Metadata;
  34. using Mono.Cecil.Signatures;
  35. sealed class CodeReader : BaseCodeVisitor {
  36. ReflectionReader m_reflectReader;
  37. MetadataRoot m_root;
  38. IDictionary m_instructions;
  39. public CodeReader (ReflectionReader reflectReader)
  40. {
  41. m_reflectReader = reflectReader;
  42. m_root = m_reflectReader.MetadataRoot;
  43. m_instructions = new Hashtable ();
  44. }
  45. public override void VisitMethodBody (MethodBody body)
  46. {
  47. MethodDefinition meth = body.Method;
  48. MethodBody methBody = body;
  49. BinaryReader br = m_reflectReader.Module.ImageReader.MetadataReader.GetDataReader (meth.RVA);
  50. // lets read the method
  51. int flags = br.ReadByte ();
  52. switch (flags & 0x3) {
  53. case (int) MethodHeader.TinyFormat :
  54. methBody.CodeSize = flags >> 2;
  55. methBody.MaxStack = 8;
  56. ReadCilBody (methBody, br);
  57. break;
  58. case (int) MethodHeader.FatFormat :
  59. br.BaseStream.Position--;
  60. int fatflags = br.ReadUInt16 ();
  61. //int headersize = (fatflags >> 12) & 0xf;
  62. methBody.MaxStack = br.ReadUInt16 ();
  63. methBody.CodeSize = br.ReadInt32 ();
  64. methBody.LocalVarToken = br.ReadInt32 ();
  65. body.InitLocals = (fatflags & (int) MethodHeader.InitLocals) != 0;
  66. if (methBody.LocalVarToken != 0)
  67. VisitVariableDefinitionCollection (methBody.Variables);
  68. ReadCilBody (methBody, br);
  69. if ((fatflags & (int) MethodHeader.MoreSects) != 0)
  70. ReadSection (methBody, br);
  71. break;
  72. }
  73. }
  74. public static uint GetRid (int token)
  75. {
  76. return (uint) token & 0x00ffffff;
  77. }
  78. public static ParameterDefinition GetParameter (MethodBody body, int index)
  79. {
  80. if (body.Method.HasThis) {
  81. if (index == 0)
  82. return body.Method.This;
  83. index--;
  84. }
  85. return body.Method.Parameters [index];
  86. }
  87. public static VariableDefinition GetVariable (MethodBody body, int index)
  88. {
  89. return body.Variables [index];
  90. }
  91. void ReadCilBody (MethodBody body, BinaryReader br)
  92. {
  93. long start = br.BaseStream.Position;
  94. Instruction last = null;
  95. m_instructions.Clear();
  96. InstructionCollection code = body.Instructions;
  97. GenericContext context = new GenericContext (body.Method);
  98. while (br.BaseStream.Position < start + body.CodeSize) {
  99. OpCode op;
  100. long offset = br.BaseStream.Position - start;
  101. int cursor = br.ReadByte ();
  102. if (cursor == 0xfe)
  103. op = OpCodes.TwoBytesOpCode [br.ReadByte ()];
  104. else
  105. op = OpCodes.OneByteOpCode [cursor];
  106. Instruction instr = new Instruction ((int) offset, op);
  107. switch (op.OperandType) {
  108. case OperandType.InlineNone :
  109. break;
  110. case OperandType.InlineSwitch :
  111. uint length = br.ReadUInt32 ();
  112. int [] branches = new int [length];
  113. int [] buf = new int [length];
  114. for (int i = 0; i < length; i++)
  115. buf [i] = br.ReadInt32 ();
  116. for (int i = 0; i < length; i++)
  117. branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
  118. instr.Operand = branches;
  119. break;
  120. case OperandType.ShortInlineBrTarget :
  121. sbyte sbrtgt = br.ReadSByte ();
  122. instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
  123. break;
  124. case OperandType.InlineBrTarget :
  125. int brtgt = br.ReadInt32 ();
  126. instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
  127. break;
  128. case OperandType.ShortInlineI :
  129. if (op == OpCodes.Ldc_I4_S)
  130. instr.Operand = br.ReadSByte ();
  131. else
  132. instr.Operand = br.ReadByte ();
  133. break;
  134. case OperandType.ShortInlineVar :
  135. instr.Operand = GetVariable (body, br.ReadByte ());
  136. break;
  137. case OperandType.ShortInlineParam :
  138. instr.Operand = GetParameter (body, br.ReadByte ());
  139. break;
  140. case OperandType.InlineSig :
  141. instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
  142. break;
  143. case OperandType.InlineI :
  144. instr.Operand = br.ReadInt32 ();
  145. break;
  146. case OperandType.InlineVar :
  147. instr.Operand = GetVariable (body, br.ReadInt16 ());
  148. break;
  149. case OperandType.InlineParam :
  150. instr.Operand = GetParameter (body, br.ReadInt16 ());
  151. break;
  152. case OperandType.InlineI8 :
  153. instr.Operand = br.ReadInt64 ();
  154. break;
  155. case OperandType.ShortInlineR :
  156. instr.Operand = br.ReadSingle ();
  157. break;
  158. case OperandType.InlineR :
  159. instr.Operand = br.ReadDouble ();
  160. break;
  161. case OperandType.InlineString :
  162. instr.Operand = m_root.Streams.UserStringsHeap [GetRid (br.ReadInt32 ())];
  163. break;
  164. case OperandType.InlineField :
  165. case OperandType.InlineMethod :
  166. case OperandType.InlineType :
  167. case OperandType.InlineTok :
  168. MetadataToken token = new MetadataToken (br.ReadInt32 ());
  169. switch (token.TokenType) {
  170. case TokenType.TypeDef:
  171. instr.Operand = m_reflectReader.GetTypeDefAt (token.RID);
  172. break;
  173. case TokenType.TypeRef:
  174. instr.Operand = m_reflectReader.GetTypeRefAt (token.RID);
  175. break;
  176. case TokenType.TypeSpec:
  177. instr.Operand = m_reflectReader.GetTypeSpecAt (token.RID, context);
  178. break;
  179. case TokenType.Field:
  180. instr.Operand = m_reflectReader.GetFieldDefAt (token.RID);
  181. break;
  182. case TokenType.Method:
  183. instr.Operand = m_reflectReader.GetMethodDefAt (token.RID);
  184. break;
  185. case TokenType.MethodSpec:
  186. instr.Operand = m_reflectReader.GetMethodSpecAt (token.RID, context);
  187. break;
  188. case TokenType.MemberRef:
  189. instr.Operand = m_reflectReader.GetMemberRefAt (token.RID, context);
  190. break;
  191. default:
  192. throw new ReflectionException ("Wrong token: " + token);
  193. }
  194. break;
  195. }
  196. m_instructions.Add (instr.Offset, instr);
  197. if (last != null) {
  198. last.Next = instr;
  199. instr.Previous = last;
  200. }
  201. last = instr;
  202. code.Add (instr);
  203. }
  204. // resolve branches
  205. foreach (Instruction i in code) {
  206. switch (i.OpCode.OperandType) {
  207. case OperandType.ShortInlineBrTarget:
  208. case OperandType.InlineBrTarget:
  209. i.Operand = GetInstruction (body, (int) i.Operand);
  210. break;
  211. case OperandType.InlineSwitch:
  212. int [] lbls = (int []) i.Operand;
  213. Instruction [] instrs = new Instruction [lbls.Length];
  214. for (int j = 0; j < lbls.Length; j++)
  215. instrs [j] = GetInstruction (body, lbls [j]);
  216. i.Operand = instrs;
  217. break;
  218. }
  219. }
  220. if (m_reflectReader.SymbolReader != null)
  221. m_reflectReader.SymbolReader.Read (body, m_instructions);
  222. }
  223. Instruction GetInstruction (MethodBody body, int offset)
  224. {
  225. Instruction instruction = m_instructions [offset] as Instruction;
  226. if (instruction != null)
  227. return instruction;
  228. return body.Instructions.Outside;
  229. }
  230. void ReadSection (MethodBody body, BinaryReader br)
  231. {
  232. br.BaseStream.Position += 3;
  233. br.BaseStream.Position &= ~3;
  234. byte flags = br.ReadByte ();
  235. if ((flags & (byte) MethodDataSection.FatFormat) == 0) {
  236. int length = br.ReadByte () / 12;
  237. br.ReadBytes (2);
  238. for (int i = 0; i < length; i++) {
  239. ExceptionHandler eh = new ExceptionHandler (
  240. (ExceptionHandlerType) (br.ReadInt16 () & 0x7));
  241. eh.TryStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
  242. eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + Convert.ToInt32 (br.ReadByte ()));
  243. eh.HandlerStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
  244. eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + Convert.ToInt32 (br.ReadByte ()));
  245. ReadExceptionHandlerEnd (eh, br, body);
  246. body.ExceptionHandlers.Add (eh);
  247. }
  248. } else {
  249. br.BaseStream.Position--;
  250. int length = (br.ReadInt32 () >> 8) / 24;
  251. if ((flags & (int) MethodDataSection.EHTable) == 0)
  252. br.ReadBytes (length * 24);
  253. for (int i = 0; i < length; i++) {
  254. ExceptionHandler eh = new ExceptionHandler (
  255. (ExceptionHandlerType) (br.ReadInt32 () & 0x7));
  256. eh.TryStart = GetInstruction (body, br.ReadInt32 ());
  257. eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + br.ReadInt32 ());
  258. eh.HandlerStart = GetInstruction (body, br.ReadInt32 ());
  259. eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + br.ReadInt32 ());
  260. ReadExceptionHandlerEnd (eh, br, body);
  261. body.ExceptionHandlers.Add (eh);
  262. }
  263. }
  264. if ((flags & (byte) MethodDataSection.MoreSects) != 0)
  265. ReadSection (body, br);
  266. }
  267. void ReadExceptionHandlerEnd (ExceptionHandler eh, BinaryReader br, MethodBody body)
  268. {
  269. switch (eh.Type) {
  270. case ExceptionHandlerType.Catch :
  271. MetadataToken token = new MetadataToken (br.ReadInt32 ());
  272. eh.CatchType = m_reflectReader.GetTypeDefOrRef (token, new GenericContext (body.Method));
  273. break;
  274. case ExceptionHandlerType.Filter :
  275. eh.FilterStart = GetInstruction (body, br.ReadInt32 ());
  276. eh.FilterEnd = GetInstruction (body, eh.HandlerStart.Previous.Offset);
  277. break;
  278. default :
  279. br.ReadInt32 ();
  280. break;
  281. }
  282. }
  283. CallSite GetCallSiteAt (int token, GenericContext context)
  284. {
  285. StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
  286. MethodSig ms = m_reflectReader.SigReader.GetStandAloneMethodSig (
  287. sasTable [(int) GetRid (token) - 1].Signature);
  288. CallSite cs = new CallSite (ms.HasThis, ms.ExplicitThis,
  289. ms.MethCallConv, m_reflectReader.GetMethodReturnType (ms, context));
  290. cs.MetadataToken = new MetadataToken (token);
  291. for (int i = 0; i < ms.ParamCount; i++) {
  292. Param p = ms.Parameters [i];
  293. cs.Parameters.Add (m_reflectReader.BuildParameterDefinition (i, p, context));
  294. }
  295. ReflectionReader.CreateSentinelIfNeeded (cs, ms);
  296. return cs;
  297. }
  298. public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables)
  299. {
  300. MethodBody body = variables.Container as MethodBody;
  301. if (body == null || body.LocalVarToken == 0)
  302. return;
  303. StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
  304. StandAloneSigRow sasRow = sasTable [(int) GetRid (body.LocalVarToken) - 1];
  305. LocalVarSig sig = m_reflectReader.SigReader.GetLocalVarSig (sasRow.Signature);
  306. for (int i = 0; i < sig.Count; i++) {
  307. LocalVarSig.LocalVariable lv = sig.LocalVariables [i];
  308. TypeReference varType = m_reflectReader.GetTypeRefFromSig (
  309. lv.Type, new GenericContext (body.Method));
  310. if (lv.ByRef)
  311. varType = new ReferenceType (varType);
  312. if ((lv.Constraint & Constraint.Pinned) != 0)
  313. varType = new PinnedType (varType);
  314. varType = m_reflectReader.GetModifierType (lv.CustomMods, varType);
  315. body.Variables.Add (new VariableDefinition (
  316. string.Concat ("V_", i), i, body.Method, varType));
  317. }
  318. }
  319. }
  320. }