664 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			664 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //
 | |
| // Author:
 | |
| //   Jb Evain (jbevain@gmail.com)
 | |
| //
 | |
| // Copyright (c) 2008 - 2015 Jb Evain
 | |
| // Copyright (c) 2008 - 2011 Novell, Inc.
 | |
| //
 | |
| // Licensed under the MIT/X11 license.
 | |
| //
 | |
| 
 | |
| using MonoFN.Cecil.PE;
 | |
| using MonoFN.Collections.Generic;
 | |
| using System;
 | |
| 
 | |
| namespace MonoFN.Cecil.Cil {
 | |
| 
 | |
| 	sealed class CodeReader : BinaryStreamReader {
 | |
| 
 | |
| 		readonly internal MetadataReader reader;
 | |
| 
 | |
| 		int start;
 | |
| 
 | |
| 		MethodDefinition method;
 | |
| 		MethodBody body;
 | |
| 
 | |
| 		int Offset {
 | |
| 			get { return Position - start; }
 | |
| 		}
 | |
| 
 | |
| 		public CodeReader (MetadataReader reader)
 | |
| 			: base (reader.image.Stream.value)
 | |
| 		{
 | |
| 			this.reader = reader;
 | |
| 		}
 | |
| 
 | |
| 		public int MoveTo (MethodDefinition method)
 | |
| 		{
 | |
| 			this.method = method;
 | |
| 			this.reader.context = method;
 | |
| 			var position = this.Position;
 | |
| 			this.Position = (int)reader.image.ResolveVirtualAddress ((uint)method.RVA);
 | |
| 			return position;
 | |
| 		}
 | |
| 
 | |
| 		public void MoveBackTo (int position)
 | |
| 		{
 | |
| 			this.reader.context = null;
 | |
| 			this.Position = position;
 | |
| 		}
 | |
| 
 | |
| 		public MethodBody ReadMethodBody (MethodDefinition method)
 | |
| 		{
 | |
| 			var position = MoveTo (method);
 | |
| 			this.body = new MethodBody (method);
 | |
| 
 | |
| 			ReadMethodBody ();
 | |
| 
 | |
| 			MoveBackTo (position);
 | |
| 			return this.body;
 | |
| 		}
 | |
| 
 | |
| 		public int ReadCodeSize (MethodDefinition method)
 | |
| 		{
 | |
| 			var position = MoveTo (method);
 | |
| 
 | |
| 			var code_size = ReadCodeSize ();
 | |
| 
 | |
| 			MoveBackTo (position);
 | |
| 			return code_size;
 | |
| 		}
 | |
| 
 | |
| 		int ReadCodeSize ()
 | |
| 		{
 | |
| 			var flags = ReadByte ();
 | |
| 			switch (flags & 0x3) {
 | |
| 			case 0x2: // tiny
 | |
| 				return flags >> 2;
 | |
| 			case 0x3: // fat
 | |
| 				Advance (-1 + 2 + 2); // go back, 2 bytes flags, 2 bytes stack size
 | |
| 				return (int)ReadUInt32 ();
 | |
| 			default:
 | |
| 				throw new InvalidOperationException ();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadMethodBody ()
 | |
| 		{
 | |
| 			var flags = ReadByte ();
 | |
| 			switch (flags & 0x3) {
 | |
| 			case 0x2: // tiny
 | |
| 				body.code_size = flags >> 2;
 | |
| 				body.MaxStackSize = 8;
 | |
| 				ReadCode ();
 | |
| 				break;
 | |
| 			case 0x3: // fat
 | |
| 				Advance (-1);
 | |
| 				ReadFatMethod ();
 | |
| 				break;
 | |
| 			default:
 | |
| 				throw new InvalidOperationException ();
 | |
| 			}
 | |
| 
 | |
| 			var symbol_reader = reader.module.symbol_reader;
 | |
| 
 | |
| 			if (symbol_reader != null && method.debug_info == null)
 | |
| 				method.debug_info = symbol_reader.Read (method);
 | |
| 
 | |
| 			if (method.debug_info != null)
 | |
| 				ReadDebugInfo ();
 | |
| 		}
 | |
| 
 | |
| 		void ReadFatMethod ()
 | |
| 		{
 | |
| 			var flags = ReadUInt16 ();
 | |
| 			body.max_stack_size = ReadUInt16 ();
 | |
| 			body.code_size = (int)ReadUInt32 ();
 | |
| 			body.local_var_token = new MetadataToken (ReadUInt32 ());
 | |
| 			body.init_locals = (flags & 0x10) != 0;
 | |
| 
 | |
| 			if (body.local_var_token.RID != 0)
 | |
| 				body.variables = ReadVariables (body.local_var_token);
 | |
| 
 | |
| 			ReadCode ();
 | |
| 
 | |
| 			if ((flags & 0x8) != 0)
 | |
| 				ReadSection ();
 | |
| 		}
 | |
| 
 | |
| 		public VariableDefinitionCollection ReadVariables (MetadataToken local_var_token)
 | |
| 		{
 | |
| 			var position = reader.position;
 | |
| 			var variables = reader.ReadVariables (local_var_token, method);
 | |
| 			reader.position = position;
 | |
| 
 | |
| 			return variables;
 | |
| 		}
 | |
| 
 | |
| 		void ReadCode ()
 | |
| 		{
 | |
| 			start = Position;
 | |
| 			var code_size = body.code_size;
 | |
| 
 | |
| 			if (code_size < 0 || Length <= (uint)(code_size + Position))
 | |
| 				code_size = 0;
 | |
| 
 | |
| 			var end = start + code_size;
 | |
| 			var instructions = body.instructions = new InstructionCollection (method, (code_size + 1) / 2);
 | |
| 
 | |
| 			while (Position < end) {
 | |
| 				var offset = Position - start;
 | |
| 				var opcode = ReadOpCode ();
 | |
| 				var current = new Instruction (offset, opcode);
 | |
| 
 | |
| 				if (opcode.OperandType != OperandType.InlineNone)
 | |
| 					current.operand = ReadOperand (current);
 | |
| 
 | |
| 				instructions.Add (current);
 | |
| 			}
 | |
| 
 | |
| 			ResolveBranches (instructions);
 | |
| 		}
 | |
| 
 | |
| 		OpCode ReadOpCode ()
 | |
| 		{
 | |
| 			var il_opcode = ReadByte ();
 | |
| 			return il_opcode != 0xfe
 | |
| 				? OpCodes.OneByteOpCode [il_opcode]
 | |
| 				: OpCodes.TwoBytesOpCode [ReadByte ()];
 | |
| 		}
 | |
| 
 | |
| 		object ReadOperand (Instruction instruction)
 | |
| 		{
 | |
| 			switch (instruction.opcode.OperandType) {
 | |
| 			case OperandType.InlineSwitch:
 | |
| 				var length = ReadInt32 ();
 | |
| 				var base_offset = Offset + (4 * length);
 | |
| 				var branches = new int [length];
 | |
| 				for (int i = 0; i < length; i++)
 | |
| 					branches [i] = base_offset + ReadInt32 ();
 | |
| 				return branches;
 | |
| 			case OperandType.ShortInlineBrTarget:
 | |
| 				return ReadSByte () + Offset;
 | |
| 			case OperandType.InlineBrTarget:
 | |
| 				return ReadInt32 () + Offset;
 | |
| 			case OperandType.ShortInlineI:
 | |
| 				if (instruction.opcode == OpCodes.Ldc_I4_S)
 | |
| 					return ReadSByte ();
 | |
| 
 | |
| 				return ReadByte ();
 | |
| 			case OperandType.InlineI:
 | |
| 				return ReadInt32 ();
 | |
| 			case OperandType.ShortInlineR:
 | |
| 				return ReadSingle ();
 | |
| 			case OperandType.InlineR:
 | |
| 				return ReadDouble ();
 | |
| 			case OperandType.InlineI8:
 | |
| 				return ReadInt64 ();
 | |
| 			case OperandType.ShortInlineVar:
 | |
| 				return GetVariable (ReadByte ());
 | |
| 			case OperandType.InlineVar:
 | |
| 				return GetVariable (ReadUInt16 ());
 | |
| 			case OperandType.ShortInlineArg:
 | |
| 				return GetParameter (ReadByte ());
 | |
| 			case OperandType.InlineArg:
 | |
| 				return GetParameter (ReadUInt16 ());
 | |
| 			case OperandType.InlineSig:
 | |
| 				return GetCallSite (ReadToken ());
 | |
| 			case OperandType.InlineString:
 | |
| 				return GetString (ReadToken ());
 | |
| 			case OperandType.InlineTok:
 | |
| 			case OperandType.InlineType:
 | |
| 			case OperandType.InlineMethod:
 | |
| 			case OperandType.InlineField:
 | |
| 				return reader.LookupToken (ReadToken ());
 | |
| 			default:
 | |
| 				throw new NotSupportedException ();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public string GetString (MetadataToken token)
 | |
| 		{
 | |
| 			return reader.image.UserStringHeap.Read (token.RID);
 | |
| 		}
 | |
| 
 | |
| 		public ParameterDefinition GetParameter (int index)
 | |
| 		{
 | |
| 			return body.GetParameter (index);
 | |
| 		}
 | |
| 
 | |
| 		public VariableDefinition GetVariable (int index)
 | |
| 		{
 | |
| 			return body.GetVariable (index);
 | |
| 		}
 | |
| 
 | |
| 		public CallSite GetCallSite (MetadataToken token)
 | |
| 		{
 | |
| 			return reader.ReadCallSite (token);
 | |
| 		}
 | |
| 
 | |
| 		void ResolveBranches (Collection<Instruction> instructions)
 | |
| 		{
 | |
| 			var items = instructions.items;
 | |
| 			var size = instructions.size;
 | |
| 
 | |
| 			for (int i = 0; i < size; i++) {
 | |
| 				var instruction = items [i];
 | |
| 				switch (instruction.opcode.OperandType) {
 | |
| 				case OperandType.ShortInlineBrTarget:
 | |
| 				case OperandType.InlineBrTarget:
 | |
| 					instruction.operand = GetInstruction ((int)instruction.operand);
 | |
| 					break;
 | |
| 				case OperandType.InlineSwitch:
 | |
| 					var offsets = (int [])instruction.operand;
 | |
| 					var branches = new Instruction [offsets.Length];
 | |
| 					for (int j = 0; j < offsets.Length; j++)
 | |
| 						branches [j] = GetInstruction (offsets [j]);
 | |
| 
 | |
| 					instruction.operand = branches;
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		Instruction GetInstruction (int offset)
 | |
| 		{
 | |
| 			return GetInstruction (body.Instructions, offset);
 | |
| 		}
 | |
| 
 | |
| 		static Instruction GetInstruction (Collection<Instruction> instructions, int offset)
 | |
| 		{
 | |
| 			var size = instructions.size;
 | |
| 			var items = instructions.items;
 | |
| 			if (offset < 0 || offset > items [size - 1].offset)
 | |
| 				return null;
 | |
| 
 | |
| 			int min = 0;
 | |
| 			int max = size - 1;
 | |
| 			while (min <= max) {
 | |
| 				int mid = min + ((max - min) / 2);
 | |
| 				var instruction = items [mid];
 | |
| 				var instruction_offset = instruction.offset;
 | |
| 
 | |
| 				if (offset == instruction_offset)
 | |
| 					return instruction;
 | |
| 
 | |
| 				if (offset < instruction_offset)
 | |
| 					max = mid - 1;
 | |
| 				else
 | |
| 					min = mid + 1;
 | |
| 			}
 | |
| 
 | |
| 			return null;
 | |
| 		}
 | |
| 
 | |
| 		void ReadSection ()
 | |
| 		{
 | |
| 			Align (4);
 | |
| 
 | |
| 			const byte fat_format = 0x40;
 | |
| 			const byte more_sects = 0x80;
 | |
| 
 | |
| 			var flags = ReadByte ();
 | |
| 			if ((flags & fat_format) == 0)
 | |
| 				ReadSmallSection ();
 | |
| 			else
 | |
| 				ReadFatSection ();
 | |
| 
 | |
| 			if ((flags & more_sects) != 0)
 | |
| 				ReadSection ();
 | |
| 		}
 | |
| 
 | |
| 		void ReadSmallSection ()
 | |
| 		{
 | |
| 			var count = ReadByte () / 12;
 | |
| 			Advance (2);
 | |
| 
 | |
| 			ReadExceptionHandlers (
 | |
| 				count,
 | |
| 				() => (int)ReadUInt16 (),
 | |
| 				() => (int)ReadByte ());
 | |
| 		}
 | |
| 
 | |
| 		void ReadFatSection ()
 | |
| 		{
 | |
| 			Advance (-1);
 | |
| 			var count = (ReadInt32 () >> 8) / 24;
 | |
| 
 | |
| 			ReadExceptionHandlers (
 | |
| 				count,
 | |
| 				ReadInt32,
 | |
| 				ReadInt32);
 | |
| 		}
 | |
| 
 | |
| 		// inline ?
 | |
| 		void ReadExceptionHandlers (int count, Func<int> read_entry, Func<int> read_length)
 | |
| 		{
 | |
| 			for (int i = 0; i < count; i++) {
 | |
| 				var handler = new ExceptionHandler (
 | |
| 					(ExceptionHandlerType)(read_entry () & 0x7));
 | |
| 
 | |
| 				handler.TryStart = GetInstruction (read_entry ());
 | |
| 				handler.TryEnd = GetInstruction (handler.TryStart.Offset + read_length ());
 | |
| 
 | |
| 				handler.HandlerStart = GetInstruction (read_entry ());
 | |
| 				handler.HandlerEnd = GetInstruction (handler.HandlerStart.Offset + read_length ());
 | |
| 
 | |
| 				ReadExceptionHandlerSpecific (handler);
 | |
| 
 | |
| 				this.body.ExceptionHandlers.Add (handler);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadExceptionHandlerSpecific (ExceptionHandler handler)
 | |
| 		{
 | |
| 			switch (handler.HandlerType) {
 | |
| 			case ExceptionHandlerType.Catch:
 | |
| 				handler.CatchType = (TypeReference)reader.LookupToken (ReadToken ());
 | |
| 				break;
 | |
| 			case ExceptionHandlerType.Filter:
 | |
| 				handler.FilterStart = GetInstruction (ReadInt32 ());
 | |
| 				break;
 | |
| 			default:
 | |
| 				Advance (4);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public MetadataToken ReadToken ()
 | |
| 		{
 | |
| 			return new MetadataToken (ReadUInt32 ());
 | |
| 		}
 | |
| 
 | |
| 		void ReadDebugInfo ()
 | |
| 		{
 | |
| 			if (method.debug_info.sequence_points != null)
 | |
| 				ReadSequencePoints ();
 | |
| 
 | |
| 			if (method.debug_info.scope != null)
 | |
| 				ReadScope (method.debug_info.scope);
 | |
| 
 | |
| 			if (method.custom_infos != null)
 | |
| 				ReadCustomDebugInformations (method);
 | |
| 		}
 | |
| 
 | |
| 		void ReadCustomDebugInformations (MethodDefinition method)
 | |
| 		{
 | |
| 			var custom_infos = method.custom_infos;
 | |
| 
 | |
| 			for (int i = 0; i < custom_infos.Count; i++) {
 | |
| 				var state_machine_scope = custom_infos [i] as StateMachineScopeDebugInformation;
 | |
| 				if (state_machine_scope != null)
 | |
| 					ReadStateMachineScope (state_machine_scope);
 | |
| 
 | |
| 				var async_method = custom_infos [i] as AsyncMethodBodyDebugInformation;
 | |
| 				if (async_method != null)
 | |
| 					ReadAsyncMethodBody (async_method);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadAsyncMethodBody (AsyncMethodBodyDebugInformation async_method)
 | |
| 		{
 | |
| 			if (async_method.catch_handler.Offset > -1)
 | |
| 				async_method.catch_handler = new InstructionOffset (GetInstruction (async_method.catch_handler.Offset));
 | |
| 
 | |
| 			if (!async_method.yields.IsNullOrEmpty ())
 | |
| 				for (int i = 0; i < async_method.yields.Count; i++)
 | |
| 					async_method.yields [i] = new InstructionOffset (GetInstruction (async_method.yields [i].Offset));
 | |
| 
 | |
| 			if (!async_method.resumes.IsNullOrEmpty ())
 | |
| 				for (int i = 0; i < async_method.resumes.Count; i++)
 | |
| 					async_method.resumes [i] = new InstructionOffset (GetInstruction (async_method.resumes [i].Offset));
 | |
| 		}
 | |
| 
 | |
| 		void ReadStateMachineScope (StateMachineScopeDebugInformation state_machine_scope)
 | |
| 		{
 | |
| 			if (state_machine_scope.scopes.IsNullOrEmpty ())
 | |
| 				return;
 | |
| 
 | |
| 			foreach (var scope in state_machine_scope.scopes) {
 | |
| 				scope.start = new InstructionOffset (GetInstruction (scope.start.Offset));
 | |
| 
 | |
| 				var end_instruction = GetInstruction (scope.end.Offset);
 | |
| 				scope.end = end_instruction == null
 | |
| 					? new InstructionOffset ()
 | |
| 					: new InstructionOffset (end_instruction);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadSequencePoints ()
 | |
| 		{
 | |
| 			var symbol = method.debug_info;
 | |
| 
 | |
| 			for (int i = 0; i < symbol.sequence_points.Count; i++) {
 | |
| 				var sequence_point = symbol.sequence_points [i];
 | |
| 				var instruction = GetInstruction (sequence_point.Offset);
 | |
| 				if (instruction != null)
 | |
| 					sequence_point.offset = new InstructionOffset (instruction);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void ReadScopes (Collection<ScopeDebugInformation> scopes)
 | |
| 		{
 | |
| 			for (int i = 0; i < scopes.Count; i++)
 | |
| 				ReadScope (scopes [i]);
 | |
| 		}
 | |
| 
 | |
| 		void ReadScope (ScopeDebugInformation scope)
 | |
| 		{
 | |
| 			var start_instruction = GetInstruction (scope.Start.Offset);
 | |
| 			if (start_instruction != null)
 | |
| 				scope.Start = new InstructionOffset (start_instruction);
 | |
| 
 | |
| 			var end_instruction = GetInstruction (scope.End.Offset);
 | |
| 			scope.End = end_instruction != null
 | |
| 				? new InstructionOffset (end_instruction)
 | |
| 				: new InstructionOffset ();
 | |
| 
 | |
| 			if (!scope.variables.IsNullOrEmpty ()) {
 | |
| 				for (int i = 0; i < scope.variables.Count; i++) {
 | |
| 					var variable_info = scope.variables [i];
 | |
| 					var variable = GetVariable (variable_info.Index);
 | |
| 					if (variable != null)
 | |
| 						variable_info.index = new VariableIndex (variable);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (!scope.scopes.IsNullOrEmpty ())
 | |
| 				ReadScopes (scope.scopes);
 | |
| 		}
 | |
| 
 | |
| 		public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
 | |
| 		{
 | |
| 			var position = MoveTo (method);
 | |
| 
 | |
| 			var buffer = new ByteBuffer ();
 | |
| 
 | |
| 			var flags = ReadByte ();
 | |
| 
 | |
| 			switch (flags & 0x3) {
 | |
| 			case 0x2: // tiny
 | |
| 				buffer.WriteByte (flags);
 | |
| 				local_var_token = MetadataToken.Zero;
 | |
| 				code_size = flags >> 2;
 | |
| 				PatchRawCode (buffer, code_size, writer);
 | |
| 				break;
 | |
| 			case 0x3: // fat
 | |
| 				Advance (-1);
 | |
| 				PatchRawFatMethod (buffer, writer, out code_size, out local_var_token);
 | |
| 				break;
 | |
| 			default:
 | |
| 				throw new NotSupportedException ();
 | |
| 			}
 | |
| 
 | |
| 			MoveBackTo (position);
 | |
| 
 | |
| 			return buffer;
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawFatMethod (ByteBuffer buffer, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
 | |
| 		{
 | |
| 			var flags = ReadUInt16 ();
 | |
| 			buffer.WriteUInt16 (flags);
 | |
| 			buffer.WriteUInt16 (ReadUInt16 ());
 | |
| 			code_size = ReadInt32 ();
 | |
| 			buffer.WriteInt32 (code_size);
 | |
| 			local_var_token = ReadToken ();
 | |
| 
 | |
| 			if (local_var_token.RID > 0) {
 | |
| 				var variables = ReadVariables (local_var_token);
 | |
| 				buffer.WriteUInt32 (variables != null
 | |
| 					? writer.GetStandAloneSignature (variables).ToUInt32 ()
 | |
| 					: 0);
 | |
| 			} else
 | |
| 				buffer.WriteUInt32 (0);
 | |
| 
 | |
| 			PatchRawCode (buffer, code_size, writer);
 | |
| 
 | |
| 			if ((flags & 0x8) != 0)
 | |
| 				PatchRawSection (buffer, writer.metadata);
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer)
 | |
| 		{
 | |
| 			var metadata = writer.metadata;
 | |
| 			buffer.WriteBytes (ReadBytes (code_size));
 | |
| 			var end = buffer.position;
 | |
| 			buffer.position -= code_size;
 | |
| 
 | |
| 			while (buffer.position < end) {
 | |
| 				OpCode opcode;
 | |
| 				var il_opcode = buffer.ReadByte ();
 | |
| 				if (il_opcode != 0xfe) {
 | |
| 					opcode = OpCodes.OneByteOpCode [il_opcode];
 | |
| 				} else {
 | |
| 					var il_opcode2 = buffer.ReadByte ();
 | |
| 					opcode = OpCodes.TwoBytesOpCode [il_opcode2];
 | |
| 				}
 | |
| 
 | |
| 				switch (opcode.OperandType) {
 | |
| 				case OperandType.ShortInlineI:
 | |
| 				case OperandType.ShortInlineBrTarget:
 | |
| 				case OperandType.ShortInlineVar:
 | |
| 				case OperandType.ShortInlineArg:
 | |
| 					buffer.position += 1;
 | |
| 					break;
 | |
| 				case OperandType.InlineVar:
 | |
| 				case OperandType.InlineArg:
 | |
| 					buffer.position += 2;
 | |
| 					break;
 | |
| 				case OperandType.InlineBrTarget:
 | |
| 				case OperandType.ShortInlineR:
 | |
| 				case OperandType.InlineI:
 | |
| 					buffer.position += 4;
 | |
| 					break;
 | |
| 				case OperandType.InlineI8:
 | |
| 				case OperandType.InlineR:
 | |
| 					buffer.position += 8;
 | |
| 					break;
 | |
| 				case OperandType.InlineSwitch:
 | |
| 					var length = buffer.ReadInt32 ();
 | |
| 					buffer.position += length * 4;
 | |
| 					break;
 | |
| 				case OperandType.InlineString:
 | |
| 					var @string = GetString (new MetadataToken (buffer.ReadUInt32 ()));
 | |
| 					buffer.position -= 4;
 | |
| 					buffer.WriteUInt32 (
 | |
| 						new MetadataToken (
 | |
| 							TokenType.String,
 | |
| 							metadata.user_string_heap.GetStringIndex (@string)).ToUInt32 ());
 | |
| 					break;
 | |
| 				case OperandType.InlineSig:
 | |
| 					var call_site = GetCallSite (new MetadataToken (buffer.ReadUInt32 ()));
 | |
| 					buffer.position -= 4;
 | |
| 					buffer.WriteUInt32 (writer.GetStandAloneSignature (call_site).ToUInt32 ());
 | |
| 					break;
 | |
| 				case OperandType.InlineTok:
 | |
| 				case OperandType.InlineType:
 | |
| 				case OperandType.InlineMethod:
 | |
| 				case OperandType.InlineField:
 | |
| 					var provider = reader.LookupToken (new MetadataToken (buffer.ReadUInt32 ()));
 | |
| 					buffer.position -= 4;
 | |
| 					buffer.WriteUInt32 (metadata.LookupToken (provider).ToUInt32 ());
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawSection (ByteBuffer buffer, MetadataBuilder metadata)
 | |
| 		{
 | |
| 			var position = Position;
 | |
| 			Align (4);
 | |
| 			buffer.WriteBytes (Position - position);
 | |
| 
 | |
| 			const byte fat_format = 0x40;
 | |
| 			const byte more_sects = 0x80;
 | |
| 
 | |
| 			var flags = ReadByte ();
 | |
| 			if ((flags & fat_format) == 0) {
 | |
| 				buffer.WriteByte (flags);
 | |
| 				PatchRawSmallSection (buffer, metadata);
 | |
| 			} else
 | |
| 				PatchRawFatSection (buffer, metadata);
 | |
| 
 | |
| 			if ((flags & more_sects) != 0)
 | |
| 				PatchRawSection (buffer, metadata);
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawSmallSection (ByteBuffer buffer, MetadataBuilder metadata)
 | |
| 		{
 | |
| 			var length = ReadByte ();
 | |
| 			buffer.WriteByte (length);
 | |
| 			Advance (2);
 | |
| 
 | |
| 			buffer.WriteUInt16 (0);
 | |
| 
 | |
| 			var count = length / 12;
 | |
| 
 | |
| 			PatchRawExceptionHandlers (buffer, metadata, count, false);
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawFatSection (ByteBuffer buffer, MetadataBuilder metadata)
 | |
| 		{
 | |
| 			Advance (-1);
 | |
| 			var length = ReadInt32 ();
 | |
| 			buffer.WriteInt32 (length);
 | |
| 
 | |
| 			var count = (length >> 8) / 24;
 | |
| 
 | |
| 			PatchRawExceptionHandlers (buffer, metadata, count, true);
 | |
| 		}
 | |
| 
 | |
| 		void PatchRawExceptionHandlers (ByteBuffer buffer, MetadataBuilder metadata, int count, bool fat_entry)
 | |
| 		{
 | |
| 			const int fat_entry_size = 16;
 | |
| 			const int small_entry_size = 6;
 | |
| 
 | |
| 			for (int i = 0; i < count; i++) {
 | |
| 				ExceptionHandlerType handler_type;
 | |
| 				if (fat_entry) {
 | |
| 					var type = ReadUInt32 ();
 | |
| 					handler_type = (ExceptionHandlerType)(type & 0x7);
 | |
| 					buffer.WriteUInt32 (type);
 | |
| 				} else {
 | |
| 					var type = ReadUInt16 ();
 | |
| 					handler_type = (ExceptionHandlerType)(type & 0x7);
 | |
| 					buffer.WriteUInt16 (type);
 | |
| 				}
 | |
| 
 | |
| 				buffer.WriteBytes (ReadBytes (fat_entry ? fat_entry_size : small_entry_size));
 | |
| 
 | |
| 				switch (handler_type) {
 | |
| 				case ExceptionHandlerType.Catch:
 | |
| 					var exception = reader.LookupToken (ReadToken ());
 | |
| 					buffer.WriteUInt32 (metadata.LookupToken (exception).ToUInt32 ());
 | |
| 					break;
 | |
| 				default:
 | |
| 					buffer.WriteUInt32 (ReadUInt32 ());
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |