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 // bug 15727 - newer cecil does the same (in MethodDefinition.GetVariable)
102 var variables
= body
.Variables
;
103 if (index
< 0 || index
>= variables
.Count
)
105 return variables
[index
];
108 void ReadCilBody (MethodBody body
, BinaryReader br
)
110 long start
= br
.BaseStream
.Position
;
111 Instruction last
= null;
112 m_instructions
.Clear();
113 InstructionCollection code
= body
.Instructions
;
114 GenericContext context
= new GenericContext (body
.Method
);
116 while (br
.BaseStream
.Position
< start
+ body
.CodeSize
) {
118 long offset
= br
.BaseStream
.Position
- start
;
119 int cursor
= br
.ReadByte ();
121 op
= OpCodes
.TwoBytesOpCode
[br
.ReadByte ()];
123 op
= OpCodes
.OneByteOpCode
[cursor
];
125 Instruction instr
= new Instruction ((int) offset
, op
);
126 switch (op
.OperandType
) {
127 case OperandType
.InlineNone
:
129 case OperandType
.InlineSwitch
:
130 uint length
= br
.ReadUInt32 ();
131 int [] branches
= new int [length
];
132 int [] buf
= new int [length
];
133 for (int i
= 0; i
< length
; i
++)
134 buf
[i
] = br
.ReadInt32 ();
135 for (int i
= 0; i
< length
; i
++)
136 branches
[i
] = Convert
.ToInt32 (br
.BaseStream
.Position
- start
+ buf
[i
]);
137 instr
.Operand
= branches
;
139 case OperandType
.ShortInlineBrTarget
:
140 sbyte sbrtgt
= br
.ReadSByte ();
141 instr
.Operand
= Convert
.ToInt32 (br
.BaseStream
.Position
- start
+ sbrtgt
);
143 case OperandType
.InlineBrTarget
:
144 int brtgt
= br
.ReadInt32 ();
145 instr
.Operand
= Convert
.ToInt32 (br
.BaseStream
.Position
- start
+ brtgt
);
147 case OperandType
.ShortInlineI
:
148 if (op
== OpCodes
.Ldc_I4_S
)
149 instr
.Operand
= br
.ReadSByte ();
151 instr
.Operand
= br
.ReadByte ();
153 case OperandType
.ShortInlineVar
:
154 instr
.Operand
= GetVariable (body
, br
.ReadByte ());
156 case OperandType
.ShortInlineParam
:
157 instr
.Operand
= GetParameter (body
, br
.ReadByte ());
159 case OperandType
.InlineSig
:
160 instr
.Operand
= GetCallSiteAt (br
.ReadInt32 (), context
);
162 case OperandType
.InlineI
:
163 instr
.Operand
= br
.ReadInt32 ();
165 case OperandType
.InlineVar
:
166 instr
.Operand
= GetVariable (body
, br
.ReadInt16 ());
168 case OperandType
.InlineParam
:
169 instr
.Operand
= GetParameter (body
, br
.ReadInt16 ());
171 case OperandType
.InlineI8
:
172 instr
.Operand
= br
.ReadInt64 ();
174 case OperandType
.ShortInlineR
:
175 instr
.Operand
= br
.ReadSingle ();
177 case OperandType
.InlineR
:
178 instr
.Operand
= br
.ReadDouble ();
180 case OperandType
.InlineString
:
181 instr
.Operand
= m_root
.Streams
.UserStringsHeap
[GetRid (br
.ReadInt32 ())];
183 case OperandType
.InlineField
:
184 case OperandType
.InlineMethod
:
185 case OperandType
.InlineType
:
186 case OperandType
.InlineTok
:
187 MetadataToken token
= new MetadataToken (br
.ReadInt32 ());
188 switch (token
.TokenType
) {
189 case TokenType
.TypeDef
:
190 instr
.Operand
= m_reflectReader
.GetTypeDefAt (token
.RID
);
192 case TokenType
.TypeRef
:
193 instr
.Operand
= m_reflectReader
.GetTypeRefAt (token
.RID
);
195 case TokenType
.TypeSpec
:
196 instr
.Operand
= m_reflectReader
.GetTypeSpecAt (token
.RID
, context
);
198 case TokenType
.Field
:
199 instr
.Operand
= m_reflectReader
.GetFieldDefAt (token
.RID
);
201 case TokenType
.Method
:
202 instr
.Operand
= m_reflectReader
.GetMethodDefAt (token
.RID
);
204 case TokenType
.MethodSpec
:
205 instr
.Operand
= m_reflectReader
.GetMethodSpecAt (token
.RID
, context
);
207 case TokenType
.MemberRef
:
208 instr
.Operand
= m_reflectReader
.GetMemberRefAt (token
.RID
, context
);
211 throw new ReflectionException ("Wrong token: " + token
);
216 m_instructions
.Add (instr
.Offset
, instr
);
220 instr
.Previous
= last
;
229 foreach (Instruction i
in code
) {
230 switch (i
.OpCode
.OperandType
) {
231 case OperandType
.ShortInlineBrTarget
:
232 case OperandType
.InlineBrTarget
:
233 i
.Operand
= GetInstruction (body
, (int) i
.Operand
);
235 case OperandType
.InlineSwitch
:
236 int [] lbls
= (int []) i
.Operand
;
237 Instruction
[] instrs
= new Instruction
[lbls
.Length
];
238 for (int j
= 0; j
< lbls
.Length
; j
++)
239 instrs
[j
] = GetInstruction (body
, lbls
[j
]);
245 if (m_reflectReader
.SymbolReader
!= null)
246 m_reflectReader
.SymbolReader
.Read (body
, m_instructions
);
249 Instruction
GetInstruction (MethodBody body
, int offset
)
251 Instruction instruction
= m_instructions
[offset
] as Instruction
;
252 if (instruction
!= null)
255 return body
.Instructions
.Outside
;
258 void ReadSection (MethodBody body
, BinaryReader br
)
260 br
.BaseStream
.Position
+= 3;
261 br
.BaseStream
.Position
&= ~
3;
263 byte flags
= br
.ReadByte ();
264 if ((flags
& (byte) MethodDataSection
.FatFormat
) == 0) {
265 int length
= br
.ReadByte () / 12;
268 for (int i
= 0; i
< length
; i
++) {
269 ExceptionHandler eh
= new ExceptionHandler (
270 (ExceptionHandlerType
) (br
.ReadInt16 () & 0x7));
271 eh
.TryStart
= GetInstruction (body
, Convert
.ToInt32 (br
.ReadInt16 ()));
272 eh
.TryEnd
= GetInstruction (body
, eh
.TryStart
.Offset
+ Convert
.ToInt32 (br
.ReadByte ()));
273 eh
.HandlerStart
= GetInstruction (body
, Convert
.ToInt32 (br
.ReadInt16 ()));
274 eh
.HandlerEnd
= GetInstruction (body
, eh
.HandlerStart
.Offset
+ Convert
.ToInt32 (br
.ReadByte ()));
275 ReadExceptionHandlerEnd (eh
, br
, body
);
276 body
.ExceptionHandlers
.Add (eh
);
279 br
.BaseStream
.Position
--;
280 int length
= (br
.ReadInt32 () >> 8) / 24;
281 if ((flags
& (int) MethodDataSection
.EHTable
) == 0)
282 br
.ReadBytes (length
* 24);
283 for (int i
= 0; i
< length
; i
++) {
284 ExceptionHandler eh
= new ExceptionHandler (
285 (ExceptionHandlerType
) (br
.ReadInt32 () & 0x7));
286 eh
.TryStart
= GetInstruction (body
, br
.ReadInt32 ());
287 eh
.TryEnd
= GetInstruction (body
, eh
.TryStart
.Offset
+ br
.ReadInt32 ());
288 eh
.HandlerStart
= GetInstruction (body
, br
.ReadInt32 ());
289 eh
.HandlerEnd
= GetInstruction (body
, eh
.HandlerStart
.Offset
+ br
.ReadInt32 ());
290 ReadExceptionHandlerEnd (eh
, br
, body
);
291 body
.ExceptionHandlers
.Add (eh
);
295 if ((flags
& (byte) MethodDataSection
.MoreSects
) != 0)
296 ReadSection (body
, br
);
299 void ReadExceptionHandlerEnd (ExceptionHandler eh
, BinaryReader br
, MethodBody body
)
302 case ExceptionHandlerType
.Catch
:
303 MetadataToken token
= new MetadataToken (br
.ReadInt32 ());
304 eh
.CatchType
= m_reflectReader
.GetTypeDefOrRef (token
, new GenericContext (body
.Method
));
306 case ExceptionHandlerType
.Filter
:
307 eh
.FilterStart
= GetInstruction (body
, br
.ReadInt32 ());
308 eh
.FilterEnd
= GetInstruction (body
, eh
.HandlerStart
.Previous
.Offset
);
316 CallSite
GetCallSiteAt (int token
, GenericContext context
)
318 StandAloneSigTable sasTable
= m_reflectReader
.TableReader
.GetStandAloneSigTable ();
319 MethodSig ms
= m_reflectReader
.SigReader
.GetStandAloneMethodSig (
320 sasTable
[(int) GetRid (token
) - 1].Signature
);
321 CallSite cs
= new CallSite (ms
.HasThis
, ms
.ExplicitThis
,
322 ms
.MethCallConv
, m_reflectReader
.GetMethodReturnType (ms
, context
));
323 cs
.MetadataToken
= new MetadataToken (token
);
325 for (int i
= 0; i
< ms
.ParamCount
; i
++) {
326 Param p
= ms
.Parameters
[i
];
327 cs
.Parameters
.Add (m_reflectReader
.BuildParameterDefinition (i
, p
, context
));
330 ReflectionReader
.CreateSentinelIfNeeded (cs
, ms
);
335 public override void VisitVariableDefinitionCollection (VariableDefinitionCollection variables
)
337 MethodBody body
= variables
.Container
as MethodBody
;
338 if (body
== null || body
.LocalVarToken
== 0)
341 StandAloneSigTable sasTable
= m_reflectReader
.TableReader
.GetStandAloneSigTable ();
342 StandAloneSigRow sasRow
= sasTable
[(int) GetRid (body
.LocalVarToken
) - 1];
343 LocalVarSig sig
= m_reflectReader
.SigReader
.GetLocalVarSig (sasRow
.Signature
);
344 for (int i
= 0; i
< sig
.Count
; i
++) {
345 LocalVarSig
.LocalVariable lv
= sig
.LocalVariables
[i
];
346 TypeReference varType
= m_reflectReader
.GetTypeRefFromSig (
347 lv
.Type
, new GenericContext (body
.Method
));
350 varType
= new ReferenceType (varType
);
351 if ((lv
.Constraint
& Constraint
.Pinned
) != 0)
352 varType
= new PinnedType (varType
);
354 varType
= m_reflectReader
.GetModifierType (lv
.CustomMods
, varType
);
356 body
.Variables
.Add (new VariableDefinition (
357 string.Concat ("V_", i
), i
, body
.Method
, varType
));