PageRenderTime 40ms CodeModel.GetById 22ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/luobailiang/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
 29namespace Mono.Cecil.Cil {
 30
 31	using System;
 32	using System.Collections;
 33	using System.IO;
 34
 35	using Mono.Cecil;
 36	using Mono.Cecil.Metadata;
 37	using Mono.Cecil.Signatures;
 38
 39	sealed class CodeReader : BaseCodeVisitor {
 40
 41		ReflectionReader m_reflectReader;
 42		MetadataRoot m_root;
 43		IDictionary m_instructions;
 44
 45		public CodeReader (ReflectionReader reflectReader)
 46		{
 47			m_reflectReader = reflectReader;
 48			m_root = m_reflectReader.MetadataRoot;
 49			m_instructions = new Hashtable ();
 50		}
 51
 52		public override void VisitMethodBody (MethodBody body)
 53		{
 54			MethodDefinition meth = body.Method;
 55			MethodBody methBody = body;
 56			BinaryReader br = m_reflectReader.Module.ImageReader.MetadataReader.GetDataReader (meth.RVA);
 57
 58			// lets read the method
 59			int flags = br.ReadByte ();
 60			switch (flags & 0x3) {
 61			case (int) MethodHeader.TinyFormat :
 62				methBody.CodeSize = flags >> 2;
 63				methBody.MaxStack = 8;
 64				ReadCilBody (methBody, br);
 65				break;
 66			case (int) MethodHeader.FatFormat :
 67				br.BaseStream.Position--;
 68				int fatflags = br.ReadUInt16 ();
 69				//int headersize = (fatflags >> 12) & 0xf;
 70				methBody.MaxStack = br.ReadUInt16 ();
 71				methBody.CodeSize = br.ReadInt32 ();
 72				methBody.LocalVarToken = br.ReadInt32 ();
 73				body.InitLocals = (fatflags & (int) MethodHeader.InitLocals) != 0;
 74				if (methBody.LocalVarToken != 0)
 75					VisitVariableDefinitionCollection (methBody.Variables);
 76				ReadCilBody (methBody, br);
 77				if ((fatflags & (int) MethodHeader.MoreSects) != 0)
 78					ReadSection (methBody, br);
 79				break;
 80			}
 81		}
 82
 83		public static uint GetRid (int token)
 84		{
 85			return (uint) token & 0x00ffffff;
 86		}
 87
 88		public static ParameterDefinition GetParameter (MethodBody body, int index)
 89		{
 90			if (body.Method.HasThis) {
 91				if (index == 0)
 92					return body.Method.This;
 93				index--;
 94			}
 95
 96			return body.Method.Parameters [index];
 97		}
 98
 99		public static VariableDefinition GetVariable (MethodBody body, int index)
100		{
101			return body.Variables [index];
102		}
103
104		void ReadCilBody (MethodBody body, BinaryReader br)
105		{
106			long start = br.BaseStream.Position;
107			Instruction last = null;
108			m_instructions.Clear();
109			InstructionCollection code = body.Instructions;
110			GenericContext context = new GenericContext (body.Method);
111
112			while (br.BaseStream.Position < start + body.CodeSize) {
113				OpCode op;
114				long offset = br.BaseStream.Position - start;
115				int cursor = br.ReadByte ();
116				if (cursor == 0xfe)
117					op = OpCodes.TwoBytesOpCode [br.ReadByte ()];
118				else
119					op = OpCodes.OneByteOpCode [cursor];
120
121				Instruction instr = new Instruction ((int) offset, op);
122				switch (op.OperandType) {
123				case OperandType.InlineNone :
124					break;
125				case OperandType.InlineSwitch :
126					uint length = br.ReadUInt32 ();
127					int [] branches = new int [length];
128					int [] buf = new int [length];
129					for (int i = 0; i < length; i++)
130						buf [i] = br.ReadInt32 ();
131					for (int i = 0; i < length; i++)
132						branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
133					instr.Operand = branches;
134					break;
135				case OperandType.ShortInlineBrTarget :
136					sbyte sbrtgt = br.ReadSByte ();
137					instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
138					break;
139				case OperandType.InlineBrTarget :
140					int brtgt = br.ReadInt32 ();
141					instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
142					break;
143				case OperandType.ShortInlineI :
144					if (op == OpCodes.Ldc_I4_S)
145						instr.Operand = br.ReadSByte ();
146					else
147						instr.Operand = br.ReadByte ();
148					break;
149				case OperandType.ShortInlineVar :
150					instr.Operand = GetVariable (body, br.ReadByte ());
151					break;
152				case OperandType.ShortInlineParam :
153					instr.Operand = GetParameter (body, br.ReadByte ());
154					break;
155				case OperandType.InlineSig :
156					instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
157					break;
158				case OperandType.InlineI :
159					instr.Operand = br.ReadInt32 ();
160					break;
161				case OperandType.InlineVar :
162					instr.Operand = GetVariable (body, br.ReadInt16 ());
163					break;
164				case OperandType.InlineParam :
165					instr.Operand = GetParameter (body, br.ReadInt16 ());
166					break;
167				case OperandType.InlineI8 :
168					instr.Operand = br.ReadInt64 ();
169					break;
170				case OperandType.ShortInlineR :
171					instr.Operand = br.ReadSingle ();
172					break;
173				case OperandType.InlineR :
174					instr.Operand = br.ReadDouble ();
175					break;
176				case OperandType.InlineString :
177					instr.Operand = m_root.Streams.UserStringsHeap [GetRid (br.ReadInt32 ())];
178					break;
179				case OperandType.InlineField :
180				case OperandType.InlineMethod :
181				case OperandType.InlineType :
182				case OperandType.InlineTok :
183					MetadataToken token = new MetadataToken (br.ReadInt32 ());
184					switch (token.TokenType) {
185					case TokenType.TypeDef:
186						instr.Operand = m_reflectReader.GetTypeDefAt (token.RID);
187						break;
188					case TokenType.TypeRef:
189						instr.Operand = m_reflectReader.GetTypeRefAt (token.RID);
190						break;
191					case TokenType.TypeSpec:
192						instr.Operand = m_reflectReader.GetTypeSpecAt (token.RID, context);
193						break;
194					case TokenType.Field:
195						instr.Operand = m_reflectReader.GetFieldDefAt (token.RID);
196						break;
197					case TokenType.Method:
198						instr.Operand = m_reflectReader.GetMethodDefAt (token.RID);
199						break;
200					case TokenType.MethodSpec:
201						instr.Operand = m_reflectReader.GetMethodSpecAt (token.RID, context);
202						break;
203					case TokenType.MemberRef:
204						instr.Operand = m_reflectReader.GetMemberRefAt (token.RID, context);
205						break;
206					default:
207						throw new ReflectionException ("Wrong token: " + token);
208					}
209					break;
210				}
211
212				m_instructions.Add (instr.Offset, instr);
213
214				if (last != null) {
215					last.Next = instr;
216					instr.Previous = last;
217				}
218
219				last = instr;
220
221				code.Add (instr);
222			}
223
224			// resolve branches
225			foreach (Instruction i in code) {
226				switch (i.OpCode.OperandType) {
227				case OperandType.ShortInlineBrTarget:
228				case OperandType.InlineBrTarget:
229					i.Operand = GetInstruction (body, (int) i.Operand);
230					break;
231				case OperandType.InlineSwitch:
232					int [] lbls = (int []) i.Operand;
233					Instruction [] instrs = new Instruction [lbls.Length];
234					for (int j = 0; j < lbls.Length; j++)
235						instrs [j] = GetInstruction (body, lbls [j]);
236					i.Operand = instrs;
237					break;
238				}
239			}
240
241			if (m_reflectReader.SymbolReader != null)
242				m_reflectReader.SymbolReader.Read (body, m_instructions);
243		}
244
245		Instruction GetInstruction (MethodBody body, int offset)
246		{
247			Instruction instruction = m_instructions [offset] as Instruction;
248			if (instruction != null)
249				return instruction;
250
251			return body.Instructions.Outside;
252		}
253
254		void ReadSection (MethodBody body, BinaryReader br)
255		{
256			br.BaseStream.Position += 3;
257			br.BaseStream.Position &= ~3;
258
259			byte flags = br.ReadByte ();
260			if ((flags & (byte) MethodDataSection.FatFormat) == 0) {
261				int length = br.ReadByte () / 12;
262				br.ReadBytes (2);
263
264				for (int i = 0; i < length; i++) {
265					ExceptionHandler eh = new ExceptionHandler (
266						(ExceptionHandlerType) (br.ReadInt16 () & 0x7));
267					eh.TryStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
268					eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + Convert.ToInt32 (br.ReadByte ()));
269					eh.HandlerStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
270					eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + Convert.ToInt32 (br.ReadByte ()));
271					ReadExceptionHandlerEnd (eh, br, body);
272					body.ExceptionHandlers.Add (eh);
273				}
274			} else {
275				br.BaseStream.Position--;
276				int length = (br.ReadInt32 () >> 8) / 24;
277				if ((flags & (int) MethodDataSection.EHTable) == 0)
278					br.ReadBytes (length * 24);
279				for (int i = 0; i < length; i++) {
280					ExceptionHandler eh = new ExceptionHandler (
281						(ExceptionHandlerType) (br.ReadInt32 () & 0x7));
282					eh.TryStart = GetInstruction (body, br.ReadInt32 ());
283					eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + br.ReadInt32 ());
284					eh.HandlerStart = GetInstruction (body, br.ReadInt32 ());
285					eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + br.ReadInt32 ());
286					ReadExceptionHandlerEnd (eh, br, body);
287					body.ExceptionHandlers.Add (eh);
288				}
289			}
290
291			if ((flags & (byte) MethodDataSection.MoreSects) != 0)
292				ReadSection (body, br);
293		}
294
295		void ReadExceptionHandlerEnd (ExceptionHandler eh, BinaryReader br, MethodBody body)
296		{
297			switch (eh.Type) {
298			case ExceptionHandlerType.Catch :
299				MetadataToken token = new MetadataToken (br.ReadInt32 ());
300				eh.CatchType = m_reflectReader.GetTypeDefOrRef (token, new GenericContext (body.Method));
301				break;
302			case ExceptionHandlerType.Filter :
303				eh.FilterStart = GetInstruction (body, br.ReadInt32 ());
304				eh.FilterEnd = GetInstruction (body, eh.HandlerStart.Previous.Offset);
305				break;
306			default :
307				br.ReadInt32 ();
308				break;
309			}
310		}
311
312		CallSite GetCallSiteAt (int token, GenericContext context)
313		{
314			StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
315			MethodSig ms = m_reflectReader.SigReader.GetStandAloneMethodSig (
316				sasTable [(int) GetRid (token) - 1].Signature);
317			CallSite cs = new CallSite (ms.HasThis, ms.ExplicitThis,
318				ms.MethCallConv, m_reflectReader.GetMethodReturnType (ms, context));
319			cs.MetadataToken = new MetadataToken (token);
320
321			for (int i = 0; i < ms.ParamCount; i++) {
322				Param p = ms.Parameters [i];
323				cs.Parameters.Add (m_reflectReader.BuildParameterDefinition (i, p, context));
324			}
325
326			ReflectionReader.CreateSentinelIfNeeded (cs, ms);
327
328			return cs;
329		}
330
331		public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables)
332		{
333			MethodBody body = variables.Container as MethodBody;
334			if (body == null || body.LocalVarToken == 0)
335				return;
336
337			StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
338			StandAloneSigRow sasRow = sasTable [(int) GetRid (body.LocalVarToken) - 1];
339			LocalVarSig sig = m_reflectReader.SigReader.GetLocalVarSig (sasRow.Signature);
340			for (int i = 0; i < sig.Count; i++) {
341				LocalVarSig.LocalVariable lv = sig.LocalVariables [i];
342				TypeReference varType = m_reflectReader.GetTypeRefFromSig (
343					lv.Type, new GenericContext (body.Method));
344
345				if (lv.ByRef)
346					varType = new ReferenceType (varType);
347				if ((lv.Constraint & Constraint.Pinned) != 0)
348					varType = new PinnedType (varType);
349
350				varType = m_reflectReader.GetModifierType (lv.CustomMods, varType);
351
352				body.Variables.Add (new VariableDefinition (
353						string.Concat ("V_", i), i, body.Method, varType));
354			}
355		}
356	}
357}