5 // Jb Evain (jbevain@gmail.com)
7 // (C) 2005 - 2007 Jb Evain
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 namespace Mono.Cecil.Cil {
32 using System.Collections;
36 using Mono.Cecil.Metadata;
37 using Mono.Cecil.Signatures;
39 class CodeReader : BaseCodeVisitor {
41 ReflectionReader m_reflectReader;
44 public CodeReader (ReflectionReader reflectReader)
46 m_reflectReader = reflectReader;
47 m_root = m_reflectReader.MetadataRoot;
50 public override void VisitMethodBody (MethodBody body)
52 MethodDefinition meth = body.Method;
53 MethodBody methBody = body;
54 BinaryReader br = m_reflectReader.Module.ImageReader.MetadataReader.GetDataReader (meth.RVA);
56 // lets read the method
58 int flags = br.ReadByte ();
59 switch (flags & 0x3) {
60 case (int) MethodHeader.TinyFormat :
61 methBody.CodeSize = flags >> 2;
62 methBody.MaxStack = 8;
63 ReadCilBody (methBody, br, out instrs);
65 case (int) MethodHeader.FatFormat :
66 br.BaseStream.Position--;
67 int fatflags = br.ReadUInt16 ();
68 //int headersize = (fatflags >> 12) & 0xf;
69 methBody.MaxStack = br.ReadUInt16 ();
70 methBody.CodeSize = br.ReadInt32 ();
71 methBody.LocalVarToken = br.ReadInt32 ();
72 body.InitLocals = (fatflags & (int) MethodHeader.InitLocals) != 0;
73 VisitVariableDefinitionCollection (methBody.Variables);
74 ReadCilBody (methBody, br, out instrs);
75 if ((fatflags & (int) MethodHeader.MoreSects) != 0)
76 ReadSection (methBody, br, instrs);
80 if (m_reflectReader.SymbolReader != null)
81 m_reflectReader.SymbolReader.Read (methBody);
84 public static uint GetRid (int token)
86 return (uint) token & 0x00ffffff;
89 public static ParameterDefinition GetParameter (MethodBody body, int index)
91 if (body.Method.HasThis) {
93 return body.Method.This;
97 return body.Method.Parameters [index];
100 public static VariableDefinition GetVariable (MethodBody body, int index)
102 return body.Variables [index];
105 void ReadCilBody (MethodBody body, BinaryReader br, out IDictionary instructions)
107 long start = br.BaseStream.Position;
108 Instruction last = null;
109 InstructionCollection code = body.Instructions;
110 instructions = new Hashtable ();
111 GenericContext context = new GenericContext (body.Method);
113 while (br.BaseStream.Position < start + body.CodeSize) {
115 long offset = br.BaseStream.Position - start;
116 int cursor = br.ReadByte ();
118 op = OpCodes.TwoBytesOpCode [br.ReadByte ()];
120 op = OpCodes.OneByteOpCode [cursor];
122 Instruction instr = new Instruction ((int) offset, op);
123 switch (op.OperandType) {
124 case OperandType.InlineNone :
126 case OperandType.InlineSwitch :
127 uint length = br.ReadUInt32 ();
128 int [] branches = new int [length];
129 int [] buf = new int [length];
130 for (int i = 0; i < length; i++)
131 buf [i] = br.ReadInt32 ();
132 for (int i = 0; i < length; i++)
133 branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
134 instr.Operand = branches;
136 case OperandType.ShortInlineBrTarget :
137 sbyte sbrtgt = br.ReadSByte ();
138 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
140 case OperandType.InlineBrTarget :
141 int brtgt = br.ReadInt32 ();
142 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
144 case OperandType.ShortInlineI :
145 if (op == OpCodes.Ldc_I4_S)
146 instr.Operand = br.ReadSByte ();
148 instr.Operand = br.ReadByte ();
150 case OperandType.ShortInlineVar :
151 instr.Operand = GetVariable (body, br.ReadByte ());
153 case OperandType.ShortInlineParam :
154 instr.Operand = GetParameter (body, br.ReadByte ());
156 case OperandType.InlineSig :
157 instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
159 case OperandType.InlineI :
160 instr.Operand = br.ReadInt32 ();
162 case OperandType.InlineVar :
163 instr.Operand = GetVariable (body, br.ReadInt16 ());
165 case OperandType.InlineParam :
166 instr.Operand = GetParameter (body, br.ReadInt16 ());
168 case OperandType.InlineI8 :
169 instr.Operand = br.ReadInt64 ();
171 case OperandType.ShortInlineR :
172 instr.Operand = br.ReadSingle ();
174 case OperandType.InlineR :
175 instr.Operand = br.ReadDouble ();
177 case OperandType.InlineString :
178 instr.Operand = m_root.Streams.UserStringsHeap [GetRid (br.ReadInt32 ())];
180 case OperandType.InlineField :
181 case OperandType.InlineMethod :
182 case OperandType.InlineType :
183 case OperandType.InlineTok :
184 MetadataToken token = new MetadataToken (br.ReadInt32 ());
185 switch (token.TokenType) {
186 case TokenType.TypeDef:
187 instr.Operand = m_reflectReader.GetTypeDefAt (token.RID);
189 case TokenType.TypeRef:
190 instr.Operand = m_reflectReader.GetTypeRefAt (token.RID);
192 case TokenType.TypeSpec:
193 instr.Operand = m_reflectReader.GetTypeSpecAt (token.RID, context);
195 case TokenType.Field:
196 instr.Operand = m_reflectReader.GetFieldDefAt (token.RID);
198 case TokenType.Method:
199 instr.Operand = m_reflectReader.GetMethodDefAt (token.RID);
201 case TokenType.MethodSpec:
202 instr.Operand = m_reflectReader.GetMethodSpecAt (token.RID, context);
204 case TokenType.MemberRef:
205 instr.Operand = m_reflectReader.GetMemberRefAt (token.RID, context);
208 throw new ReflectionException ("Wrong token: " + token);
213 instructions.Add (instr.Offset, instr);
217 instr.Previous = last;
226 foreach (Instruction i in code) {
227 switch (i.OpCode.OperandType) {
228 case OperandType.ShortInlineBrTarget:
229 case OperandType.InlineBrTarget:
230 i.Operand = GetInstruction (body, instructions, (int) i.Operand);
232 case OperandType.InlineSwitch:
233 int [] lbls = (int []) i.Operand;
234 Instruction [] instrs = new Instruction [lbls.Length];
235 for (int j = 0; j < lbls.Length; j++)
236 instrs [j] = GetInstruction (body, instructions, lbls [j]);
243 static Instruction GetInstruction (MethodBody body, IDictionary instructions, int offset)
245 Instruction instruction = instructions [offset] as Instruction;
246 if (instruction != null)
249 return body.Instructions.Outside;
252 void ReadSection (MethodBody body, BinaryReader br, IDictionary instructions)
254 br.BaseStream.Position += 3;
255 br.BaseStream.Position &= ~3;
257 byte flags = br.ReadByte ();
258 if ((flags & (byte) MethodDataSection.FatFormat) == 0) {
259 int length = br.ReadByte () / 12;
262 for (int i = 0; i < length; i++) {
263 ExceptionHandler eh = new ExceptionHandler (
264 (ExceptionHandlerType) (br.ReadInt16 () & 0x7));
265 eh.TryStart = GetInstruction (body, instructions, Convert.ToInt32 (br.ReadInt16 ()));
266 eh.TryEnd = GetInstruction (body, instructions, eh.TryStart.Offset + Convert.ToInt32 (br.ReadByte ()));
267 eh.HandlerStart = GetInstruction (body, instructions, Convert.ToInt32 (br.ReadInt16 ()));
268 eh.HandlerEnd = GetInstruction (body, instructions, eh.HandlerStart.Offset + Convert.ToInt32 (br.ReadByte ()));
269 ReadExceptionHandlerEnd (eh, br, body, instructions);
270 body.ExceptionHandlers.Add (eh);
273 br.BaseStream.Position--;
274 int length = (br.ReadInt32 () >> 8) / 24;
275 if ((flags & (int) MethodDataSection.EHTable) == 0)
276 br.ReadBytes (length * 24);
277 for (int i = 0; i < length; i++) {
278 ExceptionHandler eh = new ExceptionHandler (
279 (ExceptionHandlerType) (br.ReadInt32 () & 0x7));
280 eh.TryStart = GetInstruction (body, instructions, br.ReadInt32 ());
281 eh.TryEnd = GetInstruction (body, instructions, eh.TryStart.Offset + br.ReadInt32 ());
282 eh.HandlerStart = GetInstruction (body, instructions, br.ReadInt32 ());
283 eh.HandlerEnd = GetInstruction (body, instructions, eh.HandlerStart.Offset + br.ReadInt32 ());
284 ReadExceptionHandlerEnd(eh, br, body, instructions);
285 body.ExceptionHandlers.Add (eh);
289 if ((flags & (byte) MethodDataSection.MoreSects) != 0)
290 ReadSection (body, br, instructions);
293 void ReadExceptionHandlerEnd (ExceptionHandler eh, BinaryReader br, MethodBody body, IDictionary instructions)
296 case ExceptionHandlerType.Catch :
297 MetadataToken token = new MetadataToken (br.ReadInt32 ());
298 switch (token.TokenType) {
299 case TokenType.TypeDef:
300 eh.CatchType = m_reflectReader.GetTypeDefAt (token.RID);
303 eh.CatchType = m_reflectReader.GetTypeRefAt (token.RID);
307 case ExceptionHandlerType.Filter :
308 eh.FilterStart = GetInstruction (body, instructions, br.ReadInt32 ());
309 eh.FilterEnd = GetInstruction (body, instructions, eh.HandlerStart.Previous.Offset);
317 CallSite GetCallSiteAt (int token, GenericContext context)
319 StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
320 MethodSig ms = m_reflectReader.SigReader.GetStandAloneMethodSig (
321 sasTable [(int) GetRid (token) - 1].Signature);
322 CallSite cs = new CallSite (ms.HasThis, ms.ExplicitThis,
323 ms.MethCallConv, m_reflectReader.GetMethodReturnType (ms, context));
324 cs.MetadataToken = new MetadataToken (token);
326 for (int i = 0; i < ms.ParamCount; i++) {
327 Param p = ms.Parameters [i];
328 cs.Parameters.Add (m_reflectReader.BuildParameterDefinition (
329 string.Concat ("A_", i),
330 i, (ParameterAttributes) 0,
334 MethodRefSig refSig = ms as MethodRefSig;
335 if (refSig != null && refSig.Sentinel >= 0)
336 ReflectionReader.CreateSentinel (cs, refSig.Sentinel);
341 public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables)
343 MethodBody body = variables.Container as MethodBody;
344 if (body == null || body.LocalVarToken == 0)
347 StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
348 StandAloneSigRow sasRow = sasTable [(int) GetRid (body.LocalVarToken) - 1];
349 LocalVarSig sig = m_reflectReader.SigReader.GetLocalVarSig (sasRow.Signature);
350 for (int i = 0; i < sig.Count; i++) {
351 LocalVarSig.LocalVariable lv = sig.LocalVariables [i];
352 TypeReference varType = m_reflectReader.GetTypeRefFromSig (
353 lv.Type, new GenericContext (body.Method));
356 varType = new ReferenceType (varType);
357 if ((lv.Constraint & Constraint.Pinned) != 0)
358 varType = new PinnedType (varType);
360 if (lv.CustomMods.Length > 0)
361 varType = m_reflectReader.GetModifierType (lv.CustomMods, varType);
363 body.Variables.Add (new VariableDefinition (
364 string.Concat ("V_", i), i, body.Method, varType));