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 sealed 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 if (methBody
.LocalVarToken
!= 0)
75 VisitVariableDefinitionCollection (methBody
.Variables
);
76 ReadCilBody (methBody
, br
);
77 if ((fatflags
& (int) MethodHeader
.MoreSects
) != 0)
78 ReadSection (methBody
, br
);
83 public static uint GetRid (int token
)
85 return (uint) token
& 0x00ffffff;
88 public static ParameterDefinition
GetParameter (MethodBody body
, int index
)
90 if (body
.Method
.HasThis
) {
92 return body
.Method
.This
;
96 return body
.Method
.Parameters
[index
];
99 public static VariableDefinition
GetVariable (MethodBody body
, int index
)
101 return body
.Variables
[index
];
104 void ReadCilBody (MethodBody body
, BinaryReader br
)
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
);
112 while (br
.BaseStream
.Position
< start
+ body
.CodeSize
) {
114 long offset
= br
.BaseStream
.Position
- start
;
115 int cursor
= br
.ReadByte ();
117 op
= OpCodes
.TwoBytesOpCode
[br
.ReadByte ()];
119 op
= OpCodes
.OneByteOpCode
[cursor
];
121 Instruction instr
= new Instruction ((int) offset
, op
);
122 switch (op
.OperandType
) {
123 case OperandType
.InlineNone
:
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
;
135 case OperandType
.ShortInlineBrTarget
:
136 sbyte sbrtgt
= br
.ReadSByte ();
137 instr
.Operand
= Convert
.ToInt32 (br
.BaseStream
.Position
- start
+ sbrtgt
);
139 case OperandType
.InlineBrTarget
:
140 int brtgt
= br
.ReadInt32 ();
141 instr
.Operand
= Convert
.ToInt32 (br
.BaseStream
.Position
- start
+ brtgt
);
143 case OperandType
.ShortInlineI
:
144 if (op
== OpCodes
.Ldc_I4_S
)
145 instr
.Operand
= br
.ReadSByte ();
147 instr
.Operand
= br
.ReadByte ();
149 case OperandType
.ShortInlineVar
:
150 instr
.Operand
= GetVariable (body
, br
.ReadByte ());
152 case OperandType
.ShortInlineParam
:
153 instr
.Operand
= GetParameter (body
, br
.ReadByte ());
155 case OperandType
.InlineSig
:
156 instr
.Operand
= GetCallSiteAt (br
.ReadInt32 (), context
);
158 case OperandType
.InlineI
:
159 instr
.Operand
= br
.ReadInt32 ();
161 case OperandType
.InlineVar
:
162 instr
.Operand
= GetVariable (body
, br
.ReadInt16 ());
164 case OperandType
.InlineParam
:
165 instr
.Operand
= GetParameter (body
, br
.ReadInt16 ());
167 case OperandType
.InlineI8
:
168 instr
.Operand
= br
.ReadInt64 ();
170 case OperandType
.ShortInlineR
:
171 instr
.Operand
= br
.ReadSingle ();
173 case OperandType
.InlineR
:
174 instr
.Operand
= br
.ReadDouble ();
176 case OperandType
.InlineString
:
177 instr
.Operand
= m_root
.Streams
.UserStringsHeap
[GetRid (br
.ReadInt32 ())];
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
);
188 case TokenType
.TypeRef
:
189 instr
.Operand
= m_reflectReader
.GetTypeRefAt (token
.RID
);
191 case TokenType
.TypeSpec
:
192 instr
.Operand
= m_reflectReader
.GetTypeSpecAt (token
.RID
, context
);
194 case TokenType
.Field
:
195 instr
.Operand
= m_reflectReader
.GetFieldDefAt (token
.RID
);
197 case TokenType
.Method
:
198 instr
.Operand
= m_reflectReader
.GetMethodDefAt (token
.RID
);
200 case TokenType
.MethodSpec
:
201 instr
.Operand
= m_reflectReader
.GetMethodSpecAt (token
.RID
, context
);
203 case TokenType
.MemberRef
:
204 instr
.Operand
= m_reflectReader
.GetMemberRefAt (token
.RID
, context
);
207 throw new ReflectionException ("Wrong token: " + token
);
212 m_instructions
.Add (instr
.Offset
, instr
);
216 instr
.Previous
= last
;
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
);
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
]);
241 if (m_reflectReader
.SymbolReader
!= null)
242 m_reflectReader
.SymbolReader
.Read (body
, m_instructions
);
245 Instruction
GetInstruction (MethodBody body
, int offset
)
247 Instruction instruction
= m_instructions
[offset
] as Instruction
;
248 if (instruction
!= null)
251 return body
.Instructions
.Outside
;
254 void ReadSection (MethodBody body
, BinaryReader br
)
256 br
.BaseStream
.Position
+= 3;
257 br
.BaseStream
.Position
&= ~
3;
259 byte flags
= br
.ReadByte ();
260 if ((flags
& (byte) MethodDataSection
.FatFormat
) == 0) {
261 int length
= br
.ReadByte () / 12;
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
);
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
);
291 if ((flags
& (byte) MethodDataSection
.MoreSects
) != 0)
292 ReadSection (body
, br
);
295 void ReadExceptionHandlerEnd (ExceptionHandler eh
, BinaryReader br
, MethodBody body
)
298 case ExceptionHandlerType
.Catch
:
299 MetadataToken token
= new MetadataToken (br
.ReadInt32 ());
300 eh
.CatchType
= m_reflectReader
.GetTypeDefOrRef (token
, new GenericContext (body
.Method
));
302 case ExceptionHandlerType
.Filter
:
303 eh
.FilterStart
= GetInstruction (body
, br
.ReadInt32 ());
304 eh
.FilterEnd
= GetInstruction (body
, eh
.HandlerStart
.Previous
.Offset
);
312 CallSite
GetCallSiteAt (int token
, GenericContext context
)
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
);
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
));
326 ReflectionReader
.CreateSentinelIfNeeded (cs
, ms
);
331 public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables
)
333 MethodBody body
= variables
.Container
as MethodBody
;
334 if (body
== null || body
.LocalVarToken
== 0)
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
));
346 varType
= new ReferenceType (varType
);
347 if ((lv
.Constraint
& Constraint
.Pinned
) != 0)
348 varType
= new PinnedType (varType
);
350 varType
= m_reflectReader
.GetModifierType (lv
.CustomMods
, varType
);
352 body
.Variables
.Add (new VariableDefinition (
353 string.Concat ("V_", i
), i
, body
.Method
, varType
));