~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/Mono.Cecil/Mono.Cecil/Mono.Cecil.Cil/CodeReader.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
// Author:
5
5
//   Jb Evain (jbevain@gmail.com)
6
6
//
7
 
// (C) 2005 - 2007 Jb Evain
 
7
// Copyright (c) 2008 - 2010 Jb Evain
8
8
//
9
9
// Permission is hereby granted, free of charge, to any person obtaining
10
10
// a copy of this software and associated documentation files (the
26
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
27
//
28
28
 
 
29
using System;
 
30
 
 
31
using Mono.Cecil.PE;
 
32
using Mono.Collections.Generic;
 
33
 
 
34
using RVA = System.UInt32;
 
35
 
29
36
namespace Mono.Cecil.Cil {
30
37
 
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 ();
 
38
        sealed class CodeReader : ByteBuffer {
 
39
 
 
40
                readonly internal MetadataReader reader;
 
41
 
 
42
                int start;
 
43
                Section code_section;
 
44
 
 
45
                MethodDefinition method;
 
46
                MethodBody body;
 
47
 
 
48
                int Offset {
 
49
                        get { return base.position - start; }
 
50
                }
 
51
 
 
52
                CodeReader (Section section, MetadataReader reader)
 
53
                        : base (section.Data)
 
54
                {
 
55
                        this.code_section = section;
 
56
                        this.reader = reader;
 
57
                }
 
58
 
 
59
                public static CodeReader CreateCodeReader (MetadataReader metadata)
 
60
                {
 
61
                        return new CodeReader (metadata.image.MetadataSection, metadata);
 
62
                }
 
63
 
 
64
                public MethodBody ReadMethodBody (MethodDefinition method)
 
65
                {
 
66
                        this.method = method;
 
67
                        this.body = new MethodBody (method);
 
68
 
 
69
                        reader.context = method;
 
70
 
 
71
                        ReadMethodBody ();
 
72
 
 
73
                        return this.body;
 
74
                }
 
75
 
 
76
                public void MoveTo (int rva)
 
77
                {
 
78
                        if (!IsInSection (rva)) {
 
79
                                code_section = reader.image.GetSectionAtVirtualAddress ((uint) rva);
 
80
                                Reset (code_section.Data);
 
81
                        }
 
82
 
 
83
                        base.position = rva - (int) code_section.VirtualAddress;
 
84
                }
 
85
 
 
86
                bool IsInSection (int rva)
 
87
                {
 
88
                        return code_section.VirtualAddress <= rva && rva < code_section.VirtualAddress + code_section.SizeOfRawData;
 
89
                }
 
90
 
 
91
                void ReadMethodBody ()
 
92
                {
 
93
                        MoveTo (method.RVA);
 
94
 
 
95
                        var flags = ReadByte ();
60
96
                        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 ()];
 
97
                        case 0x2: // tiny
 
98
                                body.code_size = flags >> 2;
 
99
                                body.MaxStackSize = 8;
 
100
                                ReadCode ();
 
101
                                break;
 
102
                        case 0x3: // fat
 
103
                                base.position--;
 
104
                                ReadFatMethod ();
 
105
                                break;
 
106
                        default:
 
107
                                throw new InvalidOperationException ();
 
108
                        }
 
109
 
 
110
                        var symbol_reader = reader.module.SymbolReader;
 
111
 
 
112
                        if (symbol_reader != null) {
 
113
                                var instructions = body.Instructions;
 
114
                                symbol_reader.Read (body, offset => GetInstruction (instructions, offset));
 
115
                        }
 
116
                }
 
117
 
 
118
                void ReadFatMethod ()
 
119
                {
 
120
                        var flags = ReadUInt16 ();
 
121
                        body.max_stack_size = ReadUInt16 ();
 
122
                        body.code_size = (int) ReadUInt32 ();
 
123
                        body.local_var_token = new MetadataToken (ReadUInt32 ());
 
124
                        body.init_locals = (flags & 0x10) != 0;
 
125
 
 
126
                        if (body.local_var_token.RID != 0)
 
127
                                body.variables = ReadVariables (body.local_var_token);
 
128
 
 
129
                        ReadCode ();
 
130
 
 
131
                        if ((flags & 0x8) != 0)
 
132
                                ReadSection ();
 
133
                }
 
134
 
 
135
                public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
 
136
                {
 
137
                        var position = reader.position;
 
138
                        var variables = reader.ReadVariables (local_var_token);
 
139
                        reader.position = position;
 
140
 
 
141
                        return variables;
 
142
                }
 
143
 
 
144
                void ReadCode ()
 
145
                {
 
146
                        start = position;
 
147
                        var code_size = body.code_size;
 
148
 
 
149
                        if (code_size < 0 || buffer.Length <= (uint) (code_size + position))
 
150
                                code_size = 0;
 
151
 
 
152
                        var end = start + code_size;
 
153
                        var instructions = body.instructions = new InstructionCollection (code_size / 3);
 
154
 
 
155
                        while (position < end) {
 
156
                                var offset = base.position - start;
 
157
                                var opcode = ReadOpCode ();
 
158
                                var current = new Instruction (offset, opcode);
 
159
 
 
160
                                if (opcode.OperandType != OperandType.InlineNone)
 
161
                                        current.operand = ReadOperand (current);
 
162
 
 
163
                                instructions.Add (current);
 
164
                        }
 
165
 
 
166
                        ResolveBranches (instructions);
 
167
                }
 
168
 
 
169
                OpCode ReadOpCode ()
 
170
                {
 
171
                        var il_opcode = ReadByte ();
 
172
                        return il_opcode != 0xfe
 
173
                                ? OpCodes.OneByteOpCode [il_opcode]
 
174
                                : OpCodes.TwoBytesOpCode [ReadByte ()];
 
175
                }
 
176
 
 
177
                object ReadOperand (Instruction instruction)
 
178
                {
 
179
                        switch (instruction.opcode.OperandType) {
 
180
                        case OperandType.InlineSwitch:
 
181
                                var length = ReadInt32 ();
 
182
                                var base_offset = Offset + (4 * length);
 
183
                                var branches = new int [length];
 
184
                                for (int i = 0; i < length; i++)
 
185
                                        branches [i] = base_offset + ReadInt32 ();
 
186
                                return branches;
 
187
                        case OperandType.ShortInlineBrTarget:
 
188
                                return ReadSByte () + Offset;
 
189
                        case OperandType.InlineBrTarget:
 
190
                                return ReadInt32 () + Offset;
 
191
                        case OperandType.ShortInlineI:
 
192
                                if (instruction.opcode == OpCodes.Ldc_I4_S)
 
193
                                        return ReadSByte ();
 
194
 
 
195
                                return ReadByte ();
 
196
                        case OperandType.InlineI:
 
197
                                return ReadInt32 ();
 
198
                        case OperandType.ShortInlineR:
 
199
                                return ReadSingle ();
 
200
                        case OperandType.InlineR:
 
201
                                return ReadDouble ();
 
202
                        case OperandType.InlineI8:
 
203
                                return ReadInt64 ();
 
204
                        case OperandType.ShortInlineVar:
 
205
                                return GetVariable (ReadByte ());
 
206
                        case OperandType.InlineVar:
 
207
                                return GetVariable (ReadUInt16 ());
 
208
                        case OperandType.ShortInlineArg:
 
209
                                return GetParameter (ReadByte ());
 
210
                        case OperandType.InlineArg:
 
211
                                return GetParameter (ReadUInt16 ());
 
212
                        case OperandType.InlineSig:
 
213
                                return GetCallSite (ReadToken ());
 
214
                        case OperandType.InlineString:
 
215
                                return GetString (ReadToken ());
 
216
                        case OperandType.InlineTok:
 
217
                        case OperandType.InlineType:
 
218
                        case OperandType.InlineMethod:
 
219
                        case OperandType.InlineField:
 
220
                                return reader.LookupToken (ReadToken ());
 
221
                        default:
 
222
                                throw new NotSupportedException ();
 
223
                        }
 
224
                }
 
225
 
 
226
                public string GetString (MetadataToken token)
 
227
                {
 
228
                        return reader.image.UserStringHeap.Read (token.RID);
 
229
                }
 
230
 
 
231
                public ParameterDefinition GetParameter (int index)
 
232
                {
 
233
                        return body.GetParameter (index);
 
234
                }
 
235
 
 
236
                public VariableDefinition GetVariable (int index)
 
237
                {
 
238
                        return body.GetVariable (index);
 
239
                }
 
240
 
 
241
                public CallSite GetCallSite (MetadataToken token)
 
242
                {
 
243
                        return reader.ReadCallSite (token);
 
244
                }
 
245
 
 
246
                void ResolveBranches (Collection<Instruction> instructions)
 
247
                {
 
248
                        var items = instructions.items;
 
249
                        var size = instructions.size;
 
250
 
 
251
                        for (int i = 0; i < size; i++) {
 
252
                                var instruction = items [i];
 
253
                                switch (instruction.opcode.OperandType) {
 
254
                                case OperandType.ShortInlineBrTarget:
 
255
                                case OperandType.InlineBrTarget:
 
256
                                        instruction.operand = GetInstruction ((int) instruction.operand);
 
257
                                        break;
 
258
                                case OperandType.InlineSwitch:
 
259
                                        var offsets = (int []) instruction.operand;
 
260
                                        var branches = new Instruction [offsets.Length];
 
261
                                        for (int j = 0; j < offsets.Length; j++)
 
262
                                                branches [j] = GetInstruction (offsets [j]);
 
263
 
 
264
                                        instruction.operand = branches;
 
265
                                        break;
 
266
                                }
 
267
                        }
 
268
                }
 
269
 
 
270
                Instruction GetInstruction (int offset)
 
271
                {
 
272
                        return GetInstruction (body.Instructions, offset);
 
273
                }
 
274
 
 
275
                static Instruction GetInstruction (Collection<Instruction> instructions, int offset)
 
276
                {
 
277
                        var size = instructions.size;
 
278
                        var items = instructions.items;
 
279
                        if (offset < 0 || offset > items [size - 1].offset)
 
280
                                return null;
 
281
 
 
282
                        int min = 0;
 
283
                        int max = size - 1;
 
284
                        while (min <= max) {
 
285
                                int mid = min + ((max - min) / 2);
 
286
                                var instruction = items [mid];
 
287
                                var instruction_offset = instruction.offset;
 
288
 
 
289
                                if (offset == instruction_offset)
 
290
                                        return instruction;
 
291
 
 
292
                                if (offset < instruction_offset)
 
293
                                        max = mid - 1;
118
294
                                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) {
 
295
                                        min = mid + 1;
 
296
                        }
 
297
 
 
298
                        return null;
 
299
                }
 
300
 
 
301
                void ReadSection ()
 
302
                {
 
303
                        Align (4);
 
304
 
 
305
                        const byte fat_format = 0x40;
 
306
                        const byte more_sects = 0x80;
 
307
 
 
308
                        var flags = ReadByte ();
 
309
                        if ((flags & fat_format) == 0)
 
310
                                ReadSmallSection ();
 
311
                        else
 
312
                                ReadFatSection ();
 
313
 
 
314
                        if ((flags & more_sects) != 0)
 
315
                                ReadSection ();
 
316
                }
 
317
 
 
318
                void ReadSmallSection ()
 
319
                {
 
320
                        var count = ReadByte () / 12;
 
321
                        Advance (2);
 
322
 
 
323
                        ReadExceptionHandlers (
 
324
                                count,
 
325
                                () => (int) ReadUInt16 (),
 
326
                                () => (int) ReadByte ());
 
327
                }
 
328
 
 
329
                void ReadFatSection ()
 
330
                {
 
331
                        position--;
 
332
                        var count = (ReadInt32 () >> 8) / 24;
 
333
 
 
334
                        ReadExceptionHandlers (
 
335
                                count,
 
336
                                ReadInt32,
 
337
                                ReadInt32);
 
338
                }
 
339
 
 
340
                // inline ?
 
341
                void ReadExceptionHandlers (int count, Func<int> read_entry, Func<int> read_length)
 
342
                {
 
343
                        for (int i = 0; i < count; i++) {
 
344
                                var handler = new ExceptionHandler (
 
345
                                        (ExceptionHandlerType) (read_entry () & 0x7));
 
346
 
 
347
                                handler.TryStart = GetInstruction (read_entry ());
 
348
                                handler.TryEnd = GetInstruction (handler.TryStart.Offset + read_length ());
 
349
 
 
350
                                handler.HandlerStart = GetInstruction (read_entry ());
 
351
                                handler.HandlerEnd = GetInstruction (handler.HandlerStart.Offset + read_length ());
 
352
 
 
353
                                ReadExceptionHandlerSpecific (handler);
 
354
 
 
355
                                this.body.ExceptionHandlers.Add (handler);
 
356
                        }
 
357
                }
 
358
 
 
359
                void ReadExceptionHandlerSpecific (ExceptionHandler handler)
 
360
                {
 
361
                        switch (handler.HandlerType) {
 
362
                        case ExceptionHandlerType.Catch:
 
363
                                handler.CatchType = (TypeReference) reader.LookupToken (ReadToken ());
 
364
                                break;
 
365
                        case ExceptionHandlerType.Filter:
 
366
                                handler.FilterStart = GetInstruction (ReadInt32 ());
 
367
                                handler.FilterEnd = handler.HandlerStart.Previous;
 
368
                                break;
 
369
                        default:
 
370
                                Advance (4);
 
371
                                break;
 
372
                        }
 
373
                }
 
374
 
 
375
                void Align (int align)
 
376
                {
 
377
                        align--;
 
378
                        Advance (((position + align) & ~align) - position);
 
379
                }
 
380
 
 
381
                public MetadataToken ReadToken ()
 
382
                {
 
383
                        return new MetadataToken (ReadUInt32 ());
 
384
                }
 
385
 
 
386
#if !READ_ONLY
 
387
 
 
388
                public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out MethodSymbols symbols)
 
389
                {
 
390
                        var buffer = new ByteBuffer ();
 
391
                        symbols = new MethodSymbols (method.Name);
 
392
 
 
393
                        this.method = method;
 
394
                        reader.context = method;
 
395
 
 
396
                        MoveTo (method.RVA);
 
397
 
 
398
                        var flags = ReadByte ();
 
399
 
 
400
                        MetadataToken local_var_token;
 
401
 
 
402
                        switch (flags & 0x3) {
 
403
                        case 0x2: // tiny
 
404
                                buffer.WriteByte (flags);
 
405
                                local_var_token = MetadataToken.Zero;
 
406
                                symbols.code_size = flags >> 2;
 
407
                                PatchRawCode (buffer, symbols.code_size, writer);
 
408
                                break;
 
409
                        case 0x3: // fat
 
410
                                base.position--;
 
411
 
 
412
                                PatchRawFatMethod (buffer, symbols, writer, out local_var_token);
 
413
                                break;
 
414
                        default:
 
415
                                throw new NotSupportedException ();
 
416
                        }
 
417
 
 
418
                        var symbol_reader = reader.module.SymbolReader;
 
419
                        if (symbol_reader != null && writer.metadata.write_symbols) {
 
420
                                symbols.method_token = GetOriginalToken (writer.metadata, method);
 
421
                                symbols.local_var_token = local_var_token;
 
422
                                symbol_reader.Read (symbols);
 
423
                        }
 
424
 
 
425
                        return buffer;
 
426
                }
 
427
 
 
428
                void PatchRawFatMethod (ByteBuffer buffer, MethodSymbols symbols, CodeWriter writer, out MetadataToken local_var_token)
 
429
                {
 
430
                        var flags = ReadUInt16 ();
 
431
                        buffer.WriteUInt16 (flags);
 
432
                        buffer.WriteUInt16 (ReadUInt16 ());
 
433
                        symbols.code_size = ReadInt32 ();
 
434
                        buffer.WriteInt32 (symbols.code_size);
 
435
                        local_var_token = ReadToken ();
 
436
 
 
437
                        if (local_var_token.RID > 0) {
 
438
                                var variables = symbols.variables = ReadVariables (local_var_token);
 
439
                                buffer.WriteUInt32 (variables != null
 
440
                                        ? writer.GetStandAloneSignature (symbols.variables).ToUInt32 ()
 
441
                                        : 0);
 
442
                        } else
 
443
                                buffer.WriteUInt32 (0);
 
444
 
 
445
                        PatchRawCode (buffer, symbols.code_size, writer);
 
446
 
 
447
                        if ((flags & 0x8) != 0)
 
448
                                PatchRawSection (buffer, writer.metadata);
 
449
                }
 
450
 
 
451
                static MetadataToken GetOriginalToken (MetadataBuilder metadata, MethodDefinition method)
 
452
                {
 
453
                        MetadataToken original;
 
454
                        if (metadata.TryGetOriginalMethodToken (method.token, out original))
 
455
                                return original;
 
456
 
 
457
                        return MetadataToken.Zero;
 
458
                }
 
459
 
 
460
                void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer)
 
461
                {
 
462
                        var metadata = writer.metadata;
 
463
                        buffer.WriteBytes (ReadBytes (code_size));
 
464
                        var end = buffer.position;
 
465
                        buffer.position -= code_size;
 
466
 
 
467
                        while (buffer.position < end) {
 
468
                                OpCode opcode;
 
469
                                var il_opcode = buffer.ReadByte ();
 
470
                                if (il_opcode != 0xfe) {
 
471
                                        opcode = OpCodes.OneByteOpCode [il_opcode];
 
472
                                } else {
 
473
                                        var il_opcode2 = buffer.ReadByte ();
 
474
                                        opcode = OpCodes.TwoBytesOpCode [il_opcode2];
 
475
                                }
 
476
 
 
477
                                switch (opcode.OperandType) {
 
478
                                case OperandType.ShortInlineI:
227
479
                                case OperandType.ShortInlineBrTarget:
 
480
                                case OperandType.ShortInlineVar:
 
481
                                case OperandType.ShortInlineArg:
 
482
                                        buffer.position += 1;
 
483
                                        break;
 
484
                                case OperandType.InlineVar:
 
485
                                case OperandType.InlineArg:
 
486
                                        buffer.position += 2;
 
487
                                        break;
228
488
                                case OperandType.InlineBrTarget:
229
 
                                        i.Operand = GetInstruction (body, (int) i.Operand);
 
489
                                case OperandType.ShortInlineR:
 
490
                                case OperandType.InlineI:
 
491
                                        buffer.position += 4;
 
492
                                        break;
 
493
                                case OperandType.InlineI8:
 
494
                                case OperandType.InlineR:
 
495
                                        buffer.position += 8;
230
496
                                        break;
231
497
                                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
 
                }
 
498
                                        var length = buffer.ReadInt32 ();
 
499
                                        buffer.position += length * 4;
 
500
                                        break;
 
501
                                case OperandType.InlineString:
 
502
                                        var @string = GetString (new MetadataToken (buffer.ReadUInt32 ()));
 
503
                                        buffer.position -= 4;
 
504
                                        buffer.WriteUInt32 (
 
505
                                                new MetadataToken (
 
506
                                                        TokenType.String,
 
507
                                                        metadata.user_string_heap.GetStringIndex (@string)).ToUInt32 ());
 
508
                                        break;
 
509
                                case OperandType.InlineSig:
 
510
                                        var call_site = GetCallSite (new MetadataToken (buffer.ReadUInt32 ()));
 
511
                                        buffer.position -= 4;
 
512
                                        buffer.WriteUInt32 (writer.GetStandAloneSignature (call_site).ToUInt32 ());
 
513
                                        break;
 
514
                                case OperandType.InlineTok:
 
515
                                case OperandType.InlineType:
 
516
                                case OperandType.InlineMethod:
 
517
                                case OperandType.InlineField:
 
518
                                        var provider = reader.LookupToken (new MetadataToken (buffer.ReadUInt32 ()));
 
519
                                        buffer.position -= 4;
 
520
                                        buffer.WriteUInt32 (metadata.LookupToken (provider).ToUInt32 ());
 
521
                                        break;
 
522
                                }
 
523
                        }
 
524
                }
 
525
 
 
526
                void PatchRawSection (ByteBuffer buffer, MetadataBuilder metadata)
 
527
                {
 
528
                        var position = base.position;
 
529
                        Align (4);
 
530
                        buffer.WriteBytes (base.position - position);
 
531
 
 
532
                        const byte fat_format = 0x40;
 
533
                        const byte more_sects = 0x80;
 
534
 
 
535
                        var flags = ReadByte ();
 
536
                        if ((flags & fat_format) == 0) {
 
537
                                buffer.WriteByte (flags);
 
538
                                PatchRawSmallSection (buffer, metadata);
 
539
                        } else
 
540
                                PatchRawFatSection (buffer, metadata);
 
541
 
 
542
                        if ((flags & more_sects) != 0)
 
543
                                PatchRawSection (buffer, metadata);
 
544
                }
 
545
 
 
546
                void PatchRawSmallSection (ByteBuffer buffer, MetadataBuilder metadata)
 
547
                {
 
548
                        var length = ReadByte ();
 
549
                        buffer.WriteByte (length);
 
550
                        Advance (2);
 
551
 
 
552
                        buffer.WriteUInt16 (0);
 
553
 
 
554
                        var count = length / 12;
 
555
 
 
556
                        PatchRawExceptionHandlers (buffer, metadata, count, false);
 
557
                }
 
558
 
 
559
                void PatchRawFatSection (ByteBuffer buffer, MetadataBuilder metadata)
 
560
                {
 
561
                        position--;
 
562
                        var length = ReadInt32 ();
 
563
                        buffer.WriteInt32 (length);
 
564
 
 
565
                        var count = (length >> 8) / 24;
 
566
 
 
567
                        PatchRawExceptionHandlers (buffer, metadata, count, true);
 
568
                }
 
569
 
 
570
                void PatchRawExceptionHandlers (ByteBuffer buffer, MetadataBuilder metadata, int count, bool fat_entry)
 
571
                {
 
572
                        const int fat_entry_size = 16;
 
573
                        const int small_entry_size = 6;
 
574
 
 
575
                        for (int i = 0; i < count; i++) {
 
576
                                ExceptionHandlerType handler_type;
 
577
                                if (fat_entry) {
 
578
                                        var type = ReadUInt32 ();
 
579
                                        handler_type = (ExceptionHandlerType) (type & 0x7);
 
580
                                        buffer.WriteUInt32 (type);
 
581
                                } else {
 
582
                                        var type = ReadUInt16 ();
 
583
                                        handler_type = (ExceptionHandlerType) (type & 0x7);
 
584
                                        buffer.WriteUInt16 (type);
 
585
                                }
 
586
 
 
587
                                buffer.WriteBytes (ReadBytes (fat_entry ? fat_entry_size : small_entry_size));
 
588
 
 
589
                                switch (handler_type) {
 
590
                                case ExceptionHandlerType.Catch:
 
591
                                        var exception = reader.LookupToken (ReadToken ());
 
592
                                        buffer.WriteUInt32 (metadata.LookupToken (exception).ToUInt32 ());
 
593
                                        break;
 
594
                                default:
 
595
                                        buffer.WriteUInt32 (ReadUInt32 ());
 
596
                                        break;
 
597
                                }
 
598
                        }
 
599
                }
 
600
 
 
601
#endif
 
602
 
356
603
        }
357
604
}