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;
43 IDictionary m_instructions;
45 public CodeReader (ReflectionReader reflectReader)
47 m_reflectReader = reflectReader;
48 m_root = m_reflectReader.MetadataRoot;
49 m_instructions = new Hashtable ();
52 public override void VisitMethodBody (MethodBody body)
54 MethodDefinition meth = body.Method;
55 MethodBody methBody = body;
56 BinaryReader br = m_reflectReader.Module.ImageReader.MetadataReader.GetDataReader (meth.RVA);
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);
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 VisitVariableDefinitionCollection (methBody.Variables);
75 ReadCilBody (methBody, br);
76 if ((fatflags & (int) MethodHeader.MoreSects) != 0)
77 ReadSection (methBody, br);
81 if (m_reflectReader.SymbolReader != null)
82 m_reflectReader.SymbolReader.Read (methBody);
85 public static uint GetRid (int token)
87 return (uint) token & 0x00ffffff;
90 public static ParameterDefinition GetParameter (MethodBody body, int index)
92 if (body.Method.HasThis) {
94 return body.Method.This;
98 return body.Method.Parameters [index];
101 public static VariableDefinition GetVariable (MethodBody body, int index)
103 return body.Variables [index];
106 void ReadCilBody (MethodBody body, BinaryReader br)
108 long start = br.BaseStream.Position;
109 Instruction last = null;
110 m_instructions.Clear();
111 InstructionCollection code = body.Instructions;
112 GenericContext context = new GenericContext (body.Method);
114 while (br.BaseStream.Position < start + body.CodeSize) {
116 long offset = br.BaseStream.Position - start;
117 int cursor = br.ReadByte ();
119 op = OpCodes.TwoBytesOpCode [br.ReadByte ()];
121 op = OpCodes.OneByteOpCode [cursor];
123 Instruction instr = new Instruction ((int) offset, op);
124 switch (op.OperandType) {
125 case OperandType.InlineNone :
127 case OperandType.InlineSwitch :
128 uint length = br.ReadUInt32 ();
129 int [] branches = new int [length];
130 int [] buf = new int [length];
131 for (int i = 0; i < length; i++)
132 buf [i] = br.ReadInt32 ();
133 for (int i = 0; i < length; i++)
134 branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
135 instr.Operand = branches;
137 case OperandType.ShortInlineBrTarget :
138 sbyte sbrtgt = br.ReadSByte ();
139 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
141 case OperandType.InlineBrTarget :
142 int brtgt = br.ReadInt32 ();
143 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
145 case OperandType.ShortInlineI :
146 if (op == OpCodes.Ldc_I4_S)
147 instr.Operand = br.ReadSByte ();
149 instr.Operand = br.ReadByte ();
151 case OperandType.ShortInlineVar :
152 instr.Operand = GetVariable (body, br.ReadByte ());
154 case OperandType.ShortInlineParam :
155 instr.Operand = GetParameter (body, br.ReadByte ());
157 case OperandType.InlineSig :
158 instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
160 case OperandType.InlineI :
161 instr.Operand = br.ReadInt32 ();
163 case OperandType.InlineVar :
164 instr.Operand = GetVariable (body, br.ReadInt16 ());
166 case OperandType.InlineParam :
167 instr.Operand = GetParameter (body, br.ReadInt16 ());
169 case OperandType.InlineI8 :
170 instr.Operand = br.ReadInt64 ();
172 case OperandType.ShortInlineR :
173 instr.Operand = br.ReadSingle ();
175 case OperandType.InlineR :
176 instr.Operand = br.ReadDouble ();
178 case OperandType.InlineString :
179 instr.Operand = m_root.Streams.UserStringsHeap [GetRid (br.ReadInt32 ())];
181 case OperandType.InlineField :
182 case OperandType.InlineMethod :
183 case OperandType.InlineType :
184 case OperandType.InlineTok :
185 MetadataToken token = new MetadataToken (br.ReadInt32 ());
186 switch (token.TokenType) {
187 case TokenType.TypeDef:
188 instr.Operand = m_reflectReader.GetTypeDefAt (token.RID);
190 case TokenType.TypeRef:
191 instr.Operand = m_reflectReader.GetTypeRefAt (token.RID);
193 case TokenType.TypeSpec:
194 instr.Operand = m_reflectReader.GetTypeSpecAt (token.RID, context);
196 case TokenType.Field:
197 instr.Operand = m_reflectReader.GetFieldDefAt (token.RID);
199 case TokenType.Method:
200 instr.Operand = m_reflectReader.GetMethodDefAt (token.RID);
202 case TokenType.MethodSpec:
203 instr.Operand = m_reflectReader.GetMethodSpecAt (token.RID, context);
205 case TokenType.MemberRef:
206 instr.Operand = m_reflectReader.GetMemberRefAt (token.RID, context);
209 throw new ReflectionException ("Wrong token: " + token);
214 m_instructions.Add (instr.Offset, instr);
218 instr.Previous = last;
227 foreach (Instruction i in code) {
228 switch (i.OpCode.OperandType) {
229 case OperandType.ShortInlineBrTarget:
230 case OperandType.InlineBrTarget:
231 i.Operand = GetInstruction (body, (int) i.Operand);
233 case OperandType.InlineSwitch:
234 int [] lbls = (int []) i.Operand;
235 Instruction [] instrs = new Instruction [lbls.Length];
236 for (int j = 0; j < lbls.Length; j++)
237 instrs [j] = GetInstruction (body, lbls [j]);
244 Instruction GetInstruction (MethodBody body, int offset)
246 Instruction instruction = m_instructions [offset] as Instruction;
247 if (instruction != null)
250 return body.Instructions.Outside;
253 void ReadSection (MethodBody body, BinaryReader br)
255 br.BaseStream.Position += 3;
256 br.BaseStream.Position &= ~3;
258 byte flags = br.ReadByte ();
259 if ((flags & (byte) MethodDataSection.FatFormat) == 0) {
260 int length = br.ReadByte () / 12;
263 for (int i = 0; i < length; i++) {
264 ExceptionHandler eh = new ExceptionHandler (
265 (ExceptionHandlerType) (br.ReadInt16 () & 0x7));
266 eh.TryStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
267 eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + Convert.ToInt32 (br.ReadByte ()));
268 eh.HandlerStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ()));
269 eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + Convert.ToInt32 (br.ReadByte ()));
270 ReadExceptionHandlerEnd (eh, br, body);
271 body.ExceptionHandlers.Add (eh);
274 br.BaseStream.Position--;
275 int length = (br.ReadInt32 () >> 8) / 24;
276 if ((flags & (int) MethodDataSection.EHTable) == 0)
277 br.ReadBytes (length * 24);
278 for (int i = 0; i < length; i++) {
279 ExceptionHandler eh = new ExceptionHandler (
280 (ExceptionHandlerType) (br.ReadInt32 () & 0x7));
281 eh.TryStart = GetInstruction (body, br.ReadInt32 ());
282 eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + br.ReadInt32 ());
283 eh.HandlerStart = GetInstruction (body, br.ReadInt32 ());
284 eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + br.ReadInt32 ());
285 ReadExceptionHandlerEnd (eh, br, body);
286 body.ExceptionHandlers.Add (eh);
290 if ((flags & (byte) MethodDataSection.MoreSects) != 0)
291 ReadSection (body, br);
294 void ReadExceptionHandlerEnd (ExceptionHandler eh, BinaryReader br, MethodBody body)
297 case ExceptionHandlerType.Catch :
298 MetadataToken token = new MetadataToken (br.ReadInt32 ());
299 eh.CatchType = m_reflectReader.GetTypeDefOrRef (token, new GenericContext (body.Method));
301 case ExceptionHandlerType.Filter :
302 eh.FilterStart = GetInstruction (body, br.ReadInt32 ());
303 eh.FilterEnd = GetInstruction (body, eh.HandlerStart.Previous.Offset);
311 CallSite GetCallSiteAt (int token, GenericContext context)
313 StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
314 MethodSig ms = m_reflectReader.SigReader.GetStandAloneMethodSig (
315 sasTable [(int) GetRid (token) - 1].Signature);
316 CallSite cs = new CallSite (ms.HasThis, ms.ExplicitThis,
317 ms.MethCallConv, m_reflectReader.GetMethodReturnType (ms, context));
318 cs.MetadataToken = new MetadataToken (token);
320 for (int i = 0; i < ms.ParamCount; i++) {
321 Param p = ms.Parameters [i];
322 cs.Parameters.Add (m_reflectReader.BuildParameterDefinition (i, p, context));
325 ReflectionReader.CreateSentinelIfNeeded (cs, ms);
330 public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables)
332 MethodBody body = variables.Container as MethodBody;
333 if (body == null || body.LocalVarToken == 0)
336 StandAloneSigTable sasTable = m_reflectReader.TableReader.GetStandAloneSigTable ();
337 StandAloneSigRow sasRow = sasTable [(int) GetRid (body.LocalVarToken) - 1];
338 LocalVarSig sig = m_reflectReader.SigReader.GetLocalVarSig (sasRow.Signature);
339 for (int i = 0; i < sig.Count; i++) {
340 LocalVarSig.LocalVariable lv = sig.LocalVariables [i];
341 TypeReference varType = m_reflectReader.GetTypeRefFromSig (
342 lv.Type, new GenericContext (body.Method));
345 varType = new ReferenceType (varType);
346 if ((lv.Constraint & Constraint.Pinned) != 0)
347 varType = new PinnedType (varType);
349 varType = m_reflectReader.GetModifierType (lv.CustomMods, varType);
351 body.Variables.Add (new VariableDefinition (
352 string.Concat ("V_", i), i, body.Method, varType));